0.1.20
changed default commands handling, removed _default namespace changed s and c name spaces to use ._c, and _s as default name spaces amend commands work with above ._c and ._s props changed .socket to ._socket to avoid namespace issues with instances using .socket. Instances should use the getSocket method! copied host and port options to connect. for mqtt socket to make setting those more standard cleaned up logging Add hooking for before send, and before and after process Improved/cleaned preempting default processingmaster
parent
6da51d453f
commit
ea1342272e
|
@ -2,6 +2,8 @@ import Base from '../src/base'
|
||||||
|
|
||||||
let dy = new Base({id:'dynamic', useRootNS: true })
|
let dy = new Base({id:'dynamic', useRootNS: true })
|
||||||
|
|
||||||
|
const HOST = 'nas.kebler.net'
|
||||||
|
|
||||||
let sensor = true
|
let sensor = true
|
||||||
|
|
||||||
//dummy simulated push
|
//dummy simulated push
|
||||||
|
@ -54,8 +56,9 @@ dy.switch = {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
await dy.init()
|
await dy.init()
|
||||||
await dy.addSocket('mqs','s','m')
|
await dy.addSocket('mqs','s','m',{host:HOST})
|
||||||
dy.socket.mqs.subscribe(['switch/on','switch/off','switch/toggle','sensor/test'])
|
dy.socket.mqs.subscribe(['lights/#'])
|
||||||
|
console.log('ready')
|
||||||
|
|
||||||
})().catch(err => {
|
})().catch(err => {
|
||||||
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||||
|
|
14
package.json
14
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@uci/base",
|
"name": "@uci/base",
|
||||||
"version": "0.1.19",
|
"version": "0.1.20",
|
||||||
"description": "Multi type and transport JSON packet communication base class. Used in UCI extended classes",
|
"description": "Multi type and transport JSON packet communication base class. Used in UCI extended classes",
|
||||||
"main": "src/base",
|
"main": "src/base",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
"fio": "nodemon -r esm examples/four-in-one",
|
"fio": "nodemon -r esm examples/four-in-one",
|
||||||
"dy": "node -r esm examples/dynamic",
|
"dy": "node -r esm examples/dynamic",
|
||||||
"web": "UCI_DEV=true nodemon -r esm examples/web",
|
"web": "UCI_DEV=true nodemon -r esm examples/web",
|
||||||
"mqtt": "node -r esm examples/mqtt",
|
"mqtt": "nodemon -r esm examples/mqtt",
|
||||||
"testw": "mocha -r esm test/*.test.mjs --watch --recurse --watch-extensions mjs",
|
"testw": "mocha -r esm test/*.test.mjs --watch --recurse --watch-extensions mjs",
|
||||||
"test": "mocha -r esm test/*.test.mjs",
|
"test": "mocha -r esm test/*.test.mjs",
|
||||||
"testci": "istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -R spec --recursive && codecov || true"
|
"testci": "istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -R spec --recursive && codecov || true"
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@uci-utils/bind-funcs": "^0.2.3",
|
"@uci-utils/bind-funcs": "^0.2.3",
|
||||||
"@uci-utils/logger": "0.0.13",
|
"@uci-utils/logger": "^0.0.14",
|
||||||
"@uci/mqtt": "^0.1.9",
|
"@uci/mqtt": "^0.1.11",
|
||||||
"@uci/socket": "^0.2.10",
|
"@uci/socket": "^0.2.12",
|
||||||
"@uci/websocket": "^0.3.5",
|
"@uci/websocket": "^0.3.6",
|
||||||
"await-to-js": "^2.1.1",
|
"await-to-js": "^2.1.1",
|
||||||
"p-settle": "^3.0.0"
|
"p-settle": "^3.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
306
src/base.js
306
src/base.js
|
@ -20,7 +20,7 @@ import EventEmitter from 'events'
|
||||||
import pSettle from 'p-settle'
|
import pSettle from 'p-settle'
|
||||||
|
|
||||||
// Internal dependencies
|
// Internal dependencies
|
||||||
import { processor, commands, namespaces } from './processing'
|
import { processor, defaultCmds, namespaces } from './processing'
|
||||||
|
|
||||||
// Useful Constants
|
// Useful Constants
|
||||||
const SOCKET_INFO_KEYS = ['name', 'type', 'transport']
|
const SOCKET_INFO_KEYS = ['name', 'type', 'transport']
|
||||||
|
@ -63,20 +63,23 @@ class Base extends EventEmitter {
|
||||||
this.id = opts.id || opts.name || 'uci-base:' + new Date().getTime()
|
this.id = opts.id || opts.name || 'uci-base:' + new Date().getTime()
|
||||||
log = logger({ name: 'base', id: this.id })
|
log = logger({ name: 'base', id: this.id })
|
||||||
this.desc = opts.desc // additional details for humans
|
this.desc = opts.desc // additional details for humans
|
||||||
this.socket = {} // holds all the various communication sockets
|
this._socket = {} // holds all the various communication sockets
|
||||||
this._started = false // flag to know when instance has been initialized
|
this._started = false // flag to know when instance has been initialized
|
||||||
this._processors = { _default: processor }
|
this._processors = { _default: processor }
|
||||||
this._defaultCmds = commands
|
// _c and _s are the default namespaces
|
||||||
this._namespaces = namespaces
|
this._namespaces = namespaces
|
||||||
|
this._c = defaultCmds.c
|
||||||
|
this._s = defaultCmds.s
|
||||||
if (opts.useRootNS) {
|
if (opts.useRootNS) {
|
||||||
// add root of instance to checking for command functions - not recommended!
|
// add root of instance to checking for command functions - not recommended!
|
||||||
this._namespaces.s.splice(-1, 0, null)
|
this._namespaces.s.splice(-1, 0, null)
|
||||||
this._namespaces.c.splice(-1, 0, null)
|
this._namespaces.c.splice(-1, 0, null)
|
||||||
}
|
}
|
||||||
|
// method that will bind a whole object tree of functions
|
||||||
this.bindFuncs = bindFuncs
|
this.bindFuncs = bindFuncs
|
||||||
// predefined sockets:
|
// predefined sockets:
|
||||||
// comma delimited list of this form '<name>#<c/p/s>><n=np/t=tcp/m=mqtt/w=web>'
|
// comma delimited list of this form '<name>#<c/p/s>><n=np/t=tcp/m=mqtt/w=web>'
|
||||||
this.socket = {}
|
this._socket = {}
|
||||||
if (opts.sockets) {
|
if (opts.sockets) {
|
||||||
opts.sockets.split(/[,|\s]+/).forEach(socketStr => {
|
opts.sockets.split(/[,|\s]+/).forEach(socketStr => {
|
||||||
let socket = {}
|
let socket = {}
|
||||||
|
@ -111,15 +114,12 @@ class Base extends EventEmitter {
|
||||||
async init() {
|
async init() {
|
||||||
let sockets = []
|
let sockets = []
|
||||||
let initSockets = []
|
let initSockets = []
|
||||||
for (let name of Object.keys(this.socket)) {
|
for (let name of Object.keys(this._socket)) {
|
||||||
initSockets.push(this._initSocket(name))
|
initSockets.push(this._initSocket(name))
|
||||||
sockets.push(name)
|
sockets.push(name)
|
||||||
}
|
}
|
||||||
return pSettle(initSockets).then(res => {
|
return pSettle(initSockets).then(res => {
|
||||||
log.info(
|
log.debug({ sockets: res, method:'init', line:122, msg:'response from intializing sockets via instance options'})
|
||||||
{ sockets: res },
|
|
||||||
'response from intializing sockets via instance options'
|
|
||||||
)
|
|
||||||
let err = []
|
let err = []
|
||||||
res.forEach((p, index) => {
|
res.forEach((p, index) => {
|
||||||
if (p.isRejected) {
|
if (p.isRejected) {
|
||||||
|
@ -144,36 +144,32 @@ class Base extends EventEmitter {
|
||||||
* @returns {string} Description
|
* @returns {string} Description
|
||||||
*/
|
*/
|
||||||
async addSocket(name, type = 'c', transport = 'n', options = {}) {
|
async addSocket(name, type = 'c', transport = 'n', options = {}) {
|
||||||
log.info(
|
log.debug({ socketName: name, type: type, tranport: transport, options: options, method:'addSocket', line:147, msg:`adding socket ${name}`})
|
||||||
{ socketName: name, type: type, tranport: transport, options: options },
|
|
||||||
`adding socket ${name}`
|
|
||||||
)
|
|
||||||
options.id = this.id + ':' + name
|
options.id = this.id + ':' + name
|
||||||
switch (transport) {
|
switch (transport) {
|
||||||
case 'n':
|
case 'n':
|
||||||
options.path = options.path || true
|
options.path = options.path || true
|
||||||
// falls through
|
// falls through
|
||||||
case 't':
|
case 't':
|
||||||
this.socket[name] = new Socket[TRANSLATE[type]](options)
|
this._socket[name] = new Socket[TRANSLATE[type]](options)
|
||||||
break
|
break
|
||||||
case 'm':
|
case 'm':
|
||||||
if (type === 'p') type = 'c'
|
if (type === 'p') type = 'c'
|
||||||
options.connect = options.connect || {}
|
options.connect = options.connect || {}
|
||||||
|
if (options.host) options.connect.host = options.host
|
||||||
|
if (options.port) options.connect.port = options.port
|
||||||
options.connect.connectTimeout = options.connect.connectTimeout || 5000
|
options.connect.connectTimeout = options.connect.connectTimeout || 5000
|
||||||
this.socket[name] = new MQTT(options)
|
this._socket[name] = new MQTT(options)
|
||||||
break
|
break
|
||||||
case 'w':
|
case 'w':
|
||||||
if (type === 's') this.socket[name] = new WebSocket(options)
|
if (type === 's') this._socket[name] = new WebSocket(options)
|
||||||
else
|
else
|
||||||
log.warn(
|
log.warn({ name: name, type: type, transport: transport, method:'addSocket', line:167, msg:'Web socket not created Consumer/Client Web Socket not supported'})
|
||||||
{ name: name, type: type, transport: transport },
|
|
||||||
'Web socket not created Consumer/Client Web Socket not supported'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
this.socket[name].name = name
|
this._socket[name].name = name
|
||||||
this.socket[name].type = type
|
this._socket[name].type = type
|
||||||
this.socket[name].transport = transport
|
this._socket[name].transport = transport
|
||||||
this.socket[name]._packetProcess = this._packetProcess.bind(this, name)
|
this._socket[name]._packetProcess = this._packetProcess.bind(this, name)
|
||||||
if (this._started) return await this._initSocket(name)
|
if (this._started) return await this._initSocket(name)
|
||||||
else return `socket ${name} added`
|
else return `socket ${name} added`
|
||||||
}
|
}
|
||||||
|
@ -186,13 +182,19 @@ class Base extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
async removeSocket(name) {
|
async removeSocket(name) {
|
||||||
// NOTE: uci consumers have .end renamed as .close to match socket method for convenience
|
// NOTE: uci consumers have .end renamed as .close to match socket method for convenience
|
||||||
let [err] = await to(this.socket[name].close())
|
let [err] = await to(this._socket[name].close())
|
||||||
let errmsg = {socket:this.socket[name].name, error:err, msg:'socket/consumer closed with errors but still removed'}
|
let errmsg = {socket:this._socket[name].name, error:err, msg:'socket/consumer closed with errors but still removed'}
|
||||||
if (err) log.warn(errmsg)
|
if (err) log.warn(errmsg)
|
||||||
delete this.socket[name]
|
delete this._socket[name]
|
||||||
return err ? errmsg : 'success'
|
return err ? errmsg : 'success'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getSocket(name) {
|
||||||
|
if (name) return this._socket[name]
|
||||||
|
else return this._socket
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send - Description
|
* send - Description
|
||||||
*
|
*
|
||||||
|
@ -205,43 +207,53 @@ class Base extends EventEmitter {
|
||||||
if (typeof name !== 'string') {
|
if (typeof name !== 'string') {
|
||||||
packet = name
|
packet = name
|
||||||
let sends = []
|
let sends = []
|
||||||
for (let name of Object.keys(this.socket)) {
|
for (let name of Object.keys(this._socket)) {
|
||||||
if (this.socket[name].type === 'c') {
|
if (this._socket[name].type === 'c') {
|
||||||
sends.push(this.socket[name].send.bind(this.socket[name]))
|
let hookedPacket = {}
|
||||||
|
hookedPacket = this._socket[name].beforeSend ? await this._socket[name].beforeSend.call(this,Object.assign({},packet)) : packet
|
||||||
|
log.debug({msg:'after possible hook packet to send', name:name, packet:hookedPacket, method:'send', line:217})
|
||||||
|
sends.push(this._socket[name].send.bind(this._socket[name],hookedPacket))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sends.length === 1) return await sends[0](packet)
|
if (sends.length === 1) return await sends[0]()
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
sends.map(send => {
|
sends.map(send => {
|
||||||
return send(packet)
|
return send()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (this.socket[name]) return await this.socket[name].send(packet)
|
if (this._socket[name]) {
|
||||||
|
if (this._socket[name].beforeSend) packet = await this._socket[name].beforeSend.call(this,packet)
|
||||||
|
log.debug({msg:'single socket hooked packet to send', name:name, packet:packet, method:'send', line:230})
|
||||||
|
return await this._socket[name].send(packet)
|
||||||
|
}
|
||||||
else return { error: `no consumer socket of name ${name}` }
|
else return { error: `no consumer socket of name ${name}` }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async push(packet) {
|
async push(packet) {
|
||||||
let broadcast = []
|
let broadcast = []
|
||||||
for (let name of Object.keys(this.socket)) {
|
for (let name of Object.keys(this._socket)) {
|
||||||
if (this.socket[name].type === 's') {
|
if (this._socket[name].type === 's') {
|
||||||
broadcast.push(this.socket[name].push.bind(this.socket[name]))
|
let hookedPacket = {}
|
||||||
|
hookedPacket = this._socket[name].beforeSend ? await this._socket[name].beforeSend.call(this,Object.assign({},packet),true) : packet
|
||||||
|
log.debug({msg:'hooked packet to push', name:name, packet:hookedPacket, method:'push', line:243})
|
||||||
|
broadcast.push(this._socket[name].push.bind(this._socket[name],hookedPacket))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
broadcast.map(push => {
|
broadcast.map(push => {
|
||||||
return push(packet)
|
return push()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTransport(packet, transport) {
|
async sendTransport(packet, transport) {
|
||||||
let sends = []
|
let sends = []
|
||||||
for (let name of Object.keys(this.socket)) {
|
for (let name of Object.keys(this._socket)) {
|
||||||
if (this.socket[name].type === 'c') {
|
if (this._socket[name].type === 'c') {
|
||||||
if (this.socket[name].transport === transport) {
|
if (this._socket[name].transport === transport) {
|
||||||
sends.push(this.socket[name].send.bind(this.socket[name]))
|
sends.push(this._socket[name].send.bind(this._socket[name]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +265,7 @@ class Base extends EventEmitter {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// async sendMQTT(topic, packet) {return this.socket.mqtt.send(topic, packet)}
|
// async sendMQTT(topic, packet) {return this._socket.mqtt.send(topic, packet)}
|
||||||
async sendTCP(packet) {
|
async sendTCP(packet) {
|
||||||
return this.sendTransport(packet, 't')
|
return this.sendTransport(packet, 't')
|
||||||
}
|
}
|
||||||
|
@ -261,9 +273,14 @@ class Base extends EventEmitter {
|
||||||
return this.sendTransport(packet, 'n')
|
return this.sendTransport(packet, 'n')
|
||||||
}
|
}
|
||||||
|
|
||||||
getSocket(name) {
|
|
||||||
return this.socket[name]
|
socketsListen(event,fn) {
|
||||||
|
this._eventListen('s',event,fn)
|
||||||
}
|
}
|
||||||
|
consumersListen(event,fn) {
|
||||||
|
this._eventListen('c',event,fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getPacketByName(name, packets) {
|
getPacketByName(name, packets) {
|
||||||
if (!packets.length) packets = [packets]
|
if (!packets.length) packets = [packets]
|
||||||
|
@ -277,77 +294,84 @@ class Base extends EventEmitter {
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
socketsListen(event,fn) {
|
// add set of functions to class prop/space and then register with this
|
||||||
this._eventListen('s',event,fn)
|
|
||||||
}
|
|
||||||
consumersListen(event,fn) {
|
|
||||||
this._eventListen('c',event,fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO confirm Object.assign will be ok as it is not a deep copy
|
|
||||||
amendConsumerProcessing(funcs, trans) {
|
|
||||||
if (trans) {
|
|
||||||
if (!this._defaultCmds.c[trans]) this._defaultCmds.c[trans] = {}
|
|
||||||
Object.assign(this._defaultCmds.c[trans], funcs)
|
|
||||||
}
|
|
||||||
Object.assign(this._defaultCmds.c, funcs)
|
|
||||||
}
|
|
||||||
|
|
||||||
amendSocketProcessing(funcs, trans) {
|
|
||||||
if (trans) {
|
|
||||||
if (!this._defaultCmds.s[trans]) this._defaultCmds.s[trans] = {}
|
|
||||||
Object.assign(this._defaultCmds.s[trans], funcs)
|
|
||||||
}
|
|
||||||
Object.assign(this._defaultCmds.s, funcs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// use s: and c: keys TODO need to change this
|
|
||||||
addNamedProcessing(name, funcs, type) {
|
|
||||||
if (type) {
|
|
||||||
if (!this._cmds[name][type]) this._cmds[name][type] = {}
|
|
||||||
Object.assign(this._cmds[name][type], funcs)
|
|
||||||
} else {
|
|
||||||
if (!this._cmds[name]) this._cmds[name] = {}
|
|
||||||
Object.assign(this._cmds[name], funcs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// func should take and return a packet
|
|
||||||
// beforeSendHook (func,type,transport){} // TODO
|
|
||||||
// afterReceiveHook(func,type,transport){} // TODO
|
|
||||||
// afterProcessHook(func,type,transport){} // TODO
|
|
||||||
|
|
||||||
// here you can add namespaced functions for packet commands
|
|
||||||
|
|
||||||
//======================================================================
|
|
||||||
// TODO next several need to be redone now that namespace commands work
|
|
||||||
consumersProcessor(func) {
|
|
||||||
for (let name of Object.keys(this.socket)) {
|
|
||||||
if (this.socket[name].type === 'c') {
|
|
||||||
this.socketNameProcessor(func, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
socketsProcessor(func) {
|
|
||||||
for (let name of Object.keys(this.socket)) {
|
|
||||||
if (this.socket[name].type === 's') {
|
|
||||||
this.socketNamedProcessor(func, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
socketNameProcessor(func, socket_name) {
|
|
||||||
socket_name = socket_name || '_default'
|
|
||||||
this._processors[socket_name]._process = func
|
|
||||||
}
|
|
||||||
|
|
||||||
addNamespace(space, type, trans) {
|
addNamespace(space, type, trans) {
|
||||||
if (trans) return this._namespaces[type + trans].unshift(space)
|
if (trans) return this._namespaces[type + trans].unshift(space)
|
||||||
else return this._namespaces[type].unshift(space)
|
else return this._namespaces[type].unshift(space)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO confirm Object.assign will be ok as it is not a deep copy
|
||||||
|
// one off add a command function or two to basic namespaces which is called before default
|
||||||
|
amendConsumerCommands(funcs, trans) {
|
||||||
|
if (trans) {
|
||||||
|
if (!this._c[trans]) this._c[trans] = {}
|
||||||
|
Object.assign(this._c[trans], funcs)
|
||||||
|
}
|
||||||
|
Object.assign(this._c, funcs)
|
||||||
|
}
|
||||||
|
amendSocketCommands(funcs, trans) {
|
||||||
|
if (trans) {
|
||||||
|
if (!this._s[trans]) this._s[trans] = {}
|
||||||
|
Object.assign(this._s[trans], funcs)
|
||||||
|
}
|
||||||
|
Object.assign(this._s, funcs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func should take and return a packet. if type
|
||||||
|
beforeSendHook(func,opts) {
|
||||||
|
this._packetHook('beforeSend', func,opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeProcessHook(func,opts) {
|
||||||
|
this._packetHook('beforeProcess', func,opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
afterProcessHook(func,opts) {
|
||||||
|
this._packetHook('afterProcess', func,opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
_packetHook(hook,func,opts) {
|
||||||
|
log.debug({msg:'hooking a socket(s)', method:'_packetHook', line:334, hook:hook, function:func, options:opts})
|
||||||
|
let {name,type,trans,all} = opts
|
||||||
|
if (name) this._socket[name][hook] = func
|
||||||
|
else {
|
||||||
|
log.debug({msg:'sockets available to hook', method:'_packetHook', line:338, sockets: Object.keys(this._socket)})
|
||||||
|
for (let name of Object.keys(this._socket)) {
|
||||||
|
if (this._socket[name].type === type) this._socket[name][hook] = func
|
||||||
|
if (this._socket[name].transport === trans) this._socket[name][hook] = func
|
||||||
|
if (all) this._socket[name][hook] = func
|
||||||
|
if (this._socket[name][hook]) log.debug({msg:'hooked socket', method:'_packetHook', line:343, name:name, type:this._socket[name].type, trans:this._socket[name].transport})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Big Hammer - use only if necessary - default with hooks should suffice
|
||||||
|
// these three will pre-empt default processor to be called in ._packetProcess
|
||||||
|
|
||||||
|
// add and override default processor for ALL consumers, i.e. packets returning form a send or arrived from a push
|
||||||
|
consumersProcessor(func) {
|
||||||
|
for (let name of Object.keys(this._socket)) {
|
||||||
|
if (this._socket[name].type === 'c') {
|
||||||
|
this.altProcessor(func, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add and override default processor for ALL sockets, i.e. packets coming in from consumer send
|
||||||
|
socketsProcessor(func) {
|
||||||
|
for (let name of Object.keys(this._socket)) {
|
||||||
|
if (this._socket[name].type === 's') {
|
||||||
|
this.altProcessor(func, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add and override a processor for a particular socket/consumer to list of processors
|
||||||
|
// if no socket name given it will replace the default processor in _processors from processing.js
|
||||||
|
altProcessor(func, socket_name) {
|
||||||
|
socket_name = socket_name || '_default'
|
||||||
|
this._processors[socket_name] = func
|
||||||
|
}
|
||||||
|
|
||||||
//======================================================
|
//======================================================
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -356,38 +380,58 @@ class Base extends EventEmitter {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********default packet processor for all sockets
|
||||||
|
* this can be hooked or replaced all together
|
||||||
|
*/
|
||||||
|
|
||||||
|
async _packetProcess(socket_name, packet) {
|
||||||
|
log.debug({ socket:socket_name, packet:packet, method:'_packetProcess', line:393, msg:'processing incoming packet'})
|
||||||
|
// the processor can be set via the incoming packet
|
||||||
|
// otherwise if one is set on the socket or the default found in processing.js
|
||||||
|
// TODO?? Try all each available packet processors in some order if fails try next one before trying the default
|
||||||
|
if (this._socket[socket_name].beforeProcess) packet = await this._socket[socket_name].beforeProcess.call(this,packet)
|
||||||
|
if (packet.error) return packet // hook invalidated the packet abort further processing
|
||||||
|
let processor = packet._processor || this._processors[socket_name] ? socket_name : '_default'
|
||||||
|
let res = await this._processors[processor].call(this,packet,socket_name)
|
||||||
|
if (this._socket[socket_name].afterProcess) res = await this._socket[socket_name].afterProcess.call(this,res)
|
||||||
|
log.debug({ socket:socket_name, response:res, msg:'processed packet ready for return'})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
async _initSocket(name) {
|
async _initSocket(name) {
|
||||||
let socket = this.socket[name]
|
let socket = this._socket[name]
|
||||||
let init = {}
|
let init = {}
|
||||||
if (this.socket[name].type === 's' && this.socket[name].transport !== 'm') {
|
if (this._socket[name].type === 's' && this._socket[name].transport !== 'm') {
|
||||||
init = socket.create
|
init = socket.create
|
||||||
} else {
|
} else {
|
||||||
init = socket.connect
|
init = socket.connect
|
||||||
}
|
}
|
||||||
log.info(`initializing socket ${name}, ${socket.type}, ${socket.transport}`)
|
log.debug(`initializing socket ${name}, ${socket.type}, ${socket.transport}`)
|
||||||
if (this._started)
|
if (this._started)
|
||||||
return `socket ${name} added and initialzed, ${await init()}`
|
return `socket ${name} added and initialzed, ${await init()}`
|
||||||
else return init()
|
else return init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all sockets are emitters. Adds a listener to all sockets of a type with given event.
|
||||||
|
// now sockets can emit locally processed events
|
||||||
_eventListen(type,event,fn) {
|
_eventListen(type,event,fn) {
|
||||||
for (let name of Object.keys(this.socket)) {
|
for (let name of Object.keys(this._socket)) {
|
||||||
if (this.socket[name].type === type) {
|
if (this._socket[name].type === type) {
|
||||||
if (fn==='stop') this.socket[name].removeAllListeners(event)
|
if (fn==='stop') this._socket[name].removeAllListeners(event)
|
||||||
else {
|
else {
|
||||||
console.log('adding listener',name,type,event,fn )
|
log.debug({socket:name, type:type, event:event, msg:'adding listener to socket'})
|
||||||
console.log(this.socket[name].name)
|
this._socket[name].on(event, fn)
|
||||||
this.socket[name].on(event, fn)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_transport(name) {
|
_transport(name) {
|
||||||
return this.socket[name].transport
|
return this._socket[name].transport
|
||||||
} //getter for socket transport
|
} //getter for socket transport
|
||||||
_type(name) {
|
_type(name) {
|
||||||
return this.socket[name].type
|
return this._socket[name].type
|
||||||
} //getter for socket type
|
} //getter for socket type
|
||||||
|
|
||||||
_getTransportNamespaces(socket) {
|
_getTransportNamespaces(socket) {
|
||||||
|
@ -406,19 +450,18 @@ class Base extends EventEmitter {
|
||||||
|
|
||||||
// takes command and returns corresponding function in a hash
|
// takes command and returns corresponding function in a hash
|
||||||
_getCmdFunc(cmd, obj) {
|
_getCmdFunc(cmd, obj) {
|
||||||
// console.log('obj',obj)
|
|
||||||
if (typeof cmd === 'string') {
|
if (typeof cmd === 'string') {
|
||||||
if (!obj) obj = this
|
if (!obj) obj = this
|
||||||
cmd = cmd.split(/[.:/]+/)
|
cmd = cmd.split(/[.:/]+/)
|
||||||
// console.log('===================',cmd)
|
|
||||||
}
|
}
|
||||||
var prop = cmd.shift()
|
var prop = cmd.shift()
|
||||||
if (cmd.length === 0) return obj[prop]
|
if (cmd.length === 0) return obj[prop]
|
||||||
if (!obj[prop]) return null
|
if (!obj[prop]) return null
|
||||||
// console.log(cmd.length,cmd,prop, obj[prop])
|
log.debug({length:cmd.length,cmd:cmd, prop:prop, objprop:obj[prop], method:'_getCmdFunc', msg:'command to corresponding function in a hash'})
|
||||||
return this._getCmdFunc(cmd, obj[prop])
|
return this._getCmdFunc(cmd, obj[prop])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// primary function to find a function to call based on packet cmd
|
||||||
async _callCmdFunc(packet, socket) {
|
async _callCmdFunc(packet, socket) {
|
||||||
let cmd_func = this._getCmdFuncNamespace(
|
let cmd_func = this._getCmdFuncNamespace(
|
||||||
packet.cmd,
|
packet.cmd,
|
||||||
|
@ -433,22 +476,7 @@ class Base extends EventEmitter {
|
||||||
return 'failed'
|
return 'failed'
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
**********default packet processor for all sockets
|
|
||||||
*/
|
|
||||||
|
|
||||||
async _packetProcess(socket_name, packet) {
|
|
||||||
|
|
||||||
// TODO Try all added packet processors then defualt before sending back
|
|
||||||
// console.log(socket_name,packet)
|
|
||||||
let processor =
|
|
||||||
packet._processor || this._processors[socket_name] || '_default'
|
|
||||||
return await this._processors[processor].bind(this)(
|
|
||||||
packet,
|
|
||||||
socket_name,
|
|
||||||
this._processors[processor]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} // end Base Class
|
} // end Base Class
|
||||||
|
|
||||||
export default Base
|
export default Base
|
||||||
|
|
|
@ -7,44 +7,47 @@ let log = logger({ package: 'base',file:'processing.js'})
|
||||||
// processing errors that are caught should be sent back to consumer in packets with :error property
|
// processing errors that are caught should be sent back to consumer in packets with :error property
|
||||||
// but they might also throw local errors/execptions so they should bubble up here and get caught and logged
|
// but they might also throw local errors/execptions so they should bubble up here and get caught and logged
|
||||||
// messaging errors on socket will not be fatal to the entire socket server
|
// messaging errors on socket will not be fatal to the entire socket server
|
||||||
|
|
||||||
|
// common processor, will call based on type s or c the ones below
|
||||||
const processor = async function (packet,socket) {
|
const processor = async function (packet,socket) {
|
||||||
let [err,res] = await to(_process[this.getSocket(socket).type].bind(this)(packet,socket))
|
let [err,res] = await to(_process[this.getSocket(socket).type].bind(this)(packet,socket))
|
||||||
if (err) {
|
if (err) {
|
||||||
let error = {error:err, socket:socket, packet:packet, msg:'some possibly unhandled badness happened during packet processing'}
|
let error = {error:err, socket:socket, packet:packet, function:'processor', line: 15, msg:'some possibly unhandled badness happened during packet processing'}
|
||||||
log.warn(error)
|
log.error(error)
|
||||||
if (process.env.UCI_SHOW_UNHANDLED==='true') console.log(error)
|
if (process.env.UCI_SHOW_UNHANDLED==='true') console.log(error)
|
||||||
}
|
}
|
||||||
else return res
|
else return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export { processor, commands, namespaces }
|
export { processor, defaultCmds, namespaces }
|
||||||
|
|
||||||
|
// default processors for socket/server and consumer/client
|
||||||
const _process = {
|
const _process = {
|
||||||
s: async function (packet,socket) {
|
s: async function (packet,socket) {
|
||||||
// console.log('in default socket processor',packet.cmd)
|
if (!packet.cmd) return {error: 'no command (cmd:) in packet for socket', packet: packet }
|
||||||
if (!packet.cmd) return {error: '[socket] no command in packet', packet: packet }
|
// this call will search the namespace and envoke a function and return a repsonse packet
|
||||||
let response = await this._callCmdFunc(packet,socket); if(response!=='failed') return response
|
let response = await this._callCmdFunc(packet,socket); if(response!=='failed') return response
|
||||||
return {error: 'no socket processing function supplied for command', packet: packet }
|
return {error: 'no socket processing function supplied for command', packet: packet }
|
||||||
},
|
},
|
||||||
|
|
||||||
c: async function (packet,socket) {
|
c: async function (packet,socket) {
|
||||||
|
|
||||||
// console.log('in default consumer processor',packet.cmd)
|
// the the end of life for a consumer packet that has been sent and returned or a packet that was pushed.
|
||||||
if (packet.error) return await this._defaultCmds.c.error(packet)
|
if (packet.error) return await this._c.error(packet)
|
||||||
if (packet.cmd) {
|
if (packet.cmd) {
|
||||||
let response = await this._callCmdFunc(packet,socket); if(response!=='failed') return response
|
let response = await this._callCmdFunc(packet,socket); if(response!=='failed') return response
|
||||||
packet = {error:'no consumer processing function supplied for command',packet:packet}
|
packet = {error:'no consumer reply processing function supplied for command',packet:packet}
|
||||||
this._defaultCmds.c.error(packet)
|
this._c.error(packet)
|
||||||
} else {
|
} else {
|
||||||
packet = {error:'[consumer] no command in packet',packet:packet}
|
packet = {error:'[consumer] no command in reply packet',packet:packet}
|
||||||
return await this._defaultCmds.c.error(packet)
|
return await this._c.error(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const namespaces = {
|
const namespaces = {
|
||||||
s: ['s','_defaultCmds.s'],
|
s: ['_s'],
|
||||||
c: ['c','_defaultCmds.c'],
|
c: ['_c'],
|
||||||
cn: ['cn'],
|
cn: ['cn'],
|
||||||
ct: ['ct'],
|
ct: ['ct'],
|
||||||
sn: ['sn'],
|
sn: ['sn'],
|
||||||
|
@ -60,7 +63,7 @@ const namespaces = {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const commands ={
|
const defaultCmds ={
|
||||||
s:{
|
s:{
|
||||||
echo: async packet => {
|
echo: async packet => {
|
||||||
packet.processed = true
|
packet.processed = true
|
||||||
|
@ -75,12 +78,10 @@ const commands ={
|
||||||
},
|
},
|
||||||
c:{
|
c:{
|
||||||
error: function (packet) {
|
error: function (packet) {
|
||||||
// TODO log and make this show only on env debug
|
if (process.env.UCI_ENV==='dev') log.error({error:packet.error, packet:packet, msg:'==========Consumer Sent Packet returned with ERROR ========='})
|
||||||
log.warn({error:packet.error, packet:packet, msg:'==========Packet ERROR [consumer]========='})
|
|
||||||
},
|
},
|
||||||
reply: function(packet) {
|
reply: function(packet) {
|
||||||
// TODO log and make this show only on env debug
|
if (process.env.UCI_ENV==='dev') log.debug({packet:packet, msg:'====Packet returned from socket - debug default reply logger==='})
|
||||||
log.debug({packet:packet, msg:'====Packet returned from socket - debug reply==='})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue