UNPKG

12.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const router_1 = require("./router");
4exports.Router = router_1.WorkerRouter;
5const akala = require("@akala/core");
6const stream = require("stream");
7const send = require("send");
8const onFinished = require("on-finished");
9const log = akala.log('akala:worker');
10function createClient(namespace) {
11 return akala.resolve('$agent.' + namespace);
12}
13exports.createClient = createClient;
14const masterPrefixes = ['header', 'route', 'query', 'body'];
15class WorkerInjectorImpl extends akala.Injector {
16 constructor(request) {
17 super();
18 this.request = request;
19 }
20 resolve(name) {
21 let indexOfDot = name.indexOf('.');
22 if (~indexOfDot) {
23 let master = name.substr(0, indexOfDot);
24 if (~masterPrefixes.indexOf(master)) {
25 log(`resolving ${name}`);
26 switch (master) {
27 case 'header':
28 return this.request.headers[name.substr(indexOfDot + 1)];
29 case 'query':
30 return this.request.query && this.request.query[name.substr(indexOfDot + 1)];
31 case 'route':
32 log(this.request.params);
33 return this.request.params && this.request.params[name.substr(indexOfDot + 1)];
34 case 'body':
35 return this.request.body && this.request.body[name.substr(indexOfDot + 1)];
36 }
37 }
38 }
39 return super.resolve(name);
40 }
41}
42exports.WorkerInjectorImpl = WorkerInjectorImpl;
43function expressWrap(handler) {
44 return function (req, next) {
45 var callback = req.injector.resolve('$callback');
46 var headers = {};
47 var response = buildResponse(req, callback, next);
48 handler(req, response, next);
49 };
50}
51exports.expressWrap = expressWrap;
52function buildResponse(req, callback, next) {
53 return new MyResponse(req, callback, next);
54}
55class MyResponse extends stream.Transform {
56 constructor(req, callback, next) {
57 super({
58 transform: (chunk, _encoding, callback) => {
59 callback(null, chunk);
60 }, decodeStrings: true
61 });
62 this.req = req;
63 this.isStream = false;
64 this.headers = {};
65 this.links = undefined;
66 this.jsonp = undefined;
67 this.sendfile = undefined;
68 this.download = undefined;
69 this.type = undefined;
70 this.format = undefined;
71 this.attachment = undefined;
72 this.headersSent = false;
73 this.get = undefined;
74 this.clearCookie = undefined;
75 this.cookie = undefined;
76 /**
77 * Render `view` with the given `options` and optional callback `fn`.
78 * When a callback function is given a response will _not_ be made
79 * automatically, otherwise a response of _200_ and _text/html_ is given.
80 *
81 * Options:
82 *
83 * - `cache` boolean hinting to the engine it should cache
84 * - `filename` filename of the view being rendered
85 */
86 this.render = undefined;
87 /**
88 * Adds the field to the Vary response header, if it is not there already.
89 * Examples:
90 *
91 * res.vary('User-Agent').render('docs');
92 *
93 */
94 this.vary = undefined;
95 this.app = undefined;
96 this.setTimeout = undefined;
97 this.addTrailers = undefined;
98 this.writeContinue = undefined;
99 this.finished = false;
100 this.writable = true;
101 this.headers = {};
102 this.sendStatus = callback;
103 this.status = callback;
104 this.send = callback;
105 this.json = callback;
106 this.on('pipe', () => {
107 this.isStream = true;
108 });
109 this.on('end', () => { this.send(this); });
110 }
111 sendFile(path, options, callback) {
112 var encodedPath = encodeURI(path);
113 var done = callback;
114 var req = this.req;
115 var res = this;
116 var next = function (err) {
117 if (err)
118 res.send(500, err);
119 else
120 res.send(200);
121 };
122 var opts = options || {};
123 if (!path) {
124 throw new TypeError('path argument is required to res.sendFile');
125 }
126 // support function as second arg
127 if (typeof options === 'function') {
128 done = options;
129 opts = {};
130 }
131 // create file stream
132 var pathname = encodeURI(path);
133 var file = send(req, pathname, opts);
134 // transfer
135 sendfile(res, file, opts, function (err) {
136 if (done)
137 return done(err);
138 if (err && err.code === 'EISDIR')
139 return next();
140 // next() all but write errors
141 if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') {
142 next(err);
143 }
144 });
145 }
146 contentType(type) { this.setHeader('contentType', type); return this; }
147 set(field, value) {
148 return this.header(field, value);
149 }
150 header(field, value) {
151 if (typeof field == 'string') {
152 if (typeof (value) == 'undefined')
153 return this.headers[field];
154 this.setHeader(field, value);
155 return this;
156 }
157 else {
158 var self = this;
159 if (field)
160 akala.each(field, function (value, key) {
161 self.setHeader(key, value);
162 });
163 }
164 }
165 location(location) { this.setHeader('location', location); return this; }
166 setHeader(field, value) {
167 this.headers[field] = value;
168 }
169 redirect(url, status) {
170 if (typeof (status) == 'undefined')
171 status = 302;
172 if (typeof (url) == 'number' && typeof (status) == 'string') {
173 var swap = url;
174 url = status;
175 status = swap;
176 }
177 this.setHeader('location', url);
178 this.send(status);
179 }
180 writeHead(statusCode, reasonPhrase, headers) {
181 log('writeHead');
182 this.statusCode = statusCode;
183 if (typeof reasonPhrase != 'string') {
184 headers = reasonPhrase;
185 reasonPhrase = null;
186 }
187 if (reasonPhrase)
188 this.statusMessage = reasonPhrase;
189 this.header(headers);
190 this.send(this);
191 this.headersSent = true;
192 }
193 getHeader(name) {
194 return this.headers[name];
195 }
196 ;
197 removeHeader(name) {
198 delete this.headers[name];
199 }
200 _write(chunk, encoding, callback) {
201 if (!this.headersSent)
202 this.writeHead(this.statusCode);
203 super['_write'](chunk, encoding, callback);
204 }
205}
206function handle(app, root) {
207 return function handle(request, next) {
208 return new Promise((resolve, reject) => {
209 var callback = function callback(status, data) {
210 var response;
211 if (arguments.length == 0)
212 return reject();
213 if (arguments.length == 1 && status === 'route')
214 return reject(status);
215 if (isNaN(Number(status)) || Array.isArray(status)) {
216 response = status;
217 if (typeof (data) == 'undefined') {
218 if (typeof (status) == 'undefined')
219 response = { statusCode: 404, data: 'Not found' };
220 else if (isNaN(Number(response.statusCode)) && !(response instanceof stream.Readable)) {
221 data = response;
222 response = { statusCode: 200, data: data };
223 status = null;
224 }
225 else
226 data = undefined;
227 status = null;
228 }
229 }
230 else
231 response = { statusCode: status, data: 'No data' };
232 response.statusCode = response.statusCode || 200;
233 if (!(data instanceof stream.Readable) && !Buffer.isBuffer(data) && typeof (data) !== 'string' && typeof data != 'number' && typeof (data) != 'undefined') {
234 if (!response.headers)
235 response.headers = {};
236 if (data instanceof Error) {
237 if (!response.headers['Content-Type'])
238 response.headers['Content-Type'] = 'text/text';
239 data = data.stack;
240 }
241 else {
242 if (!response.headers['Content-Type'])
243 response.headers['Content-Type'] = 'application/json';
244 data = JSON.stringify(data);
245 }
246 }
247 if (typeof (data) != 'undefined')
248 response.data = data;
249 resolve(response);
250 };
251 callback.redirect = function (url) {
252 return callback({ status: 302, headers: { location: url } });
253 };
254 var requestInjector = new WorkerInjectorImpl(request);
255 requestInjector.register('$request', request);
256 requestInjector.register('$callback', callback);
257 // log(request);
258 Object.defineProperty(request, 'injector', { value: requestInjector, enumerable: false, configurable: false, writable: false });
259 log(request.url);
260 app.handle(request, callback, function (err, _req, _callback) {
261 reject(err);
262 });
263 });
264 };
265}
266exports.handle = handle;
267function sendfile(res, file, options, callback) {
268 var done = false;
269 var streaming;
270 // request aborted
271 function onaborted() {
272 if (done)
273 return;
274 done = true;
275 var err = new Error('Request aborted');
276 err['code'] = 'ECONNABORTED';
277 callback(err);
278 }
279 // directory
280 function ondirectory() {
281 if (done)
282 return;
283 done = true;
284 var err = new Error('EISDIR, read');
285 err['code'] = 'EISDIR';
286 callback(err);
287 }
288 // errors
289 function onerror(err) {
290 if (done)
291 return;
292 done = true;
293 callback(err);
294 }
295 // ended
296 function onend() {
297 if (done)
298 return;
299 done = true;
300 callback();
301 }
302 // file
303 function onfile() {
304 streaming = false;
305 }
306 // finished
307 function onfinish(err) {
308 if (err && err.code === 'ECONNRESET')
309 return onaborted();
310 if (err)
311 return onerror(err);
312 if (done)
313 return;
314 setImmediate(function () {
315 if (streaming !== false && !done) {
316 onaborted();
317 return;
318 }
319 if (done)
320 return;
321 done = true;
322 callback();
323 });
324 }
325 // streaming
326 function onstream() {
327 streaming = true;
328 }
329 file.on('directory', ondirectory);
330 file.on('end', onend);
331 file.on('error', onerror);
332 file.on('file', onfile);
333 file.on('stream', onstream);
334 onFinished(res, onfinish);
335 if (options.headers) {
336 // set headers on successful transfer
337 file.on('headers', function headers(res) {
338 var obj = options.headers;
339 var keys = Object.keys(obj);
340 for (var i = 0; i < keys.length; i++) {
341 var k = keys[i];
342 res.setHeader(k, obj[k]);
343 }
344 });
345 }
346 // pipe
347 file.pipe(res);
348}
349//# sourceMappingURL=worker-meta.js.map
\No newline at end of file