aripbae commited on
Commit
06a22a1
·
verified ·
1 Parent(s): d28c5a5

Update index.js

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