@scrypted/server 0.123.32 → 0.123.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cluster/cluster-setup.js +3 -3
- package/dist/cluster/cluster-setup.js.map +1 -1
- package/dist/plugin/plugin-host.d.ts +2 -1
- package/dist/plugin/plugin-host.js +17 -11
- package/dist/plugin/plugin-host.js.map +1 -1
- package/dist/plugin/plugin-remote-worker.js +10 -9
- package/dist/plugin/plugin-remote-worker.js.map +1 -1
- package/dist/plugin/runtime/child-process-worker.d.ts +1 -1
- package/dist/plugin/runtime/child-process-worker.js +2 -2
- package/dist/plugin/runtime/child-process-worker.js.map +1 -1
- package/dist/plugin/runtime/cluster-fork-worker.d.ts +2 -2
- package/dist/plugin/runtime/cluster-fork-worker.js +8 -4
- package/dist/plugin/runtime/cluster-fork-worker.js.map +1 -1
- package/dist/plugin/runtime/custom-worker.d.ts +1 -1
- package/dist/plugin/runtime/custom-worker.js +3 -3
- package/dist/plugin/runtime/custom-worker.js.map +1 -1
- package/dist/plugin/runtime/node-fork-worker.d.ts +1 -1
- package/dist/plugin/runtime/node-fork-worker.js +2 -2
- package/dist/plugin/runtime/node-fork-worker.js.map +1 -1
- package/dist/plugin/runtime/python-worker.d.ts +1 -1
- package/dist/plugin/runtime/python-worker.js +3 -3
- package/dist/plugin/runtime/python-worker.js.map +1 -1
- package/dist/plugin/runtime/runtime-host.d.ts +1 -1
- package/dist/plugin/runtime/runtime-host.js +3 -3
- package/dist/plugin/runtime/runtime-host.js.map +1 -1
- package/dist/scrypted-cluster-main.d.ts +10 -2
- package/dist/scrypted-cluster-main.js +15 -14
- package/dist/scrypted-cluster-main.js.map +1 -1
- package/dist/scrypted-server-main.js +14 -2
- package/dist/scrypted-server-main.js.map +1 -1
- package/dist/services/cluster-fork.d.ts +3 -2
- package/dist/services/cluster-fork.js +38 -7
- package/dist/services/cluster-fork.js.map +1 -1
- package/package.json +2 -2
- package/python/plugin_remote.py +15 -2
- package/src/cluster/cluster-setup.ts +3 -3
- package/src/plugin/plugin-host.ts +31 -21
- package/src/plugin/plugin-remote-worker.ts +16 -10
- package/src/plugin/runtime/child-process-worker.ts +3 -1
- package/src/plugin/runtime/cluster-fork-worker.ts +16 -10
- package/src/plugin/runtime/custom-worker.ts +3 -3
- package/src/plugin/runtime/node-fork-worker.ts +2 -2
- package/src/plugin/runtime/python-worker.ts +3 -3
- package/src/plugin/runtime/runtime-host.ts +4 -4
- package/src/scrypted-cluster-main.ts +28 -22
- package/src/scrypted-server-main.ts +16 -3
- package/src/services/cluster-fork.ts +43 -9
@@ -21,7 +21,7 @@ import { createClusterForkWorker } from './runtime/cluster-fork-worker';
|
|
21
21
|
import { NodeThreadWorker } from './runtime/node-thread-worker';
|
22
22
|
import { prepareZip } from './runtime/node-worker-common';
|
23
23
|
import { getBuiltinRuntimeHosts } from './runtime/runtime-host';
|
24
|
-
import { RuntimeWorker } from './runtime/runtime-worker';
|
24
|
+
import { RuntimeWorker, RuntimeWorkerOptions } from './runtime/runtime-worker';
|
25
25
|
import type { ClusterForkService } from '../services/cluster-fork';
|
26
26
|
import type { PluginComponent } from '../services/plugin';
|
27
27
|
import { ClusterManagerImpl } from '../scrypted-cluster-main';
|
@@ -216,10 +216,23 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
|
|
216
216
|
let nativeWorker: child_process.ChildProcess | worker_threads.Worker;
|
217
217
|
let clusterWorkerId: Promise<string>;
|
218
218
|
|
219
|
+
const runtimeWorkerOptions: RuntimeWorkerOptions = {
|
220
|
+
packageJson,
|
221
|
+
env: undefined,
|
222
|
+
pluginDebug: undefined,
|
223
|
+
zipFile,
|
224
|
+
unzippedPath,
|
225
|
+
zipHash,
|
226
|
+
};
|
227
|
+
|
219
228
|
// if running in a cluster, fork to a matching cluster worker only if necessary.
|
220
229
|
if (needsClusterForkWorker(options)) {
|
221
230
|
({ runtimeWorker, forkPeer, clusterWorkerId } = createClusterForkWorker(
|
222
|
-
|
231
|
+
runtimeWorkerOptions,
|
232
|
+
options,
|
233
|
+
api.getComponent('cluster-fork'),
|
234
|
+
() => zipAPI.getZip(),
|
235
|
+
scrypted.connectRPCObject)
|
223
236
|
);
|
224
237
|
}
|
225
238
|
else {
|
@@ -228,14 +241,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
|
|
228
241
|
const runtime = builtins.get(options.runtime);
|
229
242
|
if (!runtime)
|
230
243
|
throw new Error('unknown runtime ' + options.runtime);
|
231
|
-
runtimeWorker = runtime(mainFilename,
|
232
|
-
packageJson,
|
233
|
-
env: undefined,
|
234
|
-
pluginDebug: undefined,
|
235
|
-
zipFile,
|
236
|
-
unzippedPath,
|
237
|
-
zipHash,
|
238
|
-
}, undefined);
|
244
|
+
runtimeWorker = runtime(mainFilename, runtimeWorkerOptions, undefined);
|
239
245
|
|
240
246
|
if (runtimeWorker instanceof ChildProcessWorker) {
|
241
247
|
nativeWorker = runtimeWorker.childProcess;
|
@@ -4,14 +4,16 @@ import { RpcMessage, RpcPeer } from "../../rpc";
|
|
4
4
|
import { RuntimeWorker, RuntimeWorkerOptions } from "./runtime-worker";
|
5
5
|
|
6
6
|
export abstract class ChildProcessWorker extends EventEmitter implements RuntimeWorker {
|
7
|
+
public pluginId: string;
|
7
8
|
protected worker: child_process.ChildProcess;
|
8
9
|
|
9
10
|
get childProcess() {
|
10
11
|
return this.worker;
|
11
12
|
}
|
12
13
|
|
13
|
-
constructor(
|
14
|
+
constructor(options: RuntimeWorkerOptions) {
|
14
15
|
super();
|
16
|
+
this.pluginId = options.packageJson.name;
|
15
17
|
}
|
16
18
|
|
17
19
|
setupWorker() {
|
@@ -5,15 +5,20 @@ import { RpcPeer } from "../../rpc";
|
|
5
5
|
import { PeerLiveness } from "../../scrypted-cluster-main";
|
6
6
|
import type { ClusterForkService } from "../../services/cluster-fork";
|
7
7
|
import { writeWorkerGenerator } from "../plugin-console";
|
8
|
-
import type { RuntimeWorker } from "./runtime-worker";
|
8
|
+
import type { RuntimeWorker, RuntimeWorkerOptions } from "./runtime-worker";
|
9
9
|
|
10
10
|
export function createClusterForkWorker(
|
11
|
+
runtimeWorkerOptions: RuntimeWorkerOptions,
|
12
|
+
options: Partial<ClusterFork>,
|
11
13
|
forkComponentPromise: Promise<ClusterForkService>,
|
12
|
-
zipHash: string,
|
13
14
|
getZip: () => Promise<Buffer>,
|
14
|
-
options: Partial<ClusterFork>,
|
15
|
-
packageJson: any,
|
16
15
|
connectRPCObject: (o: any) => Promise<any>) {
|
16
|
+
|
17
|
+
// these are specific to the cluster worker host
|
18
|
+
// and will be set there.
|
19
|
+
delete runtimeWorkerOptions.zipFile;
|
20
|
+
delete runtimeWorkerOptions.unzippedPath;
|
21
|
+
|
17
22
|
const waitKilled = new Deferred<void>();
|
18
23
|
waitKilled.promise.finally(() => events.emit('exit'));
|
19
24
|
const events = new EventEmitter();
|
@@ -38,21 +43,22 @@ export function createClusterForkWorker(
|
|
38
43
|
});
|
39
44
|
|
40
45
|
const peerLiveness = new PeerLiveness(waitKilled.promise);
|
41
|
-
const clusterForkResultPromise = forkComponentPromise.then(forkComponent => forkComponent.fork(
|
46
|
+
const clusterForkResultPromise = forkComponentPromise.then(forkComponent => forkComponent.fork(runtimeWorkerOptions, {
|
42
47
|
runtime: options.runtime || 'node',
|
43
48
|
id: options.id,
|
44
49
|
...options,
|
45
|
-
},
|
46
|
-
|
50
|
+
}, peerLiveness,
|
51
|
+
getZip));
|
52
|
+
clusterForkResultPromise.catch(() => { });
|
47
53
|
|
48
54
|
const clusterWorkerId = clusterForkResultPromise.then(clusterForkResult => clusterForkResult.clusterWorkerId);
|
49
|
-
clusterWorkerId.catch(() => {});
|
55
|
+
clusterWorkerId.catch(() => { });
|
50
56
|
|
51
57
|
const forkPeer = (async () => {
|
52
58
|
const clusterForkResult = await clusterForkResultPromise;
|
53
59
|
waitKilled.promise.finally(() => {
|
54
60
|
runtimeWorker.pid = undefined;
|
55
|
-
clusterForkResult.kill().catch(() => {});
|
61
|
+
clusterForkResult.kill().catch(() => { });
|
56
62
|
});
|
57
63
|
clusterForkResult.waitKilled().catch(() => { })
|
58
64
|
.finally(() => {
|
@@ -79,7 +85,7 @@ export function createClusterForkWorker(
|
|
79
85
|
return peer;
|
80
86
|
}
|
81
87
|
catch (e) {
|
82
|
-
clusterForkResult.kill();
|
88
|
+
clusterForkResult.kill().catch(() => {});
|
83
89
|
throw e;
|
84
90
|
}
|
85
91
|
})();
|
@@ -11,8 +11,8 @@ export class CustomRuntimeWorker extends ChildProcessWorker {
|
|
11
11
|
serializer: ReturnType<typeof createRpcDuplexSerializer>;
|
12
12
|
fork: boolean;
|
13
13
|
|
14
|
-
constructor(
|
15
|
-
super(
|
14
|
+
constructor(options: RuntimeWorkerOptions, runtime: ScryptedRuntime) {
|
15
|
+
super(options);
|
16
16
|
|
17
17
|
const pluginDevice = runtime.findPluginDevice(this.pluginId);
|
18
18
|
const scryptedRuntimeArguments: ScryptedRuntimeArguments = pluginDevice.state.scryptedRuntimeArguments?.value;
|
@@ -27,7 +27,7 @@ export class CustomRuntimeWorker extends ChildProcessWorker {
|
|
27
27
|
// stdin, stdout, stderr, peer in, peer out
|
28
28
|
stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
|
29
29
|
env: Object.assign({}, process.env, env, {
|
30
|
-
SCRYYPTED_PLUGIN_ID: pluginId,
|
30
|
+
SCRYYPTED_PLUGIN_ID: this.pluginId,
|
31
31
|
SCRYPTED_DEBUG_PORT: pluginDebug?.inspectPort?.toString(),
|
32
32
|
SCRYPTED_UNZIPPED_PATH: options.unzippedPath,
|
33
33
|
SCRYPTED_ZIP_FILE: options.zipFile,
|
@@ -28,8 +28,8 @@ export function isNodePluginChildProcess() {
|
|
28
28
|
|
29
29
|
export class NodeForkWorker extends ChildProcessWorker {
|
30
30
|
|
31
|
-
constructor(mainFilename: string,
|
32
|
-
super(
|
31
|
+
constructor(mainFilename: string, options: RuntimeWorkerOptions) {
|
32
|
+
super(options);
|
33
33
|
|
34
34
|
const { env, pluginDebug } = options;
|
35
35
|
|
@@ -41,8 +41,8 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
|
|
41
41
|
return this._stderr;
|
42
42
|
}
|
43
43
|
|
44
|
-
constructor(
|
45
|
-
super(
|
44
|
+
constructor(options: RuntimeWorkerOptions) {
|
45
|
+
super(options);
|
46
46
|
|
47
47
|
const { env, pluginDebug } = options;
|
48
48
|
const args: string[] = [
|
@@ -148,7 +148,7 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
|
|
148
148
|
};
|
149
149
|
|
150
150
|
const pyVersion = require('py/package.json').version;
|
151
|
-
const pyPath = path.join(getPluginVolume(pluginId), 'py');
|
151
|
+
const pyPath = path.join(getPluginVolume(this.pluginId), 'py');
|
152
152
|
const portableInstallPath = path.join(pyPath, pyVersion);
|
153
153
|
|
154
154
|
const py = new PortablePython(pluginPythonVersion, portableInstallPath, portablePythonOptions);
|
@@ -4,14 +4,14 @@ import { NodeForkWorker } from "./node-fork-worker";
|
|
4
4
|
import { PythonRuntimeWorker } from "./python-worker";
|
5
5
|
import type { RuntimeWorker, RuntimeWorkerOptions } from "./runtime-worker";
|
6
6
|
|
7
|
-
export type RuntimeHost = (mainFilename: string,
|
7
|
+
export type RuntimeHost = (mainFilename: string, options: RuntimeWorkerOptions, runtime: ScryptedRuntime) => RuntimeWorker;
|
8
8
|
|
9
9
|
export function getBuiltinRuntimeHosts() {
|
10
10
|
const pluginHosts = new Map<string, RuntimeHost>();
|
11
11
|
|
12
|
-
pluginHosts.set('custom', (_,
|
13
|
-
pluginHosts.set('python', (_,
|
14
|
-
pluginHosts.set('node', (mainFilename,
|
12
|
+
pluginHosts.set('custom', (_, options, runtime) => new CustomRuntimeWorker(options, runtime));
|
13
|
+
pluginHosts.set('python', (_, options) => new PythonRuntimeWorker(options));
|
14
|
+
pluginHosts.set('node', (mainFilename, options) => new NodeForkWorker(mainFilename, options));
|
15
15
|
|
16
16
|
return pluginHosts;
|
17
17
|
}
|
@@ -15,7 +15,7 @@ import type { PluginAPI } from './plugin/plugin-api';
|
|
15
15
|
import { getPluginVolume, getScryptedVolume } from './plugin/plugin-volume';
|
16
16
|
import { prepareZip } from './plugin/runtime/node-worker-common';
|
17
17
|
import { getBuiltinRuntimeHosts } from './plugin/runtime/runtime-host';
|
18
|
-
import type { RuntimeWorker } from './plugin/runtime/runtime-worker';
|
18
|
+
import type { RuntimeWorker, RuntimeWorkerOptions } from './plugin/runtime/runtime-worker';
|
19
19
|
import { RpcPeer } from './rpc';
|
20
20
|
import { createRpcDuplexSerializer } from './rpc-serializer';
|
21
21
|
import type { ScryptedRuntime } from './runtime';
|
@@ -76,6 +76,7 @@ export interface RunningClusterWorker extends ClusterWorkerProperties {
|
|
76
76
|
id: string;
|
77
77
|
peer: RpcPeer;
|
78
78
|
forks: Set<ClusterForkOptions>;
|
79
|
+
address: string;
|
79
80
|
}
|
80
81
|
|
81
82
|
export class PeerLiveness {
|
@@ -86,7 +87,7 @@ export class PeerLiveness {
|
|
86
87
|
}
|
87
88
|
}
|
88
89
|
|
89
|
-
export class ClusterForkResult extends PeerLiveness {
|
90
|
+
export class ClusterForkResult extends PeerLiveness implements ClusterForkResultInterface {
|
90
91
|
[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = ['kill'];
|
91
92
|
clusterWorkerId?: string;
|
92
93
|
|
@@ -103,9 +104,17 @@ export class ClusterForkResult extends PeerLiveness {
|
|
103
104
|
}
|
104
105
|
}
|
105
106
|
|
106
|
-
export
|
107
|
+
export interface ClusterForkResultInterface {
|
108
|
+
clusterWorkerId?: string;
|
109
|
+
getResult(): Promise<any>;
|
110
|
+
kill(): Promise<void>;
|
111
|
+
waitKilled(): Promise<void>;
|
112
|
+
}
|
113
|
+
|
114
|
+
export type ClusterForkParam = (runtime: string, options: RuntimeWorkerOptions, peerLiveness: PeerLiveness, getZip: () => Promise<Buffer>) => Promise<ClusterForkResultInterface>;
|
107
115
|
|
108
116
|
export function startClusterClient(mainFilename: string) {
|
117
|
+
console.log('Cluster client starting.');
|
109
118
|
const originalClusterAddress = process.env.SCRYPTED_CLUSTER_ADDRESS;
|
110
119
|
const labels = getClusterLabels();
|
111
120
|
|
@@ -131,6 +140,7 @@ export function startClusterClient(mainFilename: string) {
|
|
131
140
|
await once(rawSocket, 'connect');
|
132
141
|
}
|
133
142
|
catch (e) {
|
143
|
+
console.warn('Cluster server not available.', host, port, e);
|
134
144
|
continue;
|
135
145
|
}
|
136
146
|
|
@@ -143,6 +153,7 @@ export function startClusterClient(mainFilename: string) {
|
|
143
153
|
await once(socket, 'secureConnect');
|
144
154
|
}
|
145
155
|
catch (e) {
|
156
|
+
console.warn('Cluster server tls failed.', host, port, e);
|
146
157
|
continue;
|
147
158
|
}
|
148
159
|
|
@@ -179,12 +190,7 @@ export function startClusterClient(mainFilename: string) {
|
|
179
190
|
const clusterPeerSetup = setupCluster(peer);
|
180
191
|
await clusterPeerSetup.initializeCluster({ clusterId, clusterSecret });
|
181
192
|
|
182
|
-
const clusterForkParam: ClusterForkParam = async (
|
183
|
-
peerLiveness: PeerLiveness,
|
184
|
-
runtime: string,
|
185
|
-
packageJson: any,
|
186
|
-
zipHash: string,
|
187
|
-
getZip: () => Promise<Buffer>) => {
|
193
|
+
const clusterForkParam: ClusterForkParam = async (runtime, runtimeWorkerOptions, peerLiveness, getZip) => {
|
188
194
|
let runtimeWorker: RuntimeWorker;
|
189
195
|
|
190
196
|
const builtins = getBuiltinRuntimeHosts();
|
@@ -192,23 +198,22 @@ export function startClusterClient(mainFilename: string) {
|
|
192
198
|
if (!rt)
|
193
199
|
throw new Error('unknown runtime ' + runtime);
|
194
200
|
|
195
|
-
const pluginId: string = packageJson.name;
|
196
|
-
const { zipFile, unzippedPath } = await prepareZip(getPluginVolume(pluginId), zipHash, getZip);
|
201
|
+
const pluginId: string = runtimeWorkerOptions.packageJson.name;
|
202
|
+
const { zipFile, unzippedPath } = await prepareZip(getPluginVolume(pluginId), runtimeWorkerOptions.zipHash, getZip);
|
197
203
|
|
198
204
|
const volume = getScryptedVolume();
|
199
205
|
const pluginVolume = getPluginVolume(pluginId);
|
200
206
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
}, undefined);
|
207
|
+
runtimeWorkerOptions.zipFile = zipFile;
|
208
|
+
runtimeWorkerOptions.unzippedPath = unzippedPath;
|
209
|
+
|
210
|
+
runtimeWorkerOptions.env = {
|
211
|
+
...runtimeWorkerOptions.env,
|
212
|
+
SCRYPTED_VOLUME: volume,
|
213
|
+
SCRYPTED_PLUGIN_VOLUME: pluginVolume,
|
214
|
+
};
|
215
|
+
|
216
|
+
runtimeWorker = rt(mainFilename, runtimeWorkerOptions, undefined);
|
212
217
|
runtimeWorker.stdout.on('data', data => console.log(data.toString()));
|
213
218
|
runtimeWorker.stderr.on('data', data => console.error(data.toString()));
|
214
219
|
|
@@ -311,6 +316,7 @@ export function createClusterServer(runtime: ScryptedRuntime, certificate: Retur
|
|
311
316
|
// generate a random uuid.
|
312
317
|
id,
|
313
318
|
peer,
|
319
|
+
address: socket.remoteAddress,
|
314
320
|
forks: new Set(),
|
315
321
|
};
|
316
322
|
runtime.clusterWorkers.set(id, worker);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import bodyParser from 'body-parser';
|
2
2
|
import cookieParser from 'cookie-parser';
|
3
|
-
import crypto from 'crypto';
|
3
|
+
import crypto, { scrypt } from 'crypto';
|
4
4
|
import { once } from 'events';
|
5
5
|
import express, { Request } from 'express';
|
6
6
|
import fs from 'fs';
|
@@ -45,10 +45,11 @@ installSourceMapSupport({
|
|
45
45
|
});
|
46
46
|
|
47
47
|
let workerInspectPort: number = undefined;
|
48
|
+
let workerInspectAddress: string = undefined;
|
48
49
|
|
49
50
|
async function doconnect(): Promise<net.Socket> {
|
50
51
|
return new Promise((resolve, reject) => {
|
51
|
-
const target = net.connect(workerInspectPort,
|
52
|
+
const target = net.connect(workerInspectPort, workerInspectAddress);
|
52
53
|
target.once('error', reject)
|
53
54
|
target.once('connect', () => resolve(target))
|
54
55
|
})
|
@@ -100,6 +101,7 @@ app.use(bodyParser.raw({ type: 'application/*', limit: 100000000 }) as any)
|
|
100
101
|
async function start(mainFilename: string, options?: {
|
101
102
|
onRuntimeCreated?: (runtime: ScryptedRuntime) => Promise<void>,
|
102
103
|
}) {
|
104
|
+
console.log('Scrypted server starting.');
|
103
105
|
const volumeDir = getScryptedVolume();
|
104
106
|
await fs.promises.mkdir(volumeDir, {
|
105
107
|
recursive: true
|
@@ -464,11 +466,20 @@ async function start(mainFilename: string, options?: {
|
|
464
466
|
waitDebug.catch(() => { });
|
465
467
|
|
466
468
|
workerInspectPort = Math.round(Math.random() * 10000) + 30000;
|
469
|
+
workerInspectAddress = '127.0.0.1';
|
467
470
|
try {
|
468
|
-
await scrypted.installPlugin(plugin, {
|
471
|
+
const host = await scrypted.installPlugin(plugin, {
|
469
472
|
waitDebug,
|
470
473
|
inspectPort: workerInspectPort,
|
471
474
|
});
|
475
|
+
|
476
|
+
const clusterWorkerId = await host.clusterWorkerId;
|
477
|
+
if (clusterWorkerId) {
|
478
|
+
const clusterWorker = scrypted.clusterWorkers.get(clusterWorkerId);
|
479
|
+
if (clusterWorker) {
|
480
|
+
workerInspectAddress = clusterWorker.address;
|
481
|
+
}
|
482
|
+
}
|
472
483
|
}
|
473
484
|
catch (e) {
|
474
485
|
res.header('Content-Type', 'text/plain');
|
@@ -479,6 +490,7 @@ async function start(mainFilename: string, options?: {
|
|
479
490
|
|
480
491
|
res.send({
|
481
492
|
workerInspectPort,
|
493
|
+
workerInspectAddress,
|
482
494
|
});
|
483
495
|
});
|
484
496
|
|
@@ -726,6 +738,7 @@ async function start(mainFilename: string, options?: {
|
|
726
738
|
|
727
739
|
const clusterMode = getScryptedClusterMode();
|
728
740
|
if (clusterMode?.[0] === 'server') {
|
741
|
+
console.log('Cluster server starting.');
|
729
742
|
const clusterServer = createClusterServer(scrypted, keyPair);
|
730
743
|
await listenServerPort('SCRYPTED_CLUSTER_SERVER', clusterMode[2], clusterServer);
|
731
744
|
}
|
@@ -1,11 +1,40 @@
|
|
1
1
|
import { matchesClusterLabels } from "../cluster/cluster-labels";
|
2
|
+
import type { RuntimeWorkerOptions } from "../plugin/runtime/runtime-worker";
|
3
|
+
import { RpcPeer } from "../rpc";
|
2
4
|
import type { ScryptedRuntime } from "../runtime";
|
3
|
-
import type { ClusterForkOptions, ClusterForkParam, PeerLiveness, RunningClusterWorker } from "../scrypted-cluster-main";
|
5
|
+
import type { ClusterForkOptions, ClusterForkParam, ClusterForkResultInterface, PeerLiveness, RunningClusterWorker } from "../scrypted-cluster-main";
|
6
|
+
|
7
|
+
class WrappedForkResult implements ClusterForkResultInterface {
|
8
|
+
[RpcPeer.PROPERTY_PROXY_PROPERTIES] = {
|
9
|
+
clusterWorkerId: undefined as string,
|
10
|
+
};
|
11
|
+
|
12
|
+
constructor(public clusterWorkerId: string, public forkResult: Promise<ClusterForkResultInterface>) {
|
13
|
+
this[RpcPeer.PROPERTY_PROXY_PROPERTIES].clusterWorkerId = clusterWorkerId;
|
14
|
+
}
|
15
|
+
|
16
|
+
async kill() {
|
17
|
+
const fr = await this.forkResult.catch(() => {});
|
18
|
+
if (!fr)
|
19
|
+
return;
|
20
|
+
await fr.kill();
|
21
|
+
}
|
22
|
+
|
23
|
+
async getResult() {
|
24
|
+
const fr = await this.forkResult;
|
25
|
+
return fr.getResult();
|
26
|
+
}
|
27
|
+
|
28
|
+
async waitKilled() {
|
29
|
+
const fr = await this.forkResult;
|
30
|
+
await fr.waitKilled();
|
31
|
+
}
|
32
|
+
}
|
4
33
|
|
5
34
|
export class ClusterForkService {
|
6
35
|
constructor(public runtime: ScryptedRuntime) { }
|
7
36
|
|
8
|
-
async fork(
|
37
|
+
async fork(runtimeWorkerOptions: RuntimeWorkerOptions, options: ClusterForkOptions, peerLiveness: PeerLiveness, getZip: () => Promise<Buffer>) {
|
9
38
|
const matchingWorkers = [...this.runtime.clusterWorkers.entries()].map(([id, worker]) => ({
|
10
39
|
worker,
|
11
40
|
matches: matchesClusterLabels(options, worker.labels),
|
@@ -34,16 +63,21 @@ export class ClusterForkService {
|
|
34
63
|
}
|
35
64
|
|
36
65
|
const fork: ClusterForkParam = await worker.peer.getParam('fork');
|
37
|
-
const
|
38
|
-
|
66
|
+
const forkResultPromise = fork(options.runtime, runtimeWorkerOptions, peerLiveness, getZip);
|
67
|
+
|
68
|
+
options.id ||= this.runtime.findPluginDevice(runtimeWorkerOptions.packageJson.name)?._id;
|
39
69
|
worker.forks.add(options);
|
40
|
-
|
41
|
-
|
70
|
+
|
71
|
+
forkResultPromise.then(forkResult => {
|
72
|
+
forkResult.clusterWorkerId = worker.id;
|
73
|
+
forkResult.waitKilled().catch(() => { }).finally(() => {
|
74
|
+
worker.forks.delete(options);
|
75
|
+
})
|
42
76
|
});
|
43
77
|
|
44
|
-
|
45
|
-
return
|
46
|
-
}
|
78
|
+
const ret: ClusterForkResultInterface = new WrappedForkResult(worker.id, forkResultPromise);
|
79
|
+
return ret;
|
80
|
+
};
|
47
81
|
|
48
82
|
async getClusterWorkers() {
|
49
83
|
const ret: any = {};
|