import { Server } from 'net' import { unlink as fileDelete } from 'fs' import btc from 'better-try-catch' import Logger from 'simple-node-logger' import ON_DEATH from 'death' //this is intentionally ugly let logger = { logFilePath:'logfile.log', timestampFormat:'YYYY-MM-DD HH:mm:ss.SSS' } export default class Socket extends Server { constructor (path, opts={}) { super() this.path = path this.logger = Logger.createSimpleLogger(opts.logger ? opts.logger: logger) } // end constructor async create ( app ) { this.on('error', async (err) => { // recover from socket file that was not removed if (err.code === 'EADDRINUSE') { console.log(`socket path ${this.path} already exists...deleting`) await fileDelete(this.path) await this.listen(this.path) return Promise.resolve(err.code) } // otherwise fatally exit console.log('error creating socket: ',err.code) return Promise.reject(err.code) }) // this.on('listening', async () => { console.log(`socket created at ${this.path}`) // this gets called for each client connection and is unique to each this.on('connection', (socket) => { console.log('new consumer connected') socket.on('data', async (buf) => { let [err, packet] = btc(JSON.parse)(buf.toString()) if (!err) { this.logger.info(`data packet received to socket \n ${packet}`) socket.write(JSON.stringify(await app.processPacket.bind(app)(packet))) } else { console.log(`bad packet JSON syntax \n ${buf.toString()}`)} }) // end incoming data listerner }) // end connected consumer }) // end socket listening listener // start it await this.listen(this.path) // if socket is terminated then shutdown gracefully ON_DEATH( async () => { await this.destroy() }) process.once('SIGUSR2', async () => { await this.destroy process.kill(process.pid, 'SIGUSR2') }) } // end create async destroy () { console.log('\nclosing down socket') await this.close() console.log('\n all connections closed....exiting') process.exit() } // end destroy } // end class