class Descendant extends events.EventEmitter {
constructor (process) {
super()
const descendant = this
this.process = process
this.children = {}
this._listeners = {}
this._counter = 0
events.EventEmitter.call(this)
}
createMockProcess () {
const process = new events.EventEmitter
process.pid = 2
process.env = { 'DESCENDANT_PROCESS_PATH': '1' }
process.send = function (message, socket) {
const vargs = Array.prototype.slice.call(arguments)
vargs.unshift('descendant:sent')
process.emit.apply(process, vargs)
}
process.connected = true
this.process = process
}
decrement () {
if (--this._counter == 0) {
this.process.removeListener('message', this._listener)
Object.keys(this.children).forEach(function (pid) {
this.removeChild(this.children[pid])
}, this)
if (this._parentProcessPath == null) {
delete this.process.env.DESCENDANT_PROCESS_PATH
} else {
this.process.env.DESCENDANT_PROCESS_PATH = this._parentProcessPath
}
this.path = null
}
}
increment () {
if (this._counter++ == 0) {
this._parentProcessPath = coalesce(this.process.env.DESCENDANT_PROCESS_PATH)
this.path = coalesce(this._parentProcessPath, '0').split(/\s+/).map(function (pid) {
return +pid
})
if (this.path[0] === 0) {
this.path = []
}
this.path.push(this.process.pid)
this.process.env.DESCENDANT_PROCESS_PATH = this.path.join(' ')
this.process.on('message', this._listener = down(this))
}
}
addMockChild (pid, cookie) {
const child = new events.EventEmitter
child.pid = pid
child.connected = true
child.send = function () {
const vargs = Array.prototype.slice.call(arguments)
vargs.unshift('descendant:sent')
this.emit.apply(this, vargs)
}
this.addChild(child, cookie)
return child
}
addChild (child, cookie) {
this.children[child.pid] = child
const listeners = this._listeners[child.pid] = {
message: up(this, cookie, child.pid),
close: close(this, cookie, child)
}
child.on('message', listeners.message)
child.on('close', listeners.close)
}
removeChild (child) {
if (Number.isInteger(child)) {
child = this.children[child]
}
const listeners = this._listeners[child.pid]
delete this.children[child.pid]
delete this._listeners[child.pid]
child.removeListener('message', listeners.message)
child.removeListener('close', listeners.close)
}
up (to, name, message) {
const vargs = Array.prototype.slice.call(arguments, 2)
if (!Array.isArray(to)) {
to = [ to ]
}
assert(to[0] !== 0 || vargs.length === 1, 'cannot broadcast a handle')
vargs[0] = {
module: 'descendant',
method: 'route',
name: name,
to: to,
path: [ this.process.pid ],
body: message
}
send(this.process, vargs)
}