-
-
Notifications
You must be signed in to change notification settings - Fork 272
/
Copy pathservice.ts
153 lines (133 loc) · 4.77 KB
/
service.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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import child_process from 'child_process';
import { once } from 'events';
import fs from 'fs';
import path from 'path';
import os from 'os';
import semver from 'semver';
async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const EXIT_FILE = '.exit';
const UPDATE_FILE = '.update';
async function runCommand(command: string, ...args: string[]) {
if (os.platform() === 'win32')
command += '.cmd';
console.log('running', command, ...args);
const cp = child_process.spawn(command, args, {
stdio: 'inherit',
env: {
...process.env,
// https://github.com/lovell/sharp/blob/eefaa998725cf345227d94b40615e090495c6d09/lib/libvips.js#L115C19-L115C46
SHARP_IGNORE_GLOBAL_LIBVIPS: 'true',
},
});
await once(cp, 'exit');
if (cp.exitCode)
throw new Error(`${command} exited with non zero result ${cp.exitCode}`);
}
async function runCommandEatError(command: string, ...args: string[]) {
try {
await runCommand(command, ...args);
}
catch (e) {
console.warn(command, args, 'command exited with error, ignoring', e)
}
}
export async function runServer(installDir: string) {
console.log('Starting scrypted main...');
await runCommand('npm', '--prefix', installDir, 'exec', 'scrypted-serve');
}
async function startServer(installDir: string) {
try {
await runServer(installDir);
}
catch (e) {
console.error('scrypted server exited with error', e);
}
}
export function getInstallDir() {
return process.env.SCRYPTED_INSTALL_PATH || path.join(os.homedir(), '.scrypted');
}
export function cwdInstallDir(): { volume: string, installDir: string } {
const installDir = getInstallDir();
const volume = path.join(installDir, 'volume');
fs.mkdirSync(volume, {
recursive: true,
});
process.chdir(installDir);
return { volume, installDir };
}
function rimrafSync(p: string) {
fs.rmSync(p, {
recursive: true,
force: true,
});
}
export async function installServe(installVersion: string, ignoreError?: boolean) {
const { installDir } = cwdInstallDir();
const packageLockJson = path.join(installDir, 'package-lock.json');
// apparently corrupted or old version of package-lock.json prevents upgrades, so
// nuke it before installing.
rimrafSync(packageLockJson);
const installJson = path.join(installDir, 'install.json');
try {
const { version } = JSON.parse(fs.readFileSync(installJson).toString());
if (semver.parse(process.version).major !== semver.parse(version).major)
throw new Error('mismatch');
}
catch (e) {
const nodeModules = path.join(installDir, 'node_modules');
console.log('Node version mismatch, missing, or corrupt. Clearing node_modules.');
rimrafSync(nodeModules);
}
fs.writeFileSync(installJson, JSON.stringify({
version: process.version,
}));
const args = ['--prefix', installDir, 'install', '--production', `@scrypted/server@${installVersion}`]
if (ignoreError)
await runCommandEatError('npm', ...args);
else
await runCommand('npm', ...args);
return installDir;
}
export async function serveMain(installVersion?: string) {
let install = !!installVersion;
const { installDir, volume } = cwdInstallDir();
if (!fs.existsSync('node_modules/@scrypted/server')) {
install = true;
installVersion ||= 'latest';
console.log('Package @scrypted/server not found. Installing.');
}
if (install) {
await installServe(installVersion, true);
}
// todo: remove at some point after core lxc updater rolls out.
if (process.env.SCRYPTED_INSTALL_ENVIRONMENT === 'lxc')
process.env.SCRYPTED_FFMPEG_PATH = '/usr/bin/ffmpeg';
process.env.SCRYPTED_NPM_SERVE = 'true';
process.env.SCRYPTED_VOLUME = volume;
process.env.SCRYPTED_CAN_EXIT = 'true';
process.env.SCRYPTED_CAN_RESTART = 'true';
console.log('cwd', process.cwd());
while (true) {
rimrafSync(EXIT_FILE);
rimrafSync(UPDATE_FILE);
await startServer(installDir);
if (fs.existsSync(UPDATE_FILE)) {
console.log('Update requested. Installing.');
await runCommandEatError('npm', '--prefix', installDir, 'install', '--production', '@scrypted/server@latest').catch(e => {
console.error('Update failed', e);
});
console.log('Exiting.');
process.exit(1);
}
else if (fs.existsSync(EXIT_FILE)) {
console.log('Exiting.');
process.exit(1);
}
else {
console.log(`Service unexpectedly exited. Restarting momentarily.`);
await sleep(10000);
}
}
}