workers: classify.
This commit is contained in:
parent
f313ca166d
commit
bad24a6f31
@ -10,40 +10,42 @@ const assert = require('assert');
|
|||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Child
|
||||||
* Represents a child process.
|
* Represents a child process.
|
||||||
* @alias module:workers.Child
|
* @alias module:workers.Child
|
||||||
* @constructor
|
* @extends EventEmitter
|
||||||
* @ignore
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Child extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Represents a child process.
|
||||||
|
* @constructor
|
||||||
* @param {String} file
|
* @param {String} file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Child(file) {
|
constructor(file) {
|
||||||
if (!(this instanceof Child))
|
super();
|
||||||
return new Child(file);
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
this.init(file);
|
this.init(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Child.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether child process support is available.
|
* Test whether child process support is available.
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.hasSupport = function hasSupport() {
|
static hasSupport() {
|
||||||
return typeof global.postMessage === 'function';
|
return typeof global.postMessage === 'function';
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize child process. Bind to events.
|
* Initialize child process. Bind to events.
|
||||||
* @private
|
* @private
|
||||||
* @param {String} file
|
* @param {String} file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.init = function init(file) {
|
init(file) {
|
||||||
this.child = new global.Worker(file);
|
this.child = new global.Worker(file);
|
||||||
|
|
||||||
this.child.onerror = (event) => {
|
this.child.onerror = (event) => {
|
||||||
@ -64,15 +66,15 @@ Child.prototype.init = function init(file) {
|
|||||||
}
|
}
|
||||||
this.emit('data', data);
|
this.emit('data', data);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to child process.
|
* Send data to child process.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.write = function write(data) {
|
write(data) {
|
||||||
if (this.child.postMessage.length === 2) {
|
if (this.child.postMessage.length === 2) {
|
||||||
data.__proto__ = Uint8Array.prototype;
|
data.__proto__ = Uint8Array.prototype;
|
||||||
this.child.postMessage({ data }, [data]);
|
this.child.postMessage({ data }, [data]);
|
||||||
@ -80,16 +82,17 @@ Child.prototype.write = function write(data) {
|
|||||||
this.child.postMessage(data.toString('hex'));
|
this.child.postMessage(data.toString('hex'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the child process.
|
* Destroy the child process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
this.child.terminate();
|
this.child.terminate();
|
||||||
this.emit('exit', 15 | 0x80, 'SIGTERM');
|
this.emit('exit', 15 | 0x80, 'SIGTERM');
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
@ -14,42 +14,45 @@ const children = new Set();
|
|||||||
let exitBound = false;
|
let exitBound = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Child
|
||||||
* Represents a child process.
|
* Represents a child process.
|
||||||
* @alias module:workers.Child
|
* @alias module:workers.Child
|
||||||
|
* @extends EventEmitter
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Child extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Represents a child process.
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} file
|
* @param {String} file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Child(file) {
|
constructor(file) {
|
||||||
if (!(this instanceof Child))
|
super();
|
||||||
return new Child(file);
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
bindExit();
|
bindExit();
|
||||||
children.add(this);
|
children.add(this);
|
||||||
|
|
||||||
this.init(file);
|
this.init(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Child.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Test whether child process support is available.
|
* Test whether child process support is available.
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.hasSupport = function hasSupport() {
|
static hasSupport() {
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize child process (node.js).
|
* Initialize child process (node.js).
|
||||||
* @private
|
* @private
|
||||||
* @param {String} file
|
* @param {String} file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.init = function init(file) {
|
init(file) {
|
||||||
const bin = process.argv[0];
|
const bin = process.argv[0];
|
||||||
const filename = path.resolve(__dirname, file);
|
const filename = path.resolve(__dirname, file);
|
||||||
const options = { stdio: 'pipe', env: process.env };
|
const options = { stdio: 'pipe', env: process.env };
|
||||||
@ -85,25 +88,26 @@ Child.prototype.init = function init(file) {
|
|||||||
this.child.stdout.on('data', (data) => {
|
this.child.stdout.on('data', (data) => {
|
||||||
this.emit('data', data);
|
this.emit('data', data);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to child process.
|
* Send data to child process.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.write = function write(data) {
|
write(data) {
|
||||||
return this.child.stdin.write(data);
|
return this.child.stdin.write(data);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the child process.
|
* Destroy the child process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Child.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
this.child.kill('SIGTERM');
|
this.child.kill('SIGTERM');
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup all child processes.
|
* Cleanup all child processes.
|
||||||
|
|||||||
@ -12,15 +12,17 @@ const bio = require('bufio');
|
|||||||
/**
|
/**
|
||||||
* Framer
|
* Framer
|
||||||
* @alias module:workers.Framer
|
* @alias module:workers.Framer
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Framer {
|
||||||
|
/**
|
||||||
|
* Create a framer.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Framer() {
|
constructor() {}
|
||||||
if (!(this instanceof Framer))
|
|
||||||
return new Framer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Framer.prototype.packet = function packet(payload) {
|
packet(payload) {
|
||||||
const size = 10 + payload.getSize();
|
const size = 10 + payload.getSize();
|
||||||
const bw = bio.write(size);
|
const bw = bio.write(size);
|
||||||
|
|
||||||
@ -36,7 +38,8 @@ Framer.prototype.packet = function packet(payload) {
|
|||||||
msg.writeUInt32LE(msg.length - 10, 5, true);
|
msg.writeUInt32LE(msg.length - 10, 5, true);
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
@ -18,16 +18,20 @@ const packets = require('./packets');
|
|||||||
const Parent = require('./parent');
|
const Parent = require('./parent');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Master
|
||||||
* Represents the master process.
|
* Represents the master process.
|
||||||
* @alias module:workers.Master
|
* @alias module:workers.Master
|
||||||
|
* @extends EventEmitter
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Master extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Create the master process.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Master() {
|
constructor() {
|
||||||
if (!(this instanceof Master))
|
super();
|
||||||
return new Master();
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
this.parent = new Parent();
|
this.parent = new Parent();
|
||||||
this.framer = new Framer();
|
this.framer = new Framer();
|
||||||
@ -36,16 +40,14 @@ function Master() {
|
|||||||
this.color = false;
|
this.color = false;
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Master.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize master. Bind events.
|
* Initialize master. Bind events.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.init = function init() {
|
init() {
|
||||||
this.parent.on('data', (data) => {
|
this.parent.on('data', (data) => {
|
||||||
this.parser.feed(data);
|
this.parser.feed(data);
|
||||||
});
|
});
|
||||||
@ -66,82 +68,82 @@ Master.prototype.init = function init() {
|
|||||||
this.parser.on('packet', (packet) => {
|
this.parser.on('packet', (packet) => {
|
||||||
this.emit('packet', packet);
|
this.emit('packet', packet);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set environment.
|
* Set environment.
|
||||||
* @param {Object} env
|
* @param {Object} env
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.setEnv = function setEnv(env) {
|
setEnv(env) {
|
||||||
this.color = env.BCOIN_WORKER_ISTTY === '1';
|
this.color = env.BCOIN_WORKER_ISTTY === '1';
|
||||||
this.set(env.BCOIN_WORKER_NETWORK);
|
this.set(env.BCOIN_WORKER_NETWORK);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set primary network.
|
* Set primary network.
|
||||||
* @param {NetworkType|Network} network
|
* @param {NetworkType|Network} network
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.set = function set(network) {
|
set(network) {
|
||||||
return Network.set(network);
|
return Network.set(network);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to worker.
|
* Send data to worker.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.write = function write(data) {
|
write(data) {
|
||||||
return this.parent.write(data);
|
return this.parent.write(data);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frame and send a packet.
|
* Frame and send a packet.
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.send = function send(packet) {
|
send(packet) {
|
||||||
return this.write(this.framer.packet(packet));
|
return this.write(this.framer.packet(packet));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit an event on the worker side.
|
* Emit an event on the worker side.
|
||||||
* @param {String} event
|
* @param {String} event
|
||||||
* @param {...Object} arg
|
* @param {...Object} arg
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.sendEvent = function sendEvent(...items) {
|
sendEvent(...items) {
|
||||||
return this.send(new packets.EventPacket(items));
|
return this.send(new packets.EventPacket(items));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the worker.
|
* Destroy the worker.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
return this.parent.destroy();
|
return this.parent.destroy();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a message to stdout in the master process.
|
* Write a message to stdout in the master process.
|
||||||
* @param {Object|String} obj
|
* @param {Object|String} obj
|
||||||
* @param {...String} args
|
* @param {...String} args
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.log = function log() {
|
log() {
|
||||||
const text = format.apply(null, arguments);
|
const text = format.apply(null, arguments);
|
||||||
this.send(new packets.LogPacket(text));
|
this.send(new packets.LogPacket(text));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for messages from master process (only if worker).
|
* Listen for messages from master process (only if worker).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.listen = function listen() {
|
listen() {
|
||||||
assert(!this.listening, 'Already listening.');
|
assert(!this.listening, 'Already listening.');
|
||||||
|
|
||||||
this.listening = true;
|
this.listening = true;
|
||||||
@ -157,15 +159,15 @@ Master.prototype.listen = function listen() {
|
|||||||
this.emit('error', e);
|
this.emit('error', e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle packet.
|
* Handle packet.
|
||||||
* @private
|
* @private
|
||||||
* @param {Packet}
|
* @param {Packet}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Master.prototype.handlePacket = function handlePacket(packet) {
|
handlePacket(packet) {
|
||||||
let result;
|
let result;
|
||||||
|
|
||||||
switch (packet.cmd) {
|
switch (packet.cmd) {
|
||||||
@ -185,7 +187,8 @@ Master.prototype.handlePacket = function handlePacket(packet) {
|
|||||||
this.send(result);
|
this.send(result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -10,29 +10,31 @@ const assert = require('assert');
|
|||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Parent
|
||||||
* Represents the parent process.
|
* Represents the parent process.
|
||||||
* @alias module:workers.Parent
|
* @alias module:workers.Parent
|
||||||
* @constructor
|
* @extends EventEmitter
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Parent() {
|
class Parent extends EventEmitter {
|
||||||
if (!(this instanceof Parent))
|
/**
|
||||||
return new Parent();
|
* Create the parent process.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
EventEmitter.call(this);
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Parent.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize master (web workers).
|
* Initialize master (web workers).
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.init = function init() {
|
init() {
|
||||||
global.onerror = (event) => {
|
global.onerror = (event) => {
|
||||||
this.emit('error', new Error('Worker error.'));
|
this.emit('error', new Error('Worker error.'));
|
||||||
};
|
};
|
||||||
@ -50,15 +52,15 @@ Parent.prototype.init = function init() {
|
|||||||
}
|
}
|
||||||
this.emit('data', data);
|
this.emit('data', data);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to parent process.
|
* Send data to parent process.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.write = function write(data) {
|
write(data) {
|
||||||
if (global.postMessage.length === 2) {
|
if (global.postMessage.length === 2) {
|
||||||
data.__proto__ = Uint8Array.prototype;
|
data.__proto__ = Uint8Array.prototype;
|
||||||
global.postMessage({ data }, [data]);
|
global.postMessage({ data }, [data]);
|
||||||
@ -66,15 +68,16 @@ Parent.prototype.write = function write(data) {
|
|||||||
global.postMessage(data.toString('hex'));
|
global.postMessage(data.toString('hex'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the parent process.
|
* Destroy the parent process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
global.close();
|
global.close();
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
@ -9,28 +9,30 @@
|
|||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Parent
|
||||||
* Represents the parent process.
|
* Represents the parent process.
|
||||||
* @alias module:workers.Parent
|
* @alias module:workers.Parent
|
||||||
|
* @extends EventEmitter
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Parent extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Create the parent process.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Parent() {
|
constructor() {
|
||||||
if (!(this instanceof Parent))
|
super();
|
||||||
return new Parent();
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Parent.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize master (node.js).
|
* Initialize master (node.js).
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.init = function init() {
|
init() {
|
||||||
process.stdin.on('data', (data) => {
|
process.stdin.on('data', (data) => {
|
||||||
this.emit('data', data);
|
this.emit('data', data);
|
||||||
});
|
});
|
||||||
@ -43,25 +45,26 @@ Parent.prototype.init = function init() {
|
|||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
this.emit('exception', err);
|
this.emit('exception', err);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to parent process.
|
* Send data to parent process.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.write = function write(data) {
|
write(data) {
|
||||||
return process.stdout.write(data);
|
return process.stdout.write(data);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the parent process.
|
* Destroy the parent process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parent.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
return process.exit(0);
|
return process.exit(0);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* workers.js - worker processes for bcoin
|
* parser.js - worker parser for bcoin
|
||||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
||||||
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
||||||
* https://github.com/bcoin-org/bcoin
|
* https://github.com/bcoin-org/bcoin
|
||||||
@ -14,24 +14,25 @@ const packets = require('./packets');
|
|||||||
/**
|
/**
|
||||||
* Parser
|
* Parser
|
||||||
* @alias module:workers.Parser
|
* @alias module:workers.Parser
|
||||||
|
* @extends EventEmitter
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Parser extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Create a parser.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Parser() {
|
constructor() {
|
||||||
if (!(this instanceof Parser))
|
super();
|
||||||
return new Parser();
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
this.waiting = 9;
|
this.waiting = 9;
|
||||||
this.header = null;
|
this.header = null;
|
||||||
this.pending = [];
|
this.pending = [];
|
||||||
this.total = 0;
|
this.total = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Parser.prototype, EventEmitter.prototype);
|
feed(data) {
|
||||||
|
|
||||||
Parser.prototype.feed = function feed(data) {
|
|
||||||
this.total += data.length;
|
this.total += data.length;
|
||||||
this.pending.push(data);
|
this.pending.push(data);
|
||||||
|
|
||||||
@ -39,9 +40,9 @@ Parser.prototype.feed = function feed(data) {
|
|||||||
const chunk = this.read(this.waiting);
|
const chunk = this.read(this.waiting);
|
||||||
this.parse(chunk);
|
this.parse(chunk);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Parser.prototype.read = function read(size) {
|
read(size) {
|
||||||
assert(this.total >= size, 'Reading too much.');
|
assert(this.total >= size, 'Reading too much.');
|
||||||
|
|
||||||
if (size === 0)
|
if (size === 0)
|
||||||
@ -80,9 +81,9 @@ Parser.prototype.read = function read(size) {
|
|||||||
this.total -= chunk.length;
|
this.total -= chunk.length;
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
};
|
}
|
||||||
|
|
||||||
Parser.prototype.parse = function parse(data) {
|
parse(data) {
|
||||||
let header = this.header;
|
let header = this.header;
|
||||||
|
|
||||||
if (!header) {
|
if (!header) {
|
||||||
@ -118,16 +119,16 @@ Parser.prototype.parse = function parse(data) {
|
|||||||
packet.id = header.id;
|
packet.id = header.id;
|
||||||
|
|
||||||
this.emit('packet', packet);
|
this.emit('packet', packet);
|
||||||
};
|
}
|
||||||
|
|
||||||
Parser.prototype.parseHeader = function parseHeader(data) {
|
parseHeader(data) {
|
||||||
const id = data.readUInt32LE(0, true);
|
const id = data.readUInt32LE(0, true);
|
||||||
const cmd = data.readUInt8(4, true);
|
const cmd = data.readUInt8(4, true);
|
||||||
const size = data.readUInt32LE(5, true);
|
const size = data.readUInt32LE(5, true);
|
||||||
return new Header(id, cmd, size);
|
return new Header(id, cmd, size);
|
||||||
};
|
}
|
||||||
|
|
||||||
Parser.prototype.parsePacket = function parsePacket(header, data) {
|
parsePacket(header, data) {
|
||||||
switch (header.cmd) {
|
switch (header.cmd) {
|
||||||
case packets.types.ENV:
|
case packets.types.ENV:
|
||||||
return packets.EnvPacket.fromRaw(data);
|
return packets.EnvPacket.fromRaw(data);
|
||||||
@ -174,18 +175,25 @@ Parser.prototype.parsePacket = function parsePacket(header, data) {
|
|||||||
default:
|
default:
|
||||||
throw new Error('Unknown packet.');
|
throw new Error('Unknown packet.');
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Header
|
* Header
|
||||||
* @constructor
|
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Header(id, cmd, size) {
|
class Header {
|
||||||
|
/**
|
||||||
|
* Create a header.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor(id, cmd, size) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.cmd = cmd;
|
this.cmd = cmd;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -20,23 +20,26 @@ const Framer = require('./framer');
|
|||||||
const packets = require('./packets');
|
const packets = require('./packets');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A worker pool.
|
* Worker Pool
|
||||||
* @alias module:workers.WorkerPool
|
* @alias module:workers.WorkerPool
|
||||||
* @constructor
|
* @extends EventEmitter
|
||||||
* @param {Object} options
|
|
||||||
* @param {Number} [options.size=num-cores] - Max pool size.
|
|
||||||
* @param {Number} [options.timeout=120000] - Execution timeout.
|
|
||||||
* @property {Number} size
|
* @property {Number} size
|
||||||
* @property {Number} timeout
|
* @property {Number} timeout
|
||||||
* @property {Map} children
|
* @property {Map} children
|
||||||
* @property {Number} uid
|
* @property {Number} uid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function WorkerPool(options) {
|
class WorkerPool extends EventEmitter {
|
||||||
if (!(this instanceof WorkerPool))
|
/**
|
||||||
return new WorkerPool(options);
|
* Create a worker pool.
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Number} [options.size=num-cores] - Max pool size.
|
||||||
|
* @param {Number} [options.timeout=120000] - Execution timeout.
|
||||||
|
*/
|
||||||
|
|
||||||
EventEmitter.call(this);
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
this.size = getCores();
|
this.size = getCores();
|
||||||
@ -47,16 +50,14 @@ function WorkerPool(options) {
|
|||||||
this.uid = 0;
|
this.uid = 0;
|
||||||
|
|
||||||
this.set(options);
|
this.set(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(WorkerPool.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Set worker pool options.
|
* Set worker pool options.
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.set = function set(options) {
|
set(options) {
|
||||||
if (!options)
|
if (!options)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -81,33 +82,33 @@ WorkerPool.prototype.set = function set(options) {
|
|||||||
assert(typeof options.file === 'string');
|
assert(typeof options.file === 'string');
|
||||||
this.file = options.file;
|
this.file = options.file;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open worker pool.
|
* Open worker pool.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.open = async function open() {
|
async open() {
|
||||||
;
|
;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close worker pool.
|
* Close worker pool.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.close = async function close() {
|
async close() {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spawn a new worker.
|
* Spawn a new worker.
|
||||||
* @param {Number} id - Worker ID.
|
* @param {Number} id - Worker ID.
|
||||||
* @returns {Worker}
|
* @returns {Worker}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.spawn = function spawn(id) {
|
spawn(id) {
|
||||||
const child = new Worker(this.file);
|
const child = new Worker(this.file);
|
||||||
|
|
||||||
child.id = id;
|
child.id = id;
|
||||||
@ -135,31 +136,31 @@ WorkerPool.prototype.spawn = function spawn(id) {
|
|||||||
this.emit('spawn', child);
|
this.emit('spawn', child);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a new worker, will not go above `size` option
|
* Allocate a new worker, will not go above `size` option
|
||||||
* and will automatically load balance the workers.
|
* and will automatically load balance the workers.
|
||||||
* @returns {Worker}
|
* @returns {Worker}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.alloc = function alloc() {
|
alloc() {
|
||||||
const id = this.uid++ % this.size;
|
const id = this.uid++ % this.size;
|
||||||
|
|
||||||
if (!this.children.has(id))
|
if (!this.children.has(id))
|
||||||
this.children.set(id, this.spawn(id));
|
this.children.set(id, this.spawn(id));
|
||||||
|
|
||||||
return this.children.get(id);
|
return this.children.get(id);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit an event on the worker side (all workers).
|
* Emit an event on the worker side (all workers).
|
||||||
* @param {String} event
|
* @param {String} event
|
||||||
* @param {...Object} arg
|
* @param {...Object} arg
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.sendEvent = function sendEvent() {
|
sendEvent() {
|
||||||
let result = true;
|
let result = true;
|
||||||
|
|
||||||
for (const child of this.children.values()) {
|
for (const child of this.children.values()) {
|
||||||
@ -168,25 +169,25 @@ WorkerPool.prototype.sendEvent = function sendEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy all workers.
|
* Destroy all workers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
for (const child of this.children.values())
|
for (const child of this.children.values())
|
||||||
child.destroy();
|
child.destroy();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a method for a worker to execute.
|
* Call a method for a worker to execute.
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
* @param {Number} timeout
|
* @param {Number} timeout
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.execute = function execute(packet, timeout) {
|
execute(packet, timeout) {
|
||||||
if (!this.enabled || !Child.hasSupport()) {
|
if (!this.enabled || !Child.hasSupport()) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
@ -208,9 +209,9 @@ WorkerPool.prototype.execute = function execute(packet, timeout) {
|
|||||||
const child = this.alloc();
|
const child = this.alloc();
|
||||||
|
|
||||||
return child.execute(packet, timeout);
|
return child.execute(packet, timeout);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the tx check job (default timeout).
|
* Execute the tx check job (default timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
@ -219,7 +220,7 @@ WorkerPool.prototype.execute = function execute(packet, timeout) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.check = async function check(tx, view, flags) {
|
async check(tx, view, flags) {
|
||||||
const packet = new packets.CheckPacket(tx, view, flags);
|
const packet = new packets.CheckPacket(tx, view, flags);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
|
|
||||||
@ -227,9 +228,9 @@ WorkerPool.prototype.check = async function check(tx, view, flags) {
|
|||||||
throw result.error;
|
throw result.error;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the tx signing job (default timeout).
|
* Execute the tx signing job (default timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {MTX} tx
|
* @param {MTX} tx
|
||||||
@ -238,7 +239,7 @@ WorkerPool.prototype.check = async function check(tx, view, flags) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.sign = async function sign(tx, ring, type) {
|
async sign(tx, ring, type) {
|
||||||
let rings = ring;
|
let rings = ring;
|
||||||
|
|
||||||
if (!Array.isArray(rings))
|
if (!Array.isArray(rings))
|
||||||
@ -250,9 +251,9 @@ WorkerPool.prototype.sign = async function sign(tx, ring, type) {
|
|||||||
result.inject(tx);
|
result.inject(tx);
|
||||||
|
|
||||||
return result.total;
|
return result.total;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the tx input check job (default timeout).
|
* Execute the tx input check job (default timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
@ -262,7 +263,7 @@ WorkerPool.prototype.sign = async function sign(tx, ring, type) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.checkInput = async function checkInput(tx, index, coin, flags) {
|
async checkInput(tx, index, coin, flags) {
|
||||||
const packet = new packets.CheckInputPacket(tx, index, coin, flags);
|
const packet = new packets.CheckInputPacket(tx, index, coin, flags);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
|
|
||||||
@ -270,9 +271,9 @@ WorkerPool.prototype.checkInput = async function checkInput(tx, index, coin, fla
|
|||||||
throw result.error;
|
throw result.error;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the tx input signing job (default timeout).
|
* Execute the tx input signing job (default timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {MTX} tx
|
* @param {MTX} tx
|
||||||
@ -283,14 +284,14 @@ WorkerPool.prototype.checkInput = async function checkInput(tx, index, coin, fla
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.signInput = async function signInput(tx, index, coin, ring, type) {
|
async signInput(tx, index, coin, ring, type) {
|
||||||
const packet = new packets.SignInputPacket(tx, index, coin, ring, type);
|
const packet = new packets.SignInputPacket(tx, index, coin, ring, type);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
result.inject(tx);
|
result.inject(tx);
|
||||||
return result.value;
|
return result.value;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the secp256k1 verify job (no timeout).
|
* Execute the secp256k1 verify job (no timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {Buffer} msg
|
* @param {Buffer} msg
|
||||||
@ -299,13 +300,13 @@ WorkerPool.prototype.signInput = async function signInput(tx, index, coin, ring,
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.ecVerify = async function ecVerify(msg, sig, key) {
|
async ecVerify(msg, sig, key) {
|
||||||
const packet = new packets.ECVerifyPacket(msg, sig, key);
|
const packet = new packets.ECVerifyPacket(msg, sig, key);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
return result.value;
|
return result.value;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the secp256k1 signing job (no timeout).
|
* Execute the secp256k1 signing job (no timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {Buffer} msg
|
* @param {Buffer} msg
|
||||||
@ -313,13 +314,13 @@ WorkerPool.prototype.ecVerify = async function ecVerify(msg, sig, key) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.ecSign = async function ecSign(msg, key) {
|
async ecSign(msg, key) {
|
||||||
const packet = new packets.ECSignPacket(msg, key);
|
const packet = new packets.ECSignPacket(msg, key);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
return result.sig;
|
return result.sig;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the mining job (no timeout).
|
* Execute the mining job (no timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
@ -329,13 +330,13 @@ WorkerPool.prototype.ecSign = async function ecSign(msg, key) {
|
|||||||
* @returns {Promise} - Returns {Number}.
|
* @returns {Promise} - Returns {Number}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.mine = async function mine(data, target, min, max) {
|
async mine(data, target, min, max) {
|
||||||
const packet = new packets.MinePacket(data, target, min, max);
|
const packet = new packets.MinePacket(data, target, min, max);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
return result.nonce;
|
return result.nonce;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute scrypt job (no timeout).
|
* Execute scrypt job (no timeout).
|
||||||
* @method
|
* @method
|
||||||
* @param {Buffer} passwd
|
* @param {Buffer} passwd
|
||||||
@ -347,24 +348,28 @@ WorkerPool.prototype.mine = async function mine(data, target, min, max) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WorkerPool.prototype.scrypt = async function scrypt(passwd, salt, N, r, p, len) {
|
async scrypt(passwd, salt, N, r, p, len) {
|
||||||
const packet = new packets.ScryptPacket(passwd, salt, N, r, p, len);
|
const packet = new packets.ScryptPacket(passwd, salt, N, r, p, len);
|
||||||
const result = await this.execute(packet, -1);
|
const result = await this.execute(packet, -1);
|
||||||
return result.key;
|
return result.key;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a worker.
|
* Worker
|
||||||
* @alias module:workers.Worker
|
* @alias module:workers.Worker
|
||||||
|
* @extends EventEmitter
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Worker extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* Create a worker.
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} file
|
* @param {String} file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Worker(file) {
|
constructor(file) {
|
||||||
if (!(this instanceof Worker))
|
super();
|
||||||
return new Worker(file);
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
this.id = -1;
|
this.id = -1;
|
||||||
this.framer = new Framer();
|
this.framer = new Framer();
|
||||||
@ -374,16 +379,14 @@ function Worker(file) {
|
|||||||
this.child = new Child(file);
|
this.child = new Child(file);
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(Worker.prototype, EventEmitter.prototype);
|
/**
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize worker. Bind to events.
|
* Initialize worker. Bind to events.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.init = function init() {
|
init() {
|
||||||
this.child.on('data', (data) => {
|
this.child.on('data', (data) => {
|
||||||
this.parser.feed(data);
|
this.parser.feed(data);
|
||||||
});
|
});
|
||||||
@ -405,14 +408,14 @@ Worker.prototype.init = function init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.listen();
|
this.listen();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for packets.
|
* Listen for packets.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.listen = function listen() {
|
listen() {
|
||||||
this.on('exit', (code, signal) => {
|
this.on('exit', (code, signal) => {
|
||||||
this.killJobs();
|
this.killJobs();
|
||||||
});
|
});
|
||||||
@ -435,15 +438,15 @@ Worker.prototype.listen = function listen() {
|
|||||||
? (process.stdout.isTTY ? '1' : '0')
|
? (process.stdout.isTTY ? '1' : '0')
|
||||||
: '0'
|
: '0'
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle packet.
|
* Handle packet.
|
||||||
* @private
|
* @private
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.handlePacket = function handlePacket(packet) {
|
handlePacket(packet) {
|
||||||
switch (packet.cmd) {
|
switch (packet.cmd) {
|
||||||
case packets.types.EVENT:
|
case packets.types.EVENT:
|
||||||
this.emit('event', packet.items);
|
this.emit('event', packet.items);
|
||||||
@ -462,71 +465,71 @@ Worker.prototype.handlePacket = function handlePacket(packet) {
|
|||||||
this.resolveJob(packet.id, packet);
|
this.resolveJob(packet.id, packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data to worker.
|
* Send data to worker.
|
||||||
* @param {Buffer} data
|
* @param {Buffer} data
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.write = function write(data) {
|
write(data) {
|
||||||
return this.child.write(data);
|
return this.child.write(data);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frame and send a packet.
|
* Frame and send a packet.
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.send = function send(packet) {
|
send(packet) {
|
||||||
return this.write(this.framer.packet(packet));
|
return this.write(this.framer.packet(packet));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send environment.
|
* Send environment.
|
||||||
* @param {Object} env
|
* @param {Object} env
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.sendEnv = function sendEnv(env) {
|
sendEnv(env) {
|
||||||
return this.send(new packets.EnvPacket(env));
|
return this.send(new packets.EnvPacket(env));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit an event on the worker side.
|
* Emit an event on the worker side.
|
||||||
* @param {String} event
|
* @param {String} event
|
||||||
* @param {...Object} arg
|
* @param {...Object} arg
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.sendEvent = function sendEvent(...items) {
|
sendEvent(...items) {
|
||||||
return this.send(new packets.EventPacket(items));
|
return this.send(new packets.EventPacket(items));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the worker.
|
* Destroy the worker.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
return this.child.destroy();
|
return this.child.destroy();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a method for a worker to execute.
|
* Call a method for a worker to execute.
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
* @param {Number} timeout
|
* @param {Number} timeout
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.execute = function execute(packet, timeout) {
|
execute(packet, timeout) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._execute(packet, timeout, resolve, reject);
|
this._execute(packet, timeout, resolve, reject);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a method for a worker to execute.
|
* Call a method for a worker to execute.
|
||||||
* @private
|
* @private
|
||||||
* @param {Packet} packet
|
* @param {Packet} packet
|
||||||
@ -536,7 +539,7 @@ Worker.prototype.execute = function execute(packet, timeout) {
|
|||||||
* the worker method specifies.
|
* the worker method specifies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype._execute = function _execute(packet, timeout, resolve, reject) {
|
_execute(packet, timeout, resolve, reject) {
|
||||||
const job = new PendingJob(this, packet.id, resolve, reject);
|
const job = new PendingJob(this, packet.id, resolve, reject);
|
||||||
|
|
||||||
assert(!this.pending.has(packet.id), 'ID overflow.');
|
assert(!this.pending.has(packet.id), 'ID overflow.');
|
||||||
@ -546,92 +549,98 @@ Worker.prototype._execute = function _execute(packet, timeout, resolve, reject)
|
|||||||
job.start(timeout);
|
job.start(timeout);
|
||||||
|
|
||||||
this.send(packet);
|
this.send(packet);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve a job.
|
* Resolve a job.
|
||||||
* @param {Number} id
|
* @param {Number} id
|
||||||
* @param {Packet} result
|
* @param {Packet} result
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.resolveJob = function resolveJob(id, result) {
|
resolveJob(id, result) {
|
||||||
const job = this.pending.get(id);
|
const job = this.pending.get(id);
|
||||||
|
|
||||||
if (!job)
|
if (!job)
|
||||||
throw new Error(`Job ${id} is not in progress.`);
|
throw new Error(`Job ${id} is not in progress.`);
|
||||||
|
|
||||||
job.resolve(result);
|
job.resolve(result);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reject a job.
|
* Reject a job.
|
||||||
* @param {Number} id
|
* @param {Number} id
|
||||||
* @param {Error} err
|
* @param {Error} err
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.rejectJob = function rejectJob(id, err) {
|
rejectJob(id, err) {
|
||||||
const job = this.pending.get(id);
|
const job = this.pending.get(id);
|
||||||
|
|
||||||
if (!job)
|
if (!job)
|
||||||
throw new Error(`Job ${id} is not in progress.`);
|
throw new Error(`Job ${id} is not in progress.`);
|
||||||
|
|
||||||
job.reject(err);
|
job.reject(err);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill all jobs associated with worker.
|
* Kill all jobs associated with worker.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Worker.prototype.killJobs = function killJobs() {
|
killJobs() {
|
||||||
for (const job of this.pending.values())
|
for (const job of this.pending.values())
|
||||||
job.destroy();
|
job.destroy();
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pending Job
|
* Pending Job
|
||||||
* @constructor
|
|
||||||
* @ignore
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PendingJob {
|
||||||
|
/**
|
||||||
|
* Create a pending job.
|
||||||
|
* @constructor
|
||||||
* @param {Worker} worker
|
* @param {Worker} worker
|
||||||
* @param {Number} id
|
* @param {Number} id
|
||||||
* @param {Function} resolve
|
* @param {Function} resolve
|
||||||
* @param {Function} reject
|
* @param {Function} reject
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function PendingJob(worker, id, resolve, reject) {
|
constructor(worker, id, resolve, reject) {
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.job = { resolve, reject };
|
this.job = { resolve, reject };
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the timer.
|
* Start the timer.
|
||||||
* @param {Number} timeout
|
* @param {Number} timeout
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PendingJob.prototype.start = function start(timeout) {
|
start(timeout) {
|
||||||
if (!timeout || timeout <= 0)
|
if (!timeout || timeout <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.timer = setTimeout(() => {
|
this.timer = setTimeout(() => {
|
||||||
this.reject(new Error('Worker timed out.'));
|
this.reject(new Error('Worker timed out.'));
|
||||||
}, timeout);
|
}, timeout);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the job with an error.
|
* Destroy the job with an error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PendingJob.prototype.destroy = function destroy() {
|
destroy() {
|
||||||
this.reject(new Error('Job was destroyed.'));
|
this.reject(new Error('Job was destroyed.'));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup job state.
|
* Cleanup job state.
|
||||||
* @returns {Job}
|
* @returns {Job}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PendingJob.prototype.cleanup = function cleanup() {
|
cleanup() {
|
||||||
const job = this.job;
|
const job = this.job;
|
||||||
|
|
||||||
assert(job, 'Already finished.');
|
assert(job, 'Already finished.');
|
||||||
@ -647,27 +656,28 @@ PendingJob.prototype.cleanup = function cleanup() {
|
|||||||
this.worker.pending.delete(this.id);
|
this.worker.pending.delete(this.id);
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete job with result.
|
* Complete job with result.
|
||||||
* @param {Object} result
|
* @param {Object} result
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PendingJob.prototype.resolve = function resolve(result) {
|
resolve(result) {
|
||||||
const job = this.cleanup();
|
const job = this.cleanup();
|
||||||
job.resolve(result);
|
job.resolve(result);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete job with error.
|
* Complete job with error.
|
||||||
* @param {Error} err
|
* @param {Error} err
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PendingJob.prototype.reject = function reject(err) {
|
reject(err) {
|
||||||
const job = this.cleanup();
|
const job = this.cleanup();
|
||||||
job.reject(err);
|
job.reject(err);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user