aripbae commited on
Commit
518ff8a
·
verified ·
1 Parent(s): ff87059

Update app.mjs

Browse files
Files changed (1) hide show
  1. app.mjs +124 -110
app.mjs CHANGED
@@ -14,113 +14,127 @@ import pluginStealth from 'puppeteer-extra-plugin-stealth'
14
  const TIMEOUT_MS = 6e4
15
  const MAX_CODE_LENGTH = 6e4
16
 
17
- !isMainThread && (async () => {
18
- const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor
19
- parentPort.on('message', async (code) => {
20
- try {
21
- const fn = new AsyncFunction('playwright', 'pluginStealth', 'console', code)
22
- parentPort.postMessage({ result: await fn(playwright, pluginStealth, console) })
23
- } catch (error) {
24
- parentPort.postMessage({ error: format(error) })
25
- }
26
- })
27
- return 1
28
- })();
29
-
30
- const isNumber = (v) => typeof v === 'number' && !isNaN(v)
31
-
32
- const transformObj = (obj, cb) => JSON.parse(
33
- JSON.stringify(
34
- obj,
35
- (key, val) => cb(key, val) ? prettyBytes(val) : val
36
- ).replace(/_(\w)/g, (_, g) => g.toUpperCase())
37
- )
38
-
39
- const getServerStats = () => {
40
- const stats = {}
41
- stats.uptime = prettyMs(process.uptime() * 1e3)
42
- stats.osUptime = prettyMs(os.uptime() * 1e3)
43
-
44
- const report = process.report?.getReport?.()
45
- if (report) Object.assign(stats, {
46
- header: report.header,
47
- javascriptHeap: transformObj(
48
- report.javascriptHeap,
49
- (k, v) => !/(ContextCount|Garbage)/i.test(k) && isNumber(v)
50
- ),
51
- resourceUsage: transformObj(
52
- report.resourceUsage,
53
- (k, v) => !/(Percent|IO|reads|write)/i.test(k) && isNumber(v)
54
- ),
55
- uvthreadResourceUsage: transformObj(
56
- report.uvthreadResourceUsage,
57
- (k, v) => isNumber(v)
58
- )
59
- })
60
-
61
- stats.memoryUsage = transformObj(
62
- process.memoryUsage(),
63
- (k, v) => isNumber(v)
64
- )
65
-
66
- return stats
67
- }
68
-
69
- const runBrowserScript = (code) => new Promise((resolve, reject) => {
70
- const worker = new Worker(new URL(import.meta.url), {
71
- resourceLimits: { maxOldGenerationSizeMb: 512 }
72
- })
73
-
74
- const timer = setTimeout(() => {
75
- worker.terminate()
76
- reject(new Error('Execution timeout'))
77
- }, TIMEOUT_MS)
78
-
79
- const cleanup = () => {
80
- clearTimeout(timer)
81
- worker.terminate()
82
- }
83
-
84
- worker.postMessage(code)
85
- worker.on('message', ({ result, error }) => {
86
- cleanup()
87
- error ? reject(new Error(error)) : resolve(format(result))
88
- })
89
- worker.on('error', (err) => {
90
- cleanup()
91
- reject(err)
92
- })
93
- worker.on('exit', (exitCode) => {
94
- clearTimeout(timer)
95
- exitCode !== 0 && reject(new Error(`Worker exited with code ${exitCode}`))
96
- })
97
- })
98
-
99
- const app = new Hono()
100
-
101
- app.use(logger())
102
- app.use(prettyJSON({ force: true }))
103
- app.use('/file/*', serveStatic({
104
- root: os.tmpdir(),
105
- rewriteRequestPath: (path) => path.replace(/^\/file/, '')
106
- }))
107
-
108
- app.get('/', (c) => c.json(getServerStats()))
109
-
110
- app.post('/run', async (c) => {
111
- const body = await c.req.json().catch(() => ({}))
112
- const { code } = body
113
-
114
- if (!code) return c.json({ error: 'Code is required' }, 400)
115
- if (typeof code !== 'string') return c.json({ error: 'Code must be a string' }, 400)
116
- if (code.length > MAX_CODE_LENGTH) return c.json({ error: 'Code too long' }, 400)
117
-
118
- try {
119
- return c.json({ result: await runBrowserScript(code) })
120
- } catch (e) {
121
- return c.json({ error: format(e) }, 500)
122
- }
123
- })
124
-
125
- const port = process.env.SPACE_ID ? 7860 : +(process.env.PORT || 3000)
126
- serve({ fetch: app.fetch, port }, () => console.log(`Playwright API listening at http://localhost:${port}`))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  const TIMEOUT_MS = 6e4
15
  const MAX_CODE_LENGTH = 6e4
16
 
17
+ if (!isMainThread) {
18
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor
19
+ parentPort.on('message', async (code) => {
20
+ try {
21
+ const fn = new AsyncFunction(
22
+ 'playwright',
23
+ 'pluginStealth',
24
+ 'console',
25
+ code
26
+ )
27
+ parentPort.postMessage({
28
+ result: await fn(playwright, pluginStealth, console)
29
+ })
30
+ } catch (e) {
31
+ parentPort.postMessage({ error: format(e) })
32
+ }
33
+ })
34
+ } else {
35
+ const isNumber = (v) => typeof v === 'number' && !isNaN(v)
36
+
37
+ const transformObj = (obj, cb) =>
38
+ JSON.parse(
39
+ JSON.stringify(obj, (key, val) =>
40
+ cb(key, val) ? prettyBytes(val) : val
41
+ ).replace(/_(\w)/g, (_, g) => g.toUpperCase())
42
+ )
43
+
44
+ const getServerStats = () => {
45
+ const stats = {}
46
+ stats.uptime = prettyMs(process.uptime() * 1e3)
47
+ stats.osUptime = prettyMs(os.uptime() * 1e3)
48
+
49
+ const report = process.report?.getReport?.()
50
+ if (report)
51
+ Object.assign(stats, {
52
+ header: report.header,
53
+ javascriptHeap: transformObj(
54
+ report.javascriptHeap,
55
+ (k, v) => !/(ContextCount|Garbage)/i.test(k) && isNumber(v)
56
+ ),
57
+ resourceUsage: transformObj(
58
+ report.resourceUsage,
59
+ (k, v) =>
60
+ !/(Percent|IO|reads|write)/i.test(k) && isNumber(v)
61
+ ),
62
+ uvthreadResourceUsage: transformObj(
63
+ report.uvthreadResourceUsage,
64
+ (k, v) => isNumber(v)
65
+ )
66
+ })
67
+
68
+ stats.memoryUsage = transformObj(process.memoryUsage(), (k, v) =>
69
+ isNumber(v)
70
+ )
71
+
72
+ return stats
73
+ }
74
+
75
+ const runBrowserScript = (code) =>
76
+ new Promise((resolve, reject) => {
77
+ const worker = new Worker(new URL(import.meta.url), {
78
+ resourceLimits: { maxOldGenerationSizeMb: 512 }
79
+ })
80
+
81
+ const timer = setTimeout(() => {
82
+ worker.terminate()
83
+ reject(new Error('Execution timeout'))
84
+ }, TIMEOUT_MS)
85
+
86
+ const cleanup = () => {
87
+ clearTimeout(timer)
88
+ worker.terminate()
89
+ }
90
+
91
+ worker.postMessage(code)
92
+ worker.on('message', ({ result, error }) => {
93
+ cleanup()
94
+ error ? reject(new Error(error)) : resolve(format(result))
95
+ })
96
+ worker.on('error', (e) => {
97
+ cleanup()
98
+ reject(e)
99
+ })
100
+ worker.on('exit', (exitCode) => {
101
+ clearTimeout(timer)
102
+ exitCode !== 0 &&
103
+ reject(new Error(`Worker exited with code ${exitCode}`))
104
+ })
105
+ })
106
+
107
+ const app = new Hono()
108
+
109
+ app.use(logger())
110
+ app.use(prettyJSON({ force: true }))
111
+ app.use(
112
+ '/file/*',
113
+ serveStatic({
114
+ root: os.tmpdir(),
115
+ rewriteRequestPath: (path) => path.replace(/^\/file/, '')
116
+ })
117
+ )
118
+
119
+ app.get('/', (c) => c.json(getServerStats()))
120
+
121
+ app.post('/run', async (c) => {
122
+ const body = await c.req.json().catch(() => ({}))
123
+ const { code } = body
124
+
125
+ if (!code) return c.json({ error: 'Code is required' }, 400)
126
+ if (typeof code !== 'string')
127
+ return c.json({ error: 'Code must be a string' }, 400)
128
+ if (code.length > MAX_CODE_LENGTH)
129
+ return c.json({ error: 'Code too long' }, 400)
130
+
131
+ try {
132
+ return c.json({ result: await runBrowserScript(code) })
133
+ } catch (e) {
134
+ return c.json({ error: format(e) }, 500)
135
+ }
136
+ })
137
+
138
+ const port = process.env.SPACE_ID ? 7860 : +(process.env.PORT || 3000)
139
+ serve({ fetch: app.fetch, port }, console.log)
140
+ }