diff --git a/lib/extension-wrapper.js b/bin/genieacs-ext old mode 100644 new mode 100755 similarity index 96% rename from lib/extension-wrapper.js rename to bin/genieacs-ext index 7e27443..43cc772 --- a/lib/extension-wrapper.js +++ b/bin/genieacs-ext @@ -1,3 +1,4 @@ +#!/usr/bin/env -S node -r esm /** * Copyright 2013-2018 Zaid Abdulla * @@ -40,7 +41,7 @@ function errorToFault(err) { fault.detail.stack = err.stack; // Trim the stack trace const stackTrimIndex = fault.detail.stack.match( - /\s+at\s[^\s]+\s\(.*extension-wrapper\.js:.+\)/ + /\s+at\s[^\s]+\s\(.*genieacs-ext:.+\)/ ); if (stackTrimIndex) fault.detail.stack = fault.detail.stack.slice(0, stackTrimIndex.index); diff --git a/build/build.js b/build/build.js index 20dfa2f..7e2e91f 100644 --- a/build/build.js +++ b/build/build.js @@ -158,6 +158,7 @@ async function generateToolsJs() { async function generateBackendJs() { for (const bin of [ "genieacs-cwmp", + "genieacs-ext", "genieacs-nbi", "genieacs-fs", "genieacs-ui" diff --git a/lib/extensions.js b/lib/extensions.js index f1d3e83..60cf9f9 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -18,19 +18,19 @@ */ "use strict"; -import { fork } from "child_process"; +import { spawn } from "child_process"; import crypto from "crypto"; import * as config from "./config"; const TIMEOUT = config.get("EXT_TIMEOUT"); const processes = {}; -const jobs = {}; +const jobs = new Map(); function messageHandler(message) { - const func = jobs[message[0]]; + const func = jobs.get(message[0]); if (func) { - delete jobs[message[0]]; + jobs.delete(message[0]); func(null, message[1], message[2]); } } @@ -38,12 +38,20 @@ function messageHandler(message) { export function run(args, callback) { const scriptName = args[0]; + const id = crypto.randomBytes(8).toString("hex"); + jobs.set(id, callback); + if (!processes[scriptName]) { - const p = fork("lib/extension-wrapper", [scriptName]); + const p = spawn("bin/genieacs-ext", [scriptName], { + stdio: ["inherit", "inherit", "inherit", "ipc"] + }); processes[scriptName] = p; - p.on("error", () => { + p.on("error", err => { if (processes[scriptName] === p) { + if (jobs.delete(id)) + callback(null, { code: err.name, message: err.message }); + kill(processes[scriptName]); delete processes[scriptName]; } @@ -59,15 +67,13 @@ export function run(args, callback) { p.on("message", messageHandler); } - const id = crypto.randomBytes(8).toString("hex"); - jobs[id] = callback; setTimeout(() => { - if (id in jobs) { - delete jobs[id]; + if (jobs.delete(id)) callback(null, { code: "timeout", message: "Extension timed out" }); - } }, TIMEOUT); + if (!processes[scriptName].connected) return false; + return processes[scriptName].send([id, args.slice(1)]); }