forked from vercel/micro
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathwith-worker.ts
82 lines (76 loc) · 2.15 KB
/
with-worker.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import path from 'path';
import { IncomingMessage, ServerResponse } from 'http';
import { buffer } from './body';
import {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
SHARE_ENV,
Worker,
isMainThread,
} from 'worker_threads';
export interface WorkerResponseHeader {
statusCode: number;
statusMessage?: string;
headers: {
[index: string]: string | string[] | undefined;
};
}
export default function withWorker<OptsType = any>(
handlerPath: string,
workerOpts?: {
eval?: boolean; // eval handlerPath as code
limit?: string; // limit the body size
env?: { [index: string]: string | undefined };
}
) {
if (!isMainThread) {
throw new Error('withWorker() can be only used in the main thread');
}
const trampoline = workerOpts?.eval
? `require('${path.join(__dirname, './worker-wrapper')}')(${handlerPath})`
: `const p=require('${handlerPath}'); require('${path.join(__dirname, './worker-wrapper')}')(p.default || p)`;
return async (req: IncomingMessage, res: ServerResponse, opts: OptsType) => {
const body = await buffer(req, { limit: workerOpts?.limit ?? undefined });
return new Promise<void>((resolve, reject) => {
const worker = new Worker(trampoline, {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
env: workerOpts?.env || SHARE_ENV,
eval: true,
workerData: {
req: {
method: req.method,
url: req.url,
headers: req.headers,
// Trailers not supported
},
opts,
},
});
let writeFn = (msg: WorkerResponseHeader) => {
res.writeHead(msg.statusCode, msg.headers);
if (msg.statusMessage) {
res.statusMessage = msg.statusMessage;
}
// Switch to writing the response body after the headers have
// been received.
writeFn = (msg) => {
res.write(Buffer.from(msg));
};
};
worker.on('message', (chunk: any) => {
writeFn(chunk);
});
worker.on('error', reject);
worker.on('exit', (code: number) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
} else {
res.end();
resolve();
}
});
worker.postMessage(body);
});
};
}