basic working socket-consumer modules with no handshaking but passing json objects

tls
David Kebler 2018-01-08 13:06:01 -08:00
parent 0290ec99a7
commit e5167c3995
8 changed files with 210 additions and 23 deletions

30
examples/client.mjs Normal file
View File

@ -0,0 +1,30 @@
import Consumer from '../src/consumer'
const USOCKET = '/opt/sockets/samplecs.sock'
const socket1 = new Consumer(USOCKET)
const socket2 = new Consumer(USOCKET)
let packet1 = {name: 'socket1', cmd:'doit', data:'data sent by socket1'}
let packet2 = {name: 'socket2', cmd:'doit', data:'data sent by socket2'}
;
(async () => {
await socket1.connect()
await socket2.connect()
await socket1.listen(app)
await socket2.listen(app)
socket1.send(packet1)
socket2.send(packet2)
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})
// This is your socket handler waiting on a message to do something
function app (packet) {
console.log('incoming packet from socket to process')
console.dir(packet)
}

36
examples/server.mjs Normal file
View File

@ -0,0 +1,36 @@
import { Socket } from '../src'
const USOCKET = '/opt/sockets/samplecs.sock'
;
(async () => {
class Test {
constructor() {
this.socket = new Socket(USOCKET)
}
async processPacket(packet) {
console.log('packet being processed')
console.dir(packet)
return await this[packet.cmd](packet.data,packet.name)
}
async doit(data,name) {
let res = {}
console.log('data:', data)
res.status ='success'
res.name = name
res.data = 'this would be response from device'
return(res)
}
init() { this.socket.create(this)}
}
let test = new Test()
await test.init()
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})

View File

@ -1,10 +1,17 @@
{ {
"name": "@uci/esmtesting", "name": "@uci/unix-socket",
"version": "0.1.0", "version": "0.1.0",
"description": "Test for esm", "description": "Bare bones intra Host Unix Socket for basic IPC on same machine",
"main": "index.js", "main": "src",
"scripts": { "scripts": {
"start": "node -r @std/esm test" "test": "node -r @std/esm test",
"testw": "./node_modules/.bin/nodemon -r @std/esm test",
"s": "node -r @std/esm examples/server",
"devs": "./node_modules/.bin/nodemon -r @std/esm -e mjs examples/server",
"c": "node -r @std/esm examples/client",
"cs": "node -r @std/esm client-server",
"ms": "node -r @std/esm mqtt-server",
"mc": "node -r @std/esm mqtt-client"
}, },
"author": "David Kebler", "author": "David Kebler",
"license": "MIT", "license": "MIT",
@ -24,9 +31,12 @@
"homepage": "https://github.com/uCOMmandIt/message#readme", "homepage": "https://github.com/uCOMmandIt/message#readme",
"@std/esm": "cjs", "@std/esm": "cjs",
"devDependencies": { "devDependencies": {
"@std/esm": "^0.18.0" "@std/esm": "^0.18.0",
"nodemon": "^1.14.3"
}, },
"dependencies": { "dependencies": {
"json-ipc-lib": "^1.0.2" "better-try-catch": "^0.6.2",
"death": "^1.1.0",
"simple-node-logger": "^0.93.33"
} }
} }

View File

@ -1,5 +1 @@
## Native ESM Testing ## Various Communication Protocol/Transport Testing
`npm start`
esm module loader testing for module written with es modules but using .js as it was meant to be transpiled

43
src/consumer.mjs Normal file
View File

@ -0,0 +1,43 @@
import { Socket } from 'net'
import btc from 'better-try-catch'
export default class Consumer extends Socket {
constructor (path, opts={}) {
super()
this.path = path
this.keepAlive = opts.keepAlive ? opts.keepAlive : true
}
async connect () {
console.log('attempting to connect to socket: ', this.path)
await super.connect({ path: this.path })
console.log(`connected to ${this.path}`)
this.setKeepAlive(this.keepAlive)
this.on('error', (error) => {
'client socket error \n ', error.code
})
}
async send(packet) {
let [err, strbuf] = btc(JSON.stringify)(packet)
if (!err) {
this.write(strbuf)
}
else { console.log(`bad packet JSON syntax \n ${packet}`)}
}
async listen (app) {
this.on('data', async (buf) => {
let [err, packet] = btc(JSON.parse)(buf.toString())
if (!err) {
app(packet)
}
else { console.log(`bad packet JSON syntax \n ${buf.toString()}`)}
})
}
} // end class

2
src/index.mjs Normal file
View File

@ -0,0 +1,2 @@
export { default as Socket } from './socket'
export { default as Consumer } from './consumer'

82
src/socket.mjs Normal file
View File

@ -0,0 +1,82 @@
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

View File

@ -1,12 +0,0 @@
import ipc from 'json-ipc-lib/src'
console.log('clinet\n',[...getAllMethodNames(new ipc.client )])
function getAllMethodNames(obj) {
let methods = new Set()
while (obj = Reflect.getPrototypeOf(obj)) {
let keys = Reflect.ownKeys(obj)
keys.forEach((k) => methods.add(k))
}
return methods
}