|
1 | 1 | #!/usr/bin/env node |
2 | | -const fs = require('fs') |
3 | | -const path = require('path') |
4 | | -const {spawn} = require('child_process') |
5 | | -const kill = require('tree-kill') |
6 | | -const minimisted = require('minimisted') |
7 | | - |
8 | | -async function main({_: [cmd], p, d}) { |
9 | | - switch (cmd) { |
10 | | - case 'start': { |
11 | | - if (d) require('daemonize-process')() |
12 | | - const cmd = require.resolve('micro/bin/micro.js') |
13 | | - const args = [ |
14 | | - cmd, |
15 | | - `--listen=tcp://0.0.0.0:${p || 9999}` |
16 | | - ] |
17 | | - let server = spawn( |
18 | | - 'node', args, |
19 | | - { |
20 | | - stdio: 'inherit', |
21 | | - windowsHide: true, |
22 | | - cwd: __dirname |
23 | | - } |
24 | | - ) |
25 | | - fs.writeFileSync( |
26 | | - path.join(process.cwd(), 'cors-proxy.pid'), |
27 | | - String(process.pid), |
28 | | - 'utf8' |
29 | | - ) |
30 | | - process.on('exit', server.kill) |
31 | | - return |
32 | | - } |
33 | | - case 'stop': { |
34 | | - let pid |
35 | | - try { |
36 | | - pid = fs.readFileSync( |
37 | | - path.join(process.cwd(), 'cors-proxy.pid'), |
38 | | - 'utf8' |
39 | | - ); |
40 | | - } catch (err) { |
41 | | - console.log('No cors-proxy.pid file') |
42 | | - return |
43 | | - } |
44 | | - pid = parseInt(pid) |
45 | | - console.log('killing', pid) |
46 | | - kill(pid, (err) => { |
47 | | - if (err) { |
48 | | - console.log(err) |
49 | | - } else { |
50 | | - fs.unlinkSync(path.join(process.cwd(), 'cors-proxy.pid')) |
51 | | - } |
52 | | - }) |
53 | | - } |
54 | | - } |
| 2 | + |
| 3 | +import { spawn } from 'node:child_process'; |
| 4 | +import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'; |
| 5 | +import { createServer } from 'node:http'; |
| 6 | +import { tmpdir } from 'node:os'; |
| 7 | +import { join } from 'node:path'; |
| 8 | +import { parseArgs } from 'node:util'; |
| 9 | +import handleRequest from './index.js'; |
| 10 | + |
| 11 | +const temp = tmpdir(); |
| 12 | + |
| 13 | +const { |
| 14 | + positionals: [cmd], |
| 15 | + values: { port, help, pid: pidFile, restart }, |
| 16 | +} = parseArgs({ |
| 17 | + options: { |
| 18 | + help: { type: 'boolean', short: 'h', default: false }, |
| 19 | + port: { type: 'string', short: 'p', default: '9999' }, |
| 20 | + pid: { type: 'string', default: join(temp, 'cors-proxy.pid') }, |
| 21 | + restart: { type: 'boolean', short: 'r', default: false }, |
| 22 | + }, |
| 23 | + allowPositionals: true, |
| 24 | +}); |
| 25 | + |
| 26 | +if (cmd == 'help' || help || !cmd) { |
| 27 | + console.log(`Usage: ${process.argv0} [...options] <command> |
| 28 | +
|
| 29 | +Commands: |
| 30 | + run Run the CORS proxy server in the foreground |
| 31 | + start Start the CORS proxy server daemon |
| 32 | + stop Stop the CORS proxy server daemon |
| 33 | + status Show the status of the CORS proxy server daemon |
| 34 | +Options: |
| 35 | + -h, --help Show this help message |
| 36 | + -p, --port <port> Port to listen on (default: 9999) |
| 37 | + --pid <path> Path to PID file (default: ${join(temp, 'cors-proxy.pid')} |
| 38 | + -r, --restart Restart the daemon if it is already running. Only valid with start`); |
55 | 39 | } |
56 | 40 |
|
57 | | -minimisted(main) |
| 41 | +function getPID(strict) { |
| 42 | + let pid; |
| 43 | + try { |
| 44 | + pid = parseInt(readFileSync(pidFile, 'utf8')); |
| 45 | + } catch (e) { |
| 46 | + if (e.code === 'ENOENT') { |
| 47 | + console.error('No PID file'); |
| 48 | + process.exit(strict ? 2 : 0); |
| 49 | + } |
| 50 | + |
| 51 | + console.error('Found existing PID file but could not read it'); |
| 52 | + process.exit(strict ? 13 : 0); |
| 53 | + } |
| 54 | + |
| 55 | + try { |
| 56 | + process.kill(pid, 0); |
| 57 | + return [pid, true]; |
| 58 | + } catch (e) { |
| 59 | + return [pid, false]; |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +switch (cmd) { |
| 64 | + case 'run': { |
| 65 | + const server = createServer(handleRequest); |
| 66 | + server.listen(port, () => console.log('Listening on port', port)); |
| 67 | + process.on('beforeExit', () => { |
| 68 | + console.log('Shutting down server'); |
| 69 | + server.close(); |
| 70 | + unlinkSync(pidFile); |
| 71 | + }); |
| 72 | + break; |
| 73 | + } |
| 74 | + case 'start': { |
| 75 | + if (existsSync(pidFile)) { |
| 76 | + const [pid, processExists] = getPID(true); |
| 77 | + |
| 78 | + if (!processExists) { |
| 79 | + unlinkSync(pidFile); |
| 80 | + console.error('Removed stale PID file'); |
| 81 | + } else if (restart) { |
| 82 | + process.kill(pid); |
| 83 | + console.error('Stopped existing daemon'); |
| 84 | + } else { |
| 85 | + console.error(`Daemon is already running (pid is ${pid})`); |
| 86 | + process.exit(16); |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + const daemon = spawn( |
| 91 | + import.meta.filename, |
| 92 | + ['run', port && `--port=${port}`].filter((a) => a), |
| 93 | + { stdio: 'ignore', detached: true }, |
| 94 | + ); |
| 95 | + daemon.unref(); |
| 96 | + console.log('Started CORS proxy daemon with PID', daemon.pid); |
| 97 | + writeFileSync(pidFile, daemon.pid.toString()); |
| 98 | + break; |
| 99 | + } |
| 100 | + case 'stop': { |
| 101 | + const [pid, processExists] = getPID(true); |
| 102 | + |
| 103 | + if (processExists) process.kill(pid); |
| 104 | + else { |
| 105 | + unlinkSync(pidFile); |
| 106 | + console.error('Removed stale PID file'); |
| 107 | + } |
| 108 | + break; |
| 109 | + } |
| 110 | + case 'status': { |
| 111 | + const [pid, processExists] = getPID(false); |
| 112 | + if (processExists) console.error('Daemon is running as pid', pid); |
| 113 | + else console.error('Not running, stale PID file'); |
| 114 | + break; |
| 115 | + } |
| 116 | +} |
0 commit comments