0.1.29 add default return command for socket/servers
add generic client and ack sockect server examplesmaster
parent
61df3593b1
commit
23ea81c9d9
|
@ -10,8 +10,11 @@ module.exports = {
|
||||||
"mocha": true
|
"mocha": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2017
|
"ecmaVersion": 2017,
|
||||||
,"sourceType": "module"
|
"sourceType": "module",
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"experimentalObjectRestSpread": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"rules": {
|
"rules": {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
simple generic server sending an ack
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import Base from '../src/base'
|
||||||
|
|
||||||
|
let opts={id:'simple-ack-server-server'}
|
||||||
|
|
||||||
|
;
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
let server = new Base(opts)
|
||||||
|
let opts2 = Object.assign({},opts)
|
||||||
|
opts.port = process.env.UCI_PORT
|
||||||
|
server.addSocket('server:tcp','s','t',opts)
|
||||||
|
opts2.path = process.env.UCI_PATH || true
|
||||||
|
server.addSocket('server:named-pipe','s','n',opts2)
|
||||||
|
|
||||||
|
server.on('status',err => {
|
||||||
|
console.log('STATUS EMITTED\n', err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// example return processor using a namespace, will take precidence over default and root namespaces
|
||||||
|
server.cmds = { ack: (packet) => {
|
||||||
|
packet.ack = true
|
||||||
|
packet.cmd='reply'
|
||||||
|
packet.msg ='ack via custom ack function'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.addNamespace('cmds') // comment this out to process via default ack
|
||||||
|
|
||||||
|
let res = await server.init()
|
||||||
|
if (res.error) {
|
||||||
|
console.log('errors during init')
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('sockets listening for an ack')
|
||||||
|
|
||||||
|
})().catch(err => {
|
||||||
|
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
})
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
simple generic client sending an ack
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import Base from '../src/base'
|
||||||
|
|
||||||
|
const delay = time => new Promise(res=>setTimeout(()=>res(),time))
|
||||||
|
|
||||||
|
let opts={id:'simple-client', useRootNS:true}
|
||||||
|
// if nothing set will be localhost:8080
|
||||||
|
if (process.env.UCI_HOST || process.env.UCI_PORT || !process.env.UCI_PATH ) {
|
||||||
|
opts.host = process.env.UCI_HOST
|
||||||
|
opts.port = process.env.UCI_PORT
|
||||||
|
} else {
|
||||||
|
opts.path = process.env.UCI_PATH==='true' ? true : process.env.UCI_PATH
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
let client = new Base(opts)
|
||||||
|
|
||||||
|
client.on('status',ev => {
|
||||||
|
switch (ev.level) {
|
||||||
|
case 'warning':
|
||||||
|
case 'error':
|
||||||
|
case 'fatal':
|
||||||
|
console.log(ev.level.toUpperCase(),'\n',ev)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function log (packet) {
|
||||||
|
if (packet.ack) {
|
||||||
|
console.log('socket acknowledged')
|
||||||
|
let {_header, cmd, ...rest} = packet
|
||||||
|
console.log('reply:',rest)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('process at socket did not acknowledge')
|
||||||
|
console.log(packet._header)
|
||||||
|
}
|
||||||
|
console.log('------ END REPLY------')
|
||||||
|
}
|
||||||
|
|
||||||
|
// example return processor using a namespace, will take precidence over default and root namespaces
|
||||||
|
client.cmds = { reply: (packet) => {
|
||||||
|
console.log('------REPLY--via cmds namespace----')
|
||||||
|
log(packet) }
|
||||||
|
}
|
||||||
|
client.addNamespace('cmds','c') // comment this out to process via root namespace
|
||||||
|
|
||||||
|
// alt example return process function making us of root namspace, useRootNS must be set true in options to do this
|
||||||
|
client.reply = function (packet) {
|
||||||
|
console.log('------REPLY--via root namespace----')
|
||||||
|
log(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.addSocket(`client:${opts.path ? 'named-pipe':'tcp'}`,'c',opts.path?'n':'t',opts)
|
||||||
|
|
||||||
|
let res = await client.init()
|
||||||
|
if (res.error) {
|
||||||
|
console.log('errors during init')
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('connected proceed with ack')
|
||||||
|
await client.send({cmd:'ack'})
|
||||||
|
delay(2000)
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
|
||||||
|
})().catch(err => {
|
||||||
|
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
})
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"ignoreRoot": [".git","examples/ws-fio-client"],
|
"ignoreRoot": [".git"],
|
||||||
"watch": ["node_modules/@uci/","node_modules/@uci-utils/","src/","index.js","examples/four-in-on.js","examples/four-in-on.js","test/"]
|
"watch": ["node_modules/@uci/","node_modules/@uci-utils/","src/","index.js","examples","test/"],
|
||||||
|
"ignore":["examples/ws-fio-client"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "@uci/base",
|
"name": "@uci/base",
|
||||||
"version": "0.1.28",
|
"version": "0.1.29",
|
||||||
"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": {
|
||||||
"fiod": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/four-in-one",
|
"fiod": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/four-in-one",
|
||||||
"fio": "nodemon -r esm examples/four-in-one",
|
"fio": "nodemon -r esm examples/four-in-one",
|
||||||
|
"ack": "node -r esm examples/ack || true",
|
||||||
|
"ack:dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/ack || true",
|
||||||
|
"client": "node -r esm examples/client || true",
|
||||||
|
"client:dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/client || true",
|
||||||
"test": "UCI_ENV=dev nodemon -r esm --preserve-symlinks test/test",
|
"test": "UCI_ENV=dev nodemon -r esm --preserve-symlinks test/test",
|
||||||
"mtestw": "mocha -r esm test/*.test.mjs --watch --recurse ",
|
"mtestw": "mocha -r esm test/*.test.mjs --watch --recurse ",
|
||||||
"mtest": "mocha -r esm test/*.test.mjs"
|
"mtest": "mocha -r esm test/*.test.mjs"
|
||||||
|
@ -36,7 +40,7 @@
|
||||||
"@uci-utils/bind-funcs": "^0.2.4",
|
"@uci-utils/bind-funcs": "^0.2.4",
|
||||||
"@uci-utils/logger": "^0.0.15",
|
"@uci-utils/logger": "^0.0.15",
|
||||||
"@uci/mqtt": "^0.1.13",
|
"@uci/mqtt": "^0.1.13",
|
||||||
"@uci/socket": "^0.2.20",
|
"@uci/socket": "^0.2.21",
|
||||||
"@uci/websocket": "^0.3.9",
|
"@uci/websocket": "^0.3.9",
|
||||||
"await-to-js": "^2.1.1",
|
"await-to-js": "^2.1.1",
|
||||||
"p-reflect": "^2.1.0",
|
"p-reflect": "^2.1.0",
|
||||||
|
|
34
src/base.js
34
src/base.js
|
@ -65,6 +65,10 @@ class Base extends EventEmitter {
|
||||||
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
|
||||||
|
// these two if passed will get applied to all consumer sockets, otherwise socket defaults will be used
|
||||||
|
this.initTimeout = opts.initTimeout
|
||||||
|
this.retryWait = opts.retryWait
|
||||||
|
this.defaultReturnCmd = opts.defaultReturnCmd
|
||||||
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 }
|
||||||
// _c and _s are the default namespaces
|
// _c and _s are the default namespaces
|
||||||
|
@ -122,7 +126,7 @@ class Base extends EventEmitter {
|
||||||
const value = await socket.init()
|
const value = await socket.init()
|
||||||
results[socket.name] = value
|
results[socket.name] = value
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.emit('error',{msg:'socket init error',error:error})// emit an error here, remove socket
|
this.emit('status',{level:'fatal', msg:'socket init error',error:error})// emit an error here, remove socket
|
||||||
let res = await this.removeSocket(socket.name)
|
let res = await this.removeSocket(socket.name)
|
||||||
errors[socket.name]={error:error, remove:res}
|
errors[socket.name]={error:error, remove:res}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +155,9 @@ class Base extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
async addSocket(name, type = 'c', transport = 'n', options = {}) {
|
async addSocket(name, type = 'c', transport = 'n', options = {}) {
|
||||||
log.debug({ socketName: name, type: type, tranport: transport, options: options, method:'addSocket', line:147, msg:`adding socket ${name}`})
|
log.debug({ socketName: name, type: type, tranport: transport, options: options, method:'addSocket', line:147, msg:`adding socket ${name}`})
|
||||||
options.id = this.id + ':' + name
|
options.id = options.id || this.id + ':' + name
|
||||||
|
if (type==='c') options = Object.assign({initTimeout:this.initTimeout, retryWait:this.retryWait},options)
|
||||||
|
if (type==='s') options = Object.assign({defaultReturnCmd:this.defaultReturnCmd},options)
|
||||||
switch (transport) {
|
switch (transport) {
|
||||||
case 'n':
|
case 'n':
|
||||||
options.path = options.path || true
|
options.path = options.path || true
|
||||||
|
@ -177,18 +183,20 @@ class Base extends EventEmitter {
|
||||||
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 (type==='c') { // bubble up events from client sockets
|
// bubble up events from sockets
|
||||||
this._socket[name].on('status', ev => {
|
this._socket[name].on('status', ev => {
|
||||||
ev.socketName=name
|
ev.socketName=name
|
||||||
this.emit('status', ev)
|
this.emit('status', ev)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (type==='c') {
|
||||||
this._socket[name].on('pushed', packet => {
|
this._socket[name].on('pushed', packet => {
|
||||||
packet._header.socketName=name
|
packet._header.socketName=name
|
||||||
this.emit('pushed', packet)
|
this.emit('pushed', packet)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// do this as .then promise then addSocket doesn't need to be async before init
|
// if instance already started then init this socket now
|
||||||
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`
|
||||||
}
|
}
|
||||||
|
@ -203,10 +211,10 @@ class Base extends EventEmitter {
|
||||||
// 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 closeError
|
let closeError
|
||||||
let [err] = await to(this._socket[name].close())
|
let [err] = await to(this._socket[name].close())
|
||||||
if (err.code !== 'ERR_SERVER_NOT_RUNNING') {
|
if(err) if (err.code !== 'ERR_SERVER_NOT_RUNNING') {
|
||||||
closeError = {socket:this._socket[name].name, error:err, msg:'socket/consumer closed with errors, but removed'}
|
closeError = {socket:this._socket[name].name, error:err, msg:'socket/consumer closed with errors, but removed'}
|
||||||
}
|
}
|
||||||
this.emit('warn', {msg:`socket ${name} has been removed`, socket:this._socket[name].opts})
|
this.emit('status', {level:'warn', msg:`socket ${name} has been removed`, socket:this._socket[name].opts})
|
||||||
delete this._socket[name]
|
delete this._socket[name]
|
||||||
return closeError ? closeError : 'success'
|
return closeError ? closeError : 'success'
|
||||||
}
|
}
|
||||||
|
@ -325,7 +333,7 @@ class Base extends EventEmitter {
|
||||||
|
|
||||||
// add set of functions to class prop/space and then register with this
|
// add set of functions to class prop/space and then register with this
|
||||||
addNamespace(space, type, trans) {
|
addNamespace(space, type, trans) {
|
||||||
if (type !=='c' || type !=='s') {
|
if (type !=='c' && type !=='s') {
|
||||||
trans = type
|
trans = type
|
||||||
type = 's' }
|
type = 's' }
|
||||||
trans = this._validateTransport(trans)
|
trans = this._validateTransport(trans)
|
||||||
|
@ -431,13 +439,11 @@ class Base extends EventEmitter {
|
||||||
if (this._socket[socket_name].beforeProcess) {
|
if (this._socket[socket_name].beforeProcess) {
|
||||||
[err,res] = await to(this._socket[socket_name].beforeProcess.call(this,packet))
|
[err,res] = await to(this._socket[socket_name].beforeProcess.call(this,packet))
|
||||||
if (err) { // hook has forced an abort to processing
|
if (err) { // hook has forced an abort to processing
|
||||||
console.log('before error', packet)
|
|
||||||
packet.error = err
|
packet.error = err
|
||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
packet = res
|
packet = res
|
||||||
}
|
}
|
||||||
// if (this._socket[socket_name].beforeProcess) packet = await this._socket[socket_name].beforeProcess.call(this,packet)
|
|
||||||
// the processor can be set via the 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
|
// otherwise if one is set on the socket or the default found in processing.js
|
||||||
// TODO Try each "available" packet processor in some order if fails try next one before trying the default
|
// TODO Try each "available" packet processor in some order if fails try next one before trying the default
|
||||||
|
@ -465,7 +471,7 @@ class Base extends EventEmitter {
|
||||||
return `socket ${name} added and initialzed, ${res}`
|
return `socket ${name} added and initialzed, ${res}`
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
this.emit('error', {msg:'failed initialization', error:err, socket:socket, code:'SOCKET_INIT'})
|
this.emit('status', {level:'fatal', msg:'failed initialization', error:err, socket:socket, code:'SOCKET_INIT'})
|
||||||
return {msg:`socket ${name} failed initialization`, error:err}
|
return {msg:`socket ${name} failed initialization`, error:err}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
)
|
)
|
||||||
|
|
|
@ -33,7 +33,6 @@ const _process = {
|
||||||
},
|
},
|
||||||
|
|
||||||
c: async function (packet,socket) {
|
c: async function (packet,socket) {
|
||||||
|
|
||||||
// the the end of life for a consumer packet that has been sent and returned or a packet that was pushed.
|
// the the end of life for a consumer packet that has been sent and returned or a packet that was pushed.
|
||||||
if (packet.error) packet.cmd='error'
|
if (packet.error) packet.cmd='error'
|
||||||
if (packet.cmd) {
|
if (packet.cmd) {
|
||||||
|
@ -78,7 +77,7 @@ const defaultCmds ={
|
||||||
ack: async packet => {
|
ack: async packet => {
|
||||||
packet.cmd = 'reply'
|
packet.cmd = 'reply'
|
||||||
packet.ack = true
|
packet.ack = true
|
||||||
packet.msg = 'this is the base default ack, superceed in your extended class'
|
packet.msg = 'this is the base default ack, superceed in your instance or extended class'
|
||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue