diff --git a/server/package.json b/server/package.json index b2897bb0b..9461c8c29 100644 --- a/server/package.json +++ b/server/package.json @@ -60,6 +60,7 @@ "bin": { "scrypted-serve": "bin/scrypted-serve" }, + "main": "dist/scrypted-main.js", "scripts": { "preserve": "npm run build", "serve": "node --expose-gc dist/scrypted-main.js", diff --git a/server/src/plugin/plugin-host.ts b/server/src/plugin/plugin-host.ts index e581d5709..f08dade9f 100644 --- a/server/src/plugin/plugin-host.ts +++ b/server/src/plugin/plugin-host.ts @@ -294,20 +294,23 @@ export class PluginHost { pluginDebug, }); } - else { + else if (!this.packageJson.scrypted.runtime || this.packageJson.scrypted.runtime === 'node') { if (!process.env.SCRYPTED_SHARED_WORKER || (this.packageJson.optionalDependencies && Object.keys(this.packageJson.optionalDependencies).length)) { - this.worker = new NodeForkWorker(this.pluginId, { + this.worker = new NodeForkWorker(this.scrypted.mainFilename, this.pluginId, { env, pluginDebug, }); } else { - this.worker = new NodeThreadWorker(this.pluginId, { + this.worker = new NodeThreadWorker(this.scrypted.mainFilename, this.pluginId, { env, pluginDebug, }); } } + else { + throw new Error(`Unsupported Scrypted runtime: ${this.packageJson.scrypted.runtime}`); + } this.peer = new RpcPeer('host', this.pluginId, (message, reject, serializationContext) => { if (connected) { diff --git a/server/src/plugin/plugin-remote-worker.ts b/server/src/plugin/plugin-remote-worker.ts index c800e7943..b92d2729f 100644 --- a/server/src/plugin/plugin-remote-worker.ts +++ b/server/src/plugin/plugin-remote-worker.ts @@ -22,7 +22,7 @@ const { link } = require('linkfs'); const serverVersion = require('../../package.json').version; -export function startPluginRemote(pluginId: string, peerSend: (message: RpcMessage, reject?: (e: Error) => void, serializationContext?: any) => void) { +export function startPluginRemote(mainFilename: string, pluginId: string, peerSend: (message: RpcMessage, reject?: (e: Error) => void, serializationContext?: any) => void) { const peer = new RpcPeer('unknown', 'host', peerSend); let systemManager: SystemManager; @@ -244,7 +244,7 @@ export function startPluginRemote(pluginId: string, peerSend: (message: RpcMessa const forks = new Set(); scrypted.fork = () => { - const ntw = new NodeThreadWorker(pluginId, { + const ntw = new NodeThreadWorker(mainFilename, pluginId, { env: process.env, pluginDebug: undefined, }); diff --git a/server/src/plugin/runtime/node-fork-worker.ts b/server/src/plugin/runtime/node-fork-worker.ts index 14f14c356..007b11a2f 100644 --- a/server/src/plugin/runtime/node-fork-worker.ts +++ b/server/src/plugin/runtime/node-fork-worker.ts @@ -9,7 +9,7 @@ import net from "net"; export class NodeForkWorker extends ChildProcessWorker { - constructor(pluginId: string, options: RuntimeWorkerOptions) { + constructor(mainFilename: string, pluginId: string, options: RuntimeWorkerOptions) { super(pluginId, options); const {env, pluginDebug} = options; @@ -19,7 +19,7 @@ export class NodeForkWorker extends ChildProcessWorker { execArgv.push(`--inspect=0.0.0.0:${pluginDebug.inspectPort}`); } - this.worker = child_process.fork(require.main.filename, ['child', this.pluginId], { + this.worker = child_process.fork(mainFilename, ['child', this.pluginId], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'], env: Object.assign({}, process.env, env, { NODE_PATH: path.join(getPluginNodePath(this.pluginId), 'node_modules'), diff --git a/server/src/plugin/runtime/node-thread-worker.ts b/server/src/plugin/runtime/node-thread-worker.ts index 0a8e1c018..3f5960efd 100644 --- a/server/src/plugin/runtime/node-thread-worker.ts +++ b/server/src/plugin/runtime/node-thread-worker.ts @@ -10,11 +10,11 @@ export class NodeThreadWorker extends EventEmitter implements RuntimeWorker { terminated: boolean; worker: worker_threads.Worker; - constructor(public pluginId: string, options: RuntimeWorkerOptions) { + constructor(mainFilename: string, public pluginId: string, options: RuntimeWorkerOptions) { super(); const { env } = options; - this.worker = new worker_threads.Worker(require.main.filename, { + this.worker = new worker_threads.Worker(mainFilename, { argv: ['child-thread', this.pluginId], env: Object.assign({}, process.env, env, { NODE_PATH: path.join(getPluginNodePath(this.pluginId), 'node_modules'), diff --git a/server/src/plugin/runtime/python-worker.ts b/server/src/plugin/runtime/python-worker.ts index bb382e763..71bb1b6aa 100644 --- a/server/src/plugin/runtime/python-worker.ts +++ b/server/src/plugin/runtime/python-worker.ts @@ -58,12 +58,14 @@ export class PythonRuntimeWorker extends ChildProcessWorker { args.push(this.pluginId); + const types = require.resolve('@scrypted/types'); + const PYTHONPATH = types.substring(0, types.indexOf('@scrypted/types') + '@scrypted/types'.length); this.worker = child_process.spawn(pythonPath, args, { // stdin, stdout, stderr, peer in, peer out stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'], env: Object.assign({ PYTHONUNBUFFERED: '1', - PYTHONPATH: path.join(process.cwd(), 'node_modules/@scrypted/types'), + PYTHONPATH, }, gstEnv, process.env, env), }); diff --git a/server/src/runtime.ts b/server/src/runtime.ts index bcbca451a..049d7f68d 100644 --- a/server/src/runtime.ts +++ b/server/src/runtime.ts @@ -84,7 +84,7 @@ export class ScryptedRuntime extends PluginHttp { addressSettings = new AddressSettings(this); usersService = new UsersService(this); - constructor(datastore: Level, insecure: http.Server, secure: https.Server, app: express.Application) { + constructor(public mainFilename: string, datastore: Level, insecure: http.Server, secure: https.Server, app: express.Application) { super(app); this.datastore = datastore; this.app = app; diff --git a/server/src/scrypted-main.ts b/server/src/scrypted-main.ts index 9cbbb1bfc..a193400a0 100644 --- a/server/src/scrypted-main.ts +++ b/server/src/scrypted-main.ts @@ -25,7 +25,8 @@ if (process.argv[2] === 'child' || process.argv[2] === 'child-thread') { console.error('unhandledRejection', e); }); - require('./scrypted-plugin-main'); + const start = require('./scrypted-plugin-main').default; + start(__filename); } else { // unhandled rejections are allowed if they are from a rpc/plugin call. @@ -37,5 +38,6 @@ else { console.warn('unhandled rejection of RPC Result', error); }); - require('./scrypted-server-main'); + const start = require('./scrypted-server-main').default; + start(__filename); } diff --git a/server/src/scrypted-plugin-main.ts b/server/src/scrypted-plugin-main.ts index 6b0f42ffd..49ce31a69 100644 --- a/server/src/scrypted-plugin-main.ts +++ b/server/src/scrypted-plugin-main.ts @@ -5,31 +5,35 @@ import v8 from 'v8'; import net from 'net'; import { SidebandSocketSerializer } from "./plugin/socket-serializer"; -if (process.argv[2] === 'child-thread') { - const peer = startPluginRemote(process.argv[3], (message, reject) => { - try { - worker_threads.parentPort.postMessage(v8.serialize(message)); - } - catch (e) { - reject?.(e); - } - }); - peer.transportSafeArgumentTypes.add(Buffer.name); - worker_threads.parentPort.on('message', message => peer.handleMessage(v8.deserialize(message))); +function start(mainFilename: string) { + if (process.argv[2] === 'child-thread') { + const peer = startPluginRemote(mainFilename, process.argv[3], (message, reject) => { + try { + worker_threads.parentPort.postMessage(v8.serialize(message)); + } + catch (e) { + reject?.(e); + } + }); + peer.transportSafeArgumentTypes.add(Buffer.name); + worker_threads.parentPort.on('message', message => peer.handleMessage(v8.deserialize(message))); + } + else { + const peer = startPluginRemote(mainFilename, process.argv[3], (message, reject, serializationContext) => process.send(message, serializationContext?.sendHandle, { + swallowErrors: !reject, + }, e => { + if (e) + reject?.(e); + })); + + peer.transportSafeArgumentTypes.add(Buffer.name); + peer.addSerializer(net.Socket, net.Socket.name, new SidebandSocketSerializer()); + process.on('message', message => peer.handleMessage(message as RpcMessage)); + process.on('disconnect', () => { + console.error('peer host disconnected, exiting.'); + process.exit(1); + }); + } } -else { - const peer = startPluginRemote(process.argv[3], (message, reject, serializationContext) => process.send(message, serializationContext?.sendHandle, { - swallowErrors: !reject, - }, e => { - if (e) - reject?.(e); - })); - peer.transportSafeArgumentTypes.add(Buffer.name); - peer.addSerializer(net.Socket, net.Socket.name, new SidebandSocketSerializer()); - process.on('message', message => peer.handleMessage(message as RpcMessage)); - process.on('disconnect', () => { - console.error('peer host disconnected, exiting.'); - process.exit(1); - }); -} +export default start; diff --git a/server/src/scrypted-server-main.ts b/server/src/scrypted-server-main.ts index d8ddceacf..ce6ca8552 100644 --- a/server/src/scrypted-server-main.ts +++ b/server/src/scrypted-server-main.ts @@ -7,7 +7,6 @@ import fs from 'fs'; import http from 'http'; import httpAuth from 'http-auth'; import https from 'https'; -import ip from 'ip'; import mkdirp from 'mkdirp'; import net from 'net'; import os from 'os'; @@ -105,7 +104,7 @@ app.use(bodyParser.json()) // parse some custom thing into a Buffer app.use(bodyParser.raw({ type: 'application/zip', limit: 100000000 }) as any) -async function start() { +async function start(mainFilename: string) { const volumeDir = getScryptedVolume(); mkdirp.sync(volumeDir); const dbPath = path.join(volumeDir, 'scrypted.db'); @@ -271,7 +270,7 @@ async function start() { next(); }); - const scrypted = new ScryptedRuntime(db, insecure, secure, app); + const scrypted = new ScryptedRuntime(mainFilename, db, insecure, secure, app); await scrypted.start(); listenServerPort('SCRYPTED_SECURE_PORT', SCRYPTED_SECURE_PORT, secure); @@ -627,4 +626,4 @@ async function start() { app.get('/', (_req, res) => res.redirect('/endpoint/@scrypted/core/public/')); } -start(); \ No newline at end of file +export default start;