UNPKG

3.7 kBJavaScriptView Raw
1'use strict';
2
3const assert = require('assert');
4const magico = require('magico');
5const debug = require('debug')('baiji:Adapter');
6const utils = require('./utils');
7
8// Basic Adapter apis that all child adapters should implement
9module.exports = class Adapter {
10 constructor(app, options) {
11 assert(app, `${app} can not be empty`);
12
13 this.app = app;
14
15 // Merge options
16 this.options = Object.assign({}, magico.get(app.settings, 'adapterOptions') || {});
17 this.options = Object.assign(this.options, options || {});
18
19 // Methods
20 this.methods = [];
21
22 // Methods sorted by route
23 this.sortedMethods = [];
24 }
25
26 // Generate Methods by wrapper
27 createMethodsBy(wrapper) {
28 assert(typeof wrapper === 'function', `${wrapper} is not a valid function`);
29
30 // Generate methods with composed invoking stack
31 let methods = this.app.composedMethods();
32 let adapterName = this.app.get('adapter');
33
34 // Generate and filter all methods
35 return methods.filter((method) => {
36 return method.isSupport(adapterName);
37 }).map((method) => {
38 let path = method.fullPath();
39 let name = method.fullName();
40 let verb = method.route.verb;
41
42 // Return specific method object that all Adapter can use
43 return {
44 verb: verb,
45 path: path,
46 name: name,
47 description: method.description,
48 notes: method.notes,
49 handler: wrapper(method)
50 };
51 });
52 }
53
54 /**
55 * Return a handler, notably means express or socketio instance
56 *
57 * @return {Function}
58 * @public
59 */
60 createHandler() {
61 throw new Error('Not Implement');
62 }
63
64 /**
65 * Initialize a new context.
66 *
67 * @api private
68 */
69 createContext() {
70 let Context = this.Context;
71 assert(typeof Context === 'function', `${Context} is not a valid Context function`);
72
73 // create Context
74 let ctx = Context.create.apply(null, arguments);
75
76 ctx.adapter = this;
77
78 return ctx;
79 }
80
81 /**
82 * Return a request handler callback
83 * for node's native http server.
84 *
85 * @return {Function}
86 * @public
87 */
88 callback() {
89 let handler = this.createHandler();
90 this.debugAllMethods();
91 return (req, res, next) => {
92 handler(req, res, next);
93 };
94 }
95
96 /**
97 * Return a http server by listen on specific port
98 * for node's native http server.
99 *
100 * @return {Function}
101 * @public
102 */
103 listen() {
104 let handler = this.createHandler();
105 this.debugAllMethods();
106 handler.listen.apply(handler, arguments);
107 }
108
109 debugAllMethods() {
110 let props = ['name', 'verb', 'path', 'description'];
111 let infos = {};
112
113 // Find longest description of `props` for better displaying
114 function setMaxLength(prop) {
115 let lengthName = `${prop}Length`;
116 infos[lengthName] = 0;
117 return function(str) {
118 let length = (str || '').length;
119 if (length > infos[lengthName]) infos[lengthName] = length;
120 };
121 }
122
123 // Loop all methods' route info
124 this.methods.forEach((route) => {
125 props.forEach((prop) => {
126 if (!infos[prop]) infos[prop] = [];
127 let val = route[prop] || '';
128 if (prop === 'verb') val = val.toUpperCase();
129 infos[prop].push(val);
130 });
131 });
132
133 // Find longtest description of each `prop`
134 props.forEach((prop) => infos[prop].forEach(setMaxLength(prop)));
135
136 // Print debug info of methods one by one
137 let count = this.methods.length;
138 debug(`All Methods: (${count})`);
139 let i = 0;
140 while(i < count) {
141 let sentence = props.map((prop) => utils.padRight(infos[prop][i], infos[`${prop}Length`]));
142 sentence.unshift('=>');
143 debug(sentence.join(' '));
144 i++;
145 }
146 }
147};