0.1.39
processing.js add ready command to consumer for pushes emitting entire packet base.js added ready all subcriber that sends/push when ready adds ready packet to conPackets for all s socket types change observer names to include sufixes :socket, :consumer, :process, :device add method to easily create an observer of connecting consumer(s)master
parent
a6d928bf56
commit
80286a2e4f
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@uci/base",
|
"name": "@uci/base",
|
||||||
"version": "0.1.38",
|
"version": "0.1.39",
|
||||||
"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": {
|
||||||
|
|
70
src/base.js
70
src/base.js
|
@ -4,6 +4,7 @@
|
||||||
// UCI communication transport communication modules
|
// UCI communication transport communication modules
|
||||||
// TODO change to dynamic import so loads only if that socket type is requestd
|
// TODO change to dynamic import so loads only if that socket type is requestd
|
||||||
import Socket from '@uci/socket' // tcp or named pipe
|
import Socket from '@uci/socket' // tcp or named pipe
|
||||||
|
// TDDO import these socket libraries dynamically from per peerDependencies
|
||||||
import MQTT from '@uci/mqtt' // requires broker
|
import MQTT from '@uci/mqtt' // requires broker
|
||||||
import WebSocket from '@uci/websocket' // server only - client is for web browser only
|
import WebSocket from '@uci/websocket' // server only - client is for web browser only
|
||||||
// UCI helpers
|
// UCI helpers
|
||||||
|
@ -73,6 +74,8 @@ class Base extends EventEmitter {
|
||||||
this.defaultReturnCmd = opts.defaultReturnCmd
|
this.defaultReturnCmd = opts.defaultReturnCmd
|
||||||
this._cmdProcessors = { _default: cmdProcessor }
|
this._cmdProcessors = { _default: cmdProcessor }
|
||||||
this.ready = new Ready({emitter: this})
|
this.ready = new Ready({emitter: this})
|
||||||
|
// ready packet to be sent when process is "ready"
|
||||||
|
this._readyPacket = {cmd:'ready', event:`${this.name}:process`, name:this.name, id:this.id, ready:false}
|
||||||
// _c and _s are the default namespaces
|
// _c and _s are the default namespaces
|
||||||
this._namespaces =Object.assign({},namespaces)
|
this._namespaces =Object.assign({},namespaces)
|
||||||
this._c = Object.assign({},defaultCmds.c)
|
this._c = Object.assign({},defaultCmds.c)
|
||||||
|
@ -117,9 +120,19 @@ class Base extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async init(sockets) {
|
async init(sockets) {
|
||||||
// Object.getPrototypeOf(Object.getPrototypeOf(this).init.call(this,sockets))
|
|
||||||
|
// subscribe to all combination and send
|
||||||
|
this.ready.subscribe(async ready => {
|
||||||
|
this._readyPacket.ready= ready
|
||||||
|
delete (this._readyPacket.failure)
|
||||||
|
if (!ready) {
|
||||||
|
const name = this.ready.failure
|
||||||
|
this._readyPacket.failure = {name:name, details:this.ready.getObserverDetails(name)}
|
||||||
|
}
|
||||||
|
await this.send(this._readyPacket)
|
||||||
|
await this.push(this._readyPacket)
|
||||||
|
})
|
||||||
return this.socketsInit(sockets)
|
return this.socketsInit(sockets)
|
||||||
// can do other init stuff here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async socketsInit(sockets) {
|
async socketsInit(sockets) {
|
||||||
|
@ -133,7 +146,6 @@ class Base extends EventEmitter {
|
||||||
try {
|
try {
|
||||||
const value = await socket.init()
|
const value = await socket.init()
|
||||||
this.emit('status',{level:'info', socketName:socket.name, msg:'socket successfully initialized', message:value})
|
this.emit('status',{level:'info', socketName:socket.name, msg:'socket successfully initialized', message:value})
|
||||||
results[socket.name] = value
|
|
||||||
resolve(value)
|
resolve(value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.emit('status',{level:'fatal', socketName:socket.name, msg:'socket init error',error:error})// emit an error here, remove socket
|
this.emit('status',{level:'fatal', socketName:socket.name, msg:'socket init error',error:error})// emit an error here, remove socket
|
||||||
|
@ -151,6 +163,7 @@ class Base extends EventEmitter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (typeof sockets ==='string') sockets = [sockets]
|
if (typeof sockets ==='string') sockets = [sockets]
|
||||||
|
|
||||||
sockets.forEach(name => {
|
sockets.forEach(name => {
|
||||||
if (this._socket[name]) {
|
if (this._socket[name]) {
|
||||||
inits.push({name:name, init:this.getSocketInit(name)})
|
inits.push({name:name, init:this.getSocketInit(name)})
|
||||||
|
@ -182,23 +195,32 @@ class Base extends EventEmitter {
|
||||||
* @returns {function} if called before base initialzation it can be ignored as all added sockets will be initialized. After through it be called to initialize that socket
|
* @returns {function} if called before base initialzation it can be ignored as all added sockets will be initialized. After through it be called to initialize that socket
|
||||||
*/
|
*/
|
||||||
registerSocket(name, type = 'c', transport = 'n', options = {}) {
|
registerSocket(name, type = 'c', transport = 'n', options = {}) {
|
||||||
// console.log('=========================================REGISTER=========',name)
|
|
||||||
if (isPlainObject(name)) ({name, type = 'c', transport = 'n', options = {}} = name)
|
if (isPlainObject(name)) ({name, type = 'c', transport = 'n', options = {}} = name)
|
||||||
if (typeof name !=='string') return null
|
if (typeof name !=='string') return null
|
||||||
transport = this._validateTransport(transport)
|
transport = this._validateTransport(transport)
|
||||||
// console.log({ socketName: name, type: type, tranport: transport, options: options, method:'addSocket', line:198, msg:`adding socket ${name}`})
|
log.debug({ socketName: name, type: type, tranport: transport, options: options, method:'addSocket', line:198, msg:`adding socket ${name}`})
|
||||||
options.id = options.id || name
|
options.id = options.id || name
|
||||||
options.name = options.name || name
|
options.name = options.name || name
|
||||||
// TODO add a 'd' type for duplex which creates an 's' first and waits on connect to make a 'c'
|
// TODO add a 'd' type for duplex which creates an 's' first and waits on connect to make a 'c'
|
||||||
if (type==='c') options = Object.assign({initTimeout:this.initTimeout, retryWait:this.retryWait},options) // outbound
|
if (type==='c') options = Object.assign({
|
||||||
if (type==='s') options = Object.assign({defaultReturnCmd:this.defaultReturnCmd},options) // inbound
|
initTimeout:this.initTimeout,
|
||||||
|
retryWait:this.retryWait
|
||||||
|
},options) // outbound
|
||||||
|
if (type==='s') {
|
||||||
|
let conPackets = [this._readyPacket]
|
||||||
|
conPackets = options.conPackets ? conPackets.concat(options.conPackets) : conPackets
|
||||||
|
conPackets = options.conPacket ? conPackets.push(options.conPacket) : conPackets
|
||||||
|
options = Object.assign({
|
||||||
|
defaultReturnCmd:this.defaultReturnCmd,
|
||||||
|
conPackets: conPackets
|
||||||
|
},options) // inbound
|
||||||
|
}
|
||||||
// TODO get rid of hard coded transports and use registered transports (t and n being default)
|
// TODO get rid of hard coded transports and use registered transports (t and n being default)
|
||||||
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':
|
||||||
// console.log('==========socket options==========\n',name,type,transport,options)
|
|
||||||
this._socket[name] = new Socket[TRANSLATE[type]](options)
|
this._socket[name] = new Socket[TRANSLATE[type]](options)
|
||||||
break
|
break
|
||||||
case 'm':
|
case 'm':
|
||||||
|
@ -222,7 +244,7 @@ class Base extends EventEmitter {
|
||||||
this._socket[name]._packetProcess = this._packetProcess.bind(this, name)
|
this._socket[name]._packetProcess = this._packetProcess.bind(this, name)
|
||||||
|
|
||||||
// bubble up events from inidivual sockets to base instance
|
// bubble up events from inidivual sockets to base instance
|
||||||
const EVENTS=['log','connection','connection:consumer', 'connection:socket'] // that should emit up from each socket to instance
|
const EVENTS=['log','socket','connection','connection:consumer', 'connection:socket'] // that should emit up from each socket to instance
|
||||||
EVENTS.forEach(event => {
|
EVENTS.forEach(event => {
|
||||||
this._socket[name].on(event, obj => {
|
this._socket[name].on(event, obj => {
|
||||||
if (Object.prototype.toString.call(obj) !== '[object Object]') {
|
if (Object.prototype.toString.call(obj) !== '[object Object]') {
|
||||||
|
@ -235,7 +257,7 @@ class Base extends EventEmitter {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (type==='c') {
|
if (type==='c') {
|
||||||
this.ready.addObserver(name,this._socket[name],{event:'connection:socket',condition:ev=>{return ev.state==='connected'}})
|
this.ready.addObserver(`${name}:consumer`,this._socket[name],{event:'connection:socket',condition:ev=>{return ev.state==='connected'}})
|
||||||
|
|
||||||
this._socket[name].on('pushed', packet => {
|
this._socket[name].on('pushed', packet => {
|
||||||
packet._header.socketName=name
|
packet._header.socketName=name
|
||||||
|
@ -244,8 +266,7 @@ class Base extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type==='s') {
|
if (type==='s') {
|
||||||
// this._socket[name].on('socket',ev=>console.log(ev))
|
this.ready.addObserver(`${name}:socket`,this._socket[name],{ event:'socket', condition: ev => (ev || {}).state ==='listening' })
|
||||||
this.ready.addObserver(name,this._socket[name],{ event:'socket', condition: ev => (ev || {}).state ==='listening' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getSocketInit(name) // returns the init function (e.g. connect or create) for the socket
|
return this.getSocketInit(name) // returns the init function (e.g. connect or create) for the socket
|
||||||
|
@ -344,6 +365,7 @@ class Base extends EventEmitter {
|
||||||
|
|
||||||
// sockets not passed all sockets pushed, otherwise array of names or sting of transport
|
// sockets not passed all sockets pushed, otherwise array of names or sting of transport
|
||||||
async push(packet,sockets) {
|
async push(packet,sockets) {
|
||||||
|
// TODO change sockets, check if sockets is plain object otherwise it's array of socket name, or single socket name
|
||||||
if (Array.isArray(sockets)) {
|
if (Array.isArray(sockets)) {
|
||||||
let socks = []
|
let socks = []
|
||||||
sockets.forEach(name => {if (this._socket[name].type==='s') socks.push(this._socket[name])})
|
sockets.forEach(name => {if (this._socket[name].type==='s') socks.push(this._socket[name])})
|
||||||
|
@ -494,6 +516,30 @@ class Base extends EventEmitter {
|
||||||
this._cmdProcessors[socket_name] = func
|
this._cmdProcessors[socket_name] = func
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a call to this method will (make or add) return and or subscribe a ready observer for incoming consumer connections
|
||||||
|
consumerConnected (socket,opts={}) {
|
||||||
|
let { subscribe, consumer, add} = opts
|
||||||
|
|
||||||
|
const conditionHandler = async ev => {
|
||||||
|
if ((ev||{}).state ==='connected'){
|
||||||
|
let data = (ev.data ||{})
|
||||||
|
console.log('connected: data from consumer',data)
|
||||||
|
if (consumer) {
|
||||||
|
console.log('observing for a particular consumer',opts.consumer)
|
||||||
|
if (data.name === consumer || [ev.name, ev.id, data.name, data.id].some(name => (name||'').includes(consumer)) ) return true
|
||||||
|
} else return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (typeof socket ==='string') socket = this.getSocket(socket)
|
||||||
|
|
||||||
|
const create = add ? 'addObserver' : 'makeObserver'
|
||||||
|
|
||||||
|
const obs = this.ready[create](socket,{event:'connection:consumer',condition:conditionHandler})
|
||||||
|
if (subscribe) return obs.subscribe(typeof subscribe==='function' ? subscribe : console.log)
|
||||||
|
return obs
|
||||||
|
} // end consumerConnected
|
||||||
|
|
||||||
//=============PRIVATE METHODS =========================================
|
//=============PRIVATE METHODS =========================================
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
|
|
@ -75,10 +75,11 @@ const defaultCmds ={
|
||||||
return packet
|
return packet
|
||||||
},
|
},
|
||||||
ready: async function (packet) {
|
ready: async function (packet) {
|
||||||
console.log('=========================READY RECEIVED AND EMITTED ======================================\n',packet)
|
console.log('======================== READY RECEIVED AND EMITTED (sent)==================================\n',packet)
|
||||||
packet.msg = 'ready state was emitted on receiving process'
|
const event = [ packet.event || packet.name || packet.id]
|
||||||
this.emit(packet.event || packet.name || packet.id, !!(packet.ready || packet.value || packet.state))
|
delete(packet._header)
|
||||||
return packet
|
this.emit(event,packet)
|
||||||
|
return {cmd:'reply', msg:'event was emitted event at socket process from send', event:event}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
c:{
|
c:{
|
||||||
|
@ -89,6 +90,13 @@ const defaultCmds ={
|
||||||
reply: function(packet) {
|
reply: function(packet) {
|
||||||
if (process.env.UCI_ENV==='dev') log.debug({packet:packet, msg:'====Packet returned from socket - default reply logger==='})
|
if (process.env.UCI_ENV==='dev') log.debug({packet:packet, msg:'====Packet returned from socket - default reply logger==='})
|
||||||
return packet
|
return packet
|
||||||
|
},
|
||||||
|
ready: async function (packet) {
|
||||||
|
console.log('----------------------- READY RECEIVED AND EMITTED (pushed)---------------------------\n',packet)
|
||||||
|
const event = [ packet.event || packet.name || packet.id]
|
||||||
|
delete(packet._header)
|
||||||
|
this.emit(event,packet)
|
||||||
|
return {cmd:'reply', msg:'event was emitted event at consumer process from push', event:event}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue