-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtdd-daemon-process.js
More file actions
115 lines (96 loc) · 2.39 KB
/
Copy pathtdd-daemon-process.js
File metadata and controls
115 lines (96 loc) · 2.39 KB
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { spawn } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
let defaultTimers = { setTimeout, clearTimeout };
function wait(ms, timers = defaultTimers) {
return new Promise(resolve => {
timers.setTimeout(resolve, ms);
});
}
function isProcessRunning(pid) {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
function parsePositiveInteger(value) {
let text = String(value).trim();
if (!/^\d+$/.test(text)) {
return null;
}
let number = Number(text);
return Number.isSafeInteger(number) && number > 0 ? number : null;
}
export function readDaemonPidFile(pidFile, deps = {}) {
let fileExists = deps.existsSync || existsSync;
let readFile = deps.readFileSync || readFileSync;
if (!fileExists(pidFile)) {
return null;
}
try {
return parsePositiveInteger(readFile(pidFile, 'utf8'));
} catch {
return null;
}
}
export async function findDaemonPidByPort(port, { spawnProcess = spawn } = {}) {
try {
let lsofProcess = spawnProcess('lsof', ['-ti', `:${port}`], {
stdio: 'pipe',
});
let lsofOutput = '';
lsofProcess.stdout.on('data', data => {
lsofOutput += data.toString();
});
return await new Promise(resolve => {
lsofProcess.on('close', code => {
if (code === 0 && lsofOutput.trim()) {
let foundPid = parsePositiveInteger(lsofOutput.trim().split('\n')[0]);
resolve(foundPid);
return;
}
resolve(null);
});
lsofProcess.on('error', () => {
resolve(null);
});
});
} catch {
return null;
}
}
export async function resolveDaemonPid({
port,
pidFile = join(process.cwd(), '.vizzly', 'server.pid'),
readPid = readDaemonPidFile,
findByPort = findDaemonPidByPort,
fileDeps = {},
} = {}) {
let pid = readPid(pidFile, fileDeps);
if (pid) {
return pid;
}
return await findByPort(port);
}
export async function waitForProcessExit(
pid,
{
timeoutMs = 2000,
intervalMs = 100,
processRunning = isProcessRunning,
timers = defaultTimers,
} = {}
) {
let elapsedMs = 0;
while (elapsedMs < timeoutMs) {
if (!processRunning(pid)) {
return true;
}
let nextDelay = Math.min(intervalMs, timeoutMs - elapsedMs);
await wait(nextDelay, timers);
elapsedMs += nextDelay;
}
return !processRunning(pid);
}