136 lines
4.0 KiB
JavaScript
136 lines
4.0 KiB
JavaScript
import { Socket } from 'net'
|
|
import btc from 'better-try-catch'
|
|
import bunyan from 'bunyan'
|
|
// import Stream from 'delimiter-stream'
|
|
import JsonStream from './json-stream'
|
|
|
|
export default class Consumer extends Socket {
|
|
constructor (path={}, opts={}) {
|
|
super()
|
|
// set or tcp socket
|
|
if (typeof(path)!=='string') {
|
|
opts = path
|
|
if (!path.host || !path.port) opts = path
|
|
this.host = path.host || '127.0.0.1' // TODO log a warning about host on same machine
|
|
this.port = path.port || 8080
|
|
} else this.path = path
|
|
this.packet = {
|
|
_process: async (packet) => {
|
|
console.log('default processor -- packet from socket')
|
|
console.dir(packet)
|
|
return packet }
|
|
}
|
|
this.keepAlive = opts.keepAlive ? opts.keepAlive : true
|
|
this._ready = false
|
|
this.timeout = opts.timeout || 500
|
|
this.wait = opts.wait || 5
|
|
this.stream = new JsonStream()
|
|
this.packet = {
|
|
_process: (packet) => {
|
|
packet.res='echoed'
|
|
return packet }
|
|
}
|
|
// logging
|
|
this.log_file=opts.log_file || './socket.log'
|
|
this.log_opts = {streams:[]}
|
|
this.log_opts.name = opts.name ? opts.name : 'uci-socket-consumer'
|
|
// this.log_opts.streams.push({level: 'info',path: this.log_file })
|
|
if (opts.log) this.log_opts.streams.push({level: 'info',stream: process.stdout})
|
|
this.log = bunyan.createLogger(this.log_opts)
|
|
// bind to class for other class functions
|
|
this.connect = this.connect.bind(this)
|
|
this.ready = this.ready.bind(this)
|
|
}
|
|
|
|
ready() {return this._ready}
|
|
|
|
async connect () {
|
|
|
|
// if (context) this.packet.context = context
|
|
// else this.packet.context = this
|
|
|
|
return new Promise( (resolve,reject) => {
|
|
|
|
const connect = () => {
|
|
super.connect({ port:this.port, host:this.host, path: this.path })
|
|
}
|
|
|
|
const timeout = setTimeout(() =>{
|
|
reject(`unable to connect in ${this.timeout*10}ms`)
|
|
}
|
|
,this.timeout*10)
|
|
|
|
this.once('connect', async () => {
|
|
clearTimeout(timeout)
|
|
this.listen()
|
|
this.log.info({path:this.path},'connected waiting for socket ready handshake')
|
|
this.setKeepAlive(this.keepAlive)
|
|
let [err, res] = await btc(isReady).bind(this)(this.ready, this.wait, this.timeout)
|
|
if (err) reject(err)
|
|
this.log.info('handshake done, authenticating')
|
|
// TODO authenticate here by encrypting a payload with private key and sending that.
|
|
// await btc(authenticate)
|
|
resolve(res)
|
|
})
|
|
|
|
this.on('error', async (err) => {
|
|
if (err.code === 'EISCONN') {
|
|
return resolve('ready')
|
|
}
|
|
this.log.warn(err.code)
|
|
setTimeout(() =>{
|
|
this.log.warn('retry connect')
|
|
connect()
|
|
}
|
|
,this.wait*10)
|
|
})
|
|
|
|
connect()
|
|
|
|
}) //end promise
|
|
|
|
}
|
|
|
|
async listen () {
|
|
|
|
this.log.info('listening for incoming packets from socket')
|
|
this.on('data', this.stream.onData)
|
|
this.stream.on('message', messageProcess.bind(this))
|
|
async function messageProcess (packet) {
|
|
if (packet.ready) {
|
|
this._ready = true
|
|
return }
|
|
await this.packet._process(packet)
|
|
}
|
|
}
|
|
|
|
async send(packet) {
|
|
await this.write(this.stream.serialize(packet))
|
|
// TODO handle error here? and/or await response if required before allowing more sending
|
|
}
|
|
|
|
// TODO register alt stream processor (emit 'message' with JSON, serialize function, onData method for raw socket chucks)
|
|
|
|
// TODO register authenciation function (set up default)
|
|
|
|
registerPacketProcessor (func) {
|
|
this.packet._process = func
|
|
}
|
|
|
|
} // end class
|
|
|
|
// wait for handshake packet from socket
|
|
function isReady(ready, wait=30, timeout=1000) {
|
|
let log = this.log
|
|
let time = 0
|
|
return new Promise((resolve, reject) => {
|
|
(function waitReady(){
|
|
if (time > timeout) return reject(`timeout waiting for socket ready handshake - ${timeout}ms`)
|
|
if (ready()) return resolve('ready')
|
|
log.info(`waiting ${wait}ms for handshake`)
|
|
time += wait
|
|
setTimeout(waitReady, wait)
|
|
})()
|
|
})
|
|
}
|