1 | "use strict";
|
2 | var __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 | };
|
9 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
10 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
11 | };
|
12 | Object.defineProperty(exports, "__esModule", { value: true });
|
13 | const router_1 = require("./router");
|
14 | exports.Router = router_1.WorkerRouter;
|
15 | const akala = __importStar(require("@akala/core"));
|
16 | const stream = __importStar(require("stream"));
|
17 | const send_1 = __importDefault(require("send"));
|
18 | const on_finished_1 = __importDefault(require("on-finished"));
|
19 | const log = akala.log('akala:worker');
|
20 | function createClient(namespace) {
|
21 | return akala.resolve('$agent.' + namespace);
|
22 | }
|
23 | exports.createClient = createClient;
|
24 | const masterPrefixes = ['header', 'route', 'query', 'body'];
|
25 | class 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 | }
|
52 | exports.WorkerInjectorImpl = WorkerInjectorImpl;
|
53 | function 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 | }
|
61 | exports.expressWrap = expressWrap;
|
62 | function buildResponse(req, callback, next) {
|
63 | return new MyResponse(req, callback, next);
|
64 | }
|
65 | class 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 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | this.render = undefined;
|
97 | |
98 |
|
99 |
|
100 |
|
101 |
|
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 |
|
137 | if (typeof options === 'function') {
|
138 | done = options;
|
139 | opts = {};
|
140 | }
|
141 |
|
142 | var pathname = encodeURI(path);
|
143 | var file = send_1.default(req, pathname, opts);
|
144 |
|
145 | sendfile(res, file, opts, function (err) {
|
146 | if (done)
|
147 | return done(err);
|
148 | if (err && err.code === 'EISDIR')
|
149 | return next();
|
150 |
|
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 | }
|
216 | function 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 |
|
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 | }
|
276 | exports.handle = handle;
|
277 | function sendfile(res, file, options, callback) {
|
278 | var done = false;
|
279 | var streaming;
|
280 |
|
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 |
|
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 |
|
299 | function onerror(err) {
|
300 | if (done)
|
301 | return;
|
302 | done = true;
|
303 | callback(err);
|
304 | }
|
305 |
|
306 | function onend() {
|
307 | if (done)
|
308 | return;
|
309 | done = true;
|
310 | callback();
|
311 | }
|
312 |
|
313 | function onfile() {
|
314 | streaming = false;
|
315 | }
|
316 |
|
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 |
|
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 |
|
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 |
|
357 | file.pipe(res);
|
358 | }
|
359 |
|
\ | No newline at end of file |