UNPKG

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