From cd544cbbc59adf3fbe8e7f062ce9662a7a2dc4f7 Mon Sep 17 00:00:00 2001 From: Jason Mulligan <jason.mulligan@avoidwork.com> Date: Tue, 29 Sep 2015 20:02:31 -0400 Subject: [PATCH] Getting it functional --- lib/index.js | 68 +++++++++++++++++++++++++++++++++++++------ lib/noop.js | 3 ++ lib/worker.js | 80 +++++++++++++++++++++++++++++++++++++++++++++------ src/index.js | 50 +++++++++++++++++++++++++++----- src/noop.js | 1 + src/worker.js | 75 +++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 246 insertions(+), 31 deletions(-) create mode 100644 lib/noop.js create mode 100644 src/noop.js diff --git a/lib/index.js b/lib/index.js index 511bf67..471a6d2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,15 +1,67 @@ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + var path = require("path"); -var worker = require(path.join(__dirname, "worker.js")); +var fork = require("child_process").fork; +var worker = path.join(__dirname, "worker.js"); +var events = /^(error|message)$/; + +var Worker = (function () { + function Worker(arg) { + var _this = this; + + _classCallCheck(this, Worker); + + var isfn = typeof arg === "function", + input = isfn ? arg.toString() : arg; + + this.child = fork(worker); + this.onerror = undefined; + this.onmessage = undefined; + + this.child.on("error", function (e) { + if (_this.onerror) { + _this.onerror.call(_this, e); + } + }); + + this.child.on("message", function (msg) { + if (_this.onmessage) { + _this.onmessage.call(_this, JSON.parse(msg)); + } + }); -function factory(arg) { - var fn = typeof arg === "function", - obj = undefined; + this.child.send({ input: input, isfn: isfn }); + } - obj = worker(arg, fn); + _createClass(Worker, [{ + key: "addEventListener", + value: function addEventListener(event, fn) { + if (events.test(event)) { + this["on" + event] = fn; + } + } + }, { + key: "close", + value: function close() { + this.child.kill(); + } + }, { + key: "postMessage", + value: function postMessage(msg) { + this.child.send(JSON.stringify({ data: msg })); + } + }, { + key: "terminate", + value: function terminate() { + this.child.kill(); + } + }]); - return obj; -} + return Worker; +})(); -module.exports = factory; +module.exports = Worker; diff --git a/lib/noop.js b/lib/noop.js new file mode 100644 index 0000000..7f0f4e8 --- /dev/null +++ b/lib/noop.js @@ -0,0 +1,3 @@ +"use strict"; + +module.exports = function () {}; diff --git a/lib/worker.js b/lib/worker.js index 35e0866..6d59a12 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -1,15 +1,79 @@ "use strict"; -var spawn = require("child_process").spawn; +var fs = require("fs"); +var path = require("path"); +var vm = require("vm"); +var noop = path.join(__dirname, "noop.js"); -function factory(arg) { - var ps = spawn("grep", [arg]); +function trim(arg) { + return arg.replace(/^(\s+|\t+|\n+)|(\s+|\t+|\n+)$/g, ""); +} - ps.on("close", function (code, signal) { - console.log("child process terminated due to receipt of signal " + signal); - }); +function explode(arg) { + return trim(arg).split(new RegExp("\\s*,\\s*")); +} - return ps; +function toFunction(arg) { + var args = trim(arg.replace(/^.*\(/, "").replace(/[\t|\r|\n|\"|\']+/g, "").replace(/\).*/, "")), + body = trim(arg.replace(/^.*\{/, "").replace(/\}$/, "")); + + return Function.apply(Function, explode(args).concat([body])); } -module.exports = factory; +// Bootstraps the Worker +process.once("message", function (obj) { + var exp = obj.isfn ? toFunction(obj.input) : fs.readFileSync(obj.input, "utf8"), + sexp = undefined; + + global.self = { + postMessage: function postMessage(msg) { + process.send(JSON.stringify({ data: msg })); + }, + onmessage: noop, + onerror: noop, + addEventListener: function addEventListener(event, fn) { + if (event === "message") { + global.onmessage = global.self.onmessage = fn; + } + + if (event === "error") { + global.onerror = global.self.onerror = fn; + } + } + }; + + global.importScripts = function () { + var script = undefined, + scripts = undefined; + + for (var _len = arguments.length, files = Array(_len), _key = 0; _key < _len; _key++) { + files[_key] = arguments[_key]; + } + + scripts = files.map(function (file) { + return fs.readFileSync(file, "utf8"); + }).join("\n"); + + script = vm.createScript(scripts); + script.runInThisContext(); + }; + + Object.keys(global.self).forEach(function (key) { + global[key] = global.self[key]; + }); + + process.on("message", function (msg) { + global.self.onmessage(JSON.parse(msg)); + }); + + process.on("error", function (err) { + global.self.onerror(err); + }); + + if (typeof exp === "function") { + exp(); + } else { + sexp = vm.createScript(exp); + sexp.runInThisContext(); + } +}); diff --git a/src/index.js b/src/index.js index b884591..af7957d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,49 @@ const path = require("path"); -const worker = require(path.join(__dirname, "worker.js")); +const fork = require("child_process").fork; +const worker = path.join(__dirname, "worker.js"); +const events = /^(error|message)$/; -function factory (arg) { - let fn = typeof arg === "function", - obj; +class Worker { + constructor (arg) { + let isfn = typeof arg === "function", + input = isfn ? arg.toString() : arg; - obj = worker(arg, fn); + this.child = fork(worker); + this.onerror = undefined; + this.onmessage = undefined; - return obj; + this.child.on("error", e => { + if (this.onerror) { + this.onerror.call(this, e); + } + }); + + this.child.on("message", msg => { + if (this.onmessage) { + this.onmessage.call(this, JSON.parse(msg)); + } + }); + + this.child.send({input: input, isfn: isfn}); + } + + addEventListener (event, fn) { + if (events.test(event)) { + this["on" + event] = fn; + } + } + + close () { + this.child.kill(); + } + + postMessage (msg) { + this.child.send(JSON.stringify({data: msg})); + } + + terminate () { + this.child.kill(); + } } -module.exports = factory; +module.exports = Worker; diff --git a/src/noop.js b/src/noop.js new file mode 100644 index 0000000..ea41b01 --- /dev/null +++ b/src/noop.js @@ -0,0 +1 @@ +module.exports = function () {}; diff --git a/src/worker.js b/src/worker.js index c123c88..7e1a6cc 100644 --- a/src/worker.js +++ b/src/worker.js @@ -1,13 +1,72 @@ -const spawn = require("child_process").spawn; +const fs = require("fs"); +const path = require("path"); +const vm = require("vm"); +const noop = path.join(__dirname, "noop.js"); -function factory (arg) { - let ps = spawn("grep", [arg]); +function trim (arg) { + return arg.replace(/^(\s+|\t+|\n+)|(\s+|\t+|\n+)$/g, ""); +} - ps.on("close", function (code, signal) { - console.log("child process terminated due to receipt of signal " + signal); - }); +function explode (arg) { + return trim(arg).split(new RegExp("\\s*,\\s*")); +} + +function toFunction (arg) { + let args = trim(arg.replace(/^.*\(/, "").replace(/[\t|\r|\n|\"|\']+/g, "").replace(/\).*/, "")), + body = trim(arg.replace(/^.*\{/, "").replace(/\}$/, "")); - return ps; + return Function.apply(Function, explode(args).concat([body])); } -module.exports = factory; +// Bootstraps the Worker +process.once("message", function (obj) { + let exp = obj.isfn ? toFunction(obj.input) : fs.readFileSync(obj.input, "utf8"), + sexp; + + global.self = { + postMessage: function (msg) { + process.send(JSON.stringify({data: msg})); + }, + onmessage: noop, + onerror: noop, + addEventListener: function (event, fn) { + if (event === "message") { + global.onmessage = global.self.onmessage = fn; + } + + if (event === "error") { + global.onerror = global.self.onerror = fn; + } + } + }; + + global.importScripts = function (...files) { + let script, scripts; + + scripts = files.map(function (file) { + return fs.readFileSync(file, "utf8"); + }).join("\n"); + + script = vm.createScript(scripts); + script.runInThisContext(); + }; + + Object.keys(global.self).forEach(function (key) { + global[key] = global.self[key]; + }); + + process.on("message", function (msg) { + global.self.onmessage(JSON.parse(msg)); + }); + + process.on("error", function (err) { + global.self.onerror(err); + }); + + if (typeof exp === "function") { + exp(); + } else { + sexp = vm.createScript(exp); + sexp.runInThisContext(); + } +}); -- GitLab