UNPKG

node-edge

Version:

node-edge is a tcp communication library for edge computing using local area networking.

615 lines (514 loc) 17.1 kB
'use strict' const edge = require('node-edge') const { Buffer } = require('node:buffer') const { createHash } = require('node:crypto') function voltageSource(){ return 50 + Math.floor(Math.random() * 10) } let port = 8125 /**************************************************************** A quick simple client/server api test Pass: The test will run continously w/o errors for a least 30000 or half-minute Fail: If any error occurs the test run will throw an error ****************************************************************/ /******************** server section ********************/ // edge.createServer(port, (server) => { // port must be provided // throws an error due to data has ciphertext // 1. create server w/ callback /*edge.createServer(8127, (server) => { server.publish('server-pub-1', (tcp) => { tcp.send( voltageSource() ) }) server.subscribe('client-pub-1', (data) => { console.log('client-pub-1', typeof data) // expect data as buffer from regular string or number if(typeof data !== 'object'){ throw 'invalid data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) server.on('connection', (count) => { console.log('****************** server2 connected client:', count) if(count > 5){ console.log('runaway client count!') process.exit() } }) })*/ // 2. create server w/o callback then return the server object and using server.listen(port) to start the server // const server = edge.createServer(port) // add the port and server will start listening immediately instead of using the server.listen(port) const server = edge.createServer() /*** * publish method */ let serverPayload = {} server.publish('server-pub-1', (tcp) => { let v = voltageSource() tcp.send( v ) // number payload serverPayload.data = {topic:'server-pub-1', type:'number', value:v} }) server.pub('server-pub-2', (tcp) => { tcp.polling = 9000 let v = {value:voltageSource()} const hash = createHash('sha256') hash.update( JSON.stringify(v) ) serverPayload.data.hash = hash.digest('hex') tcp.send( v ) // object payload serverPayload.data = {topic:'server-pub-2', type:'object', value:v} }) server.pub('server-pub-3', (tcp) => { tcp.polling = 7000 let v = JSON.stringify({topic:'server-pub-3', value:voltageSource()}) const hash = createHash('sha256') hash.update( v ) serverPayload.data.hash = hash.digest('hex') tcp.send( v ) // json string payload serverPayload.data = {topic:'server-pub-3', type:'json string', value:v} }) server.publish('server-pub-4', (tcp) => { let v = voltageSource().toString() tcp.send( v ) // regular string payload serverPayload.data = {topic:'server-pub-4', type:'regular string', value:v} }) /*** * subscribe method */ server.subscribe('client-pub-1', (data) => { // data can be buffer, object and string console.log('sub client-pub-1', typeof data, data) // expect data as buffer from regular string or number if(!Buffer.isBuffer(data) && typeof data !== 'object' && typeof data !== 'string'){ throw 'invalid data' } }) server.sub('client-pub-2', (data) => { console.log('client-pub-2', data) // expect data as object if(typeof data !== 'object'){ throw 'invalid data as object' } }) server.sub('client-pub-3', (data) => { console.log('client-pub-3', data) // expect data as json string if(typeof data !== 'string'){ throw 'invalid data as json string' } let d = JSON.parse(data) if(typeof d !== 'object'){ throw 'invalid parse data from json string' } }) /*** * dataSource for read/getData method */ server.dataSource('source-data-1', (tcp) => { console.log('source-data-1', tcp.payload) // payload can be a regular string | number | object | json string if(tcp.payload === 'on'){ //tcp.send( tcp.payload ) tcp.end( tcp.payload ) } else if(tcp.payload === 'off'){ tcp.send( tcp.payload ) //tcp.end( tcp.payload ) } else{ tcp.send( voltageSource().toString() ) //tcp.end( voltageSource().toString() ) } }) server.on('source-data-2', (tcp) => { if(tcp.payload){ console.log('source-data-2', tcp.payload) } else{ tcp.end( voltageSource() ) } }) server.on('source-data-3', (tcp) => { tcp.send( {topic:'source-data-3' , value:voltageSource()} ) }) server.on('source-data-4', (tcp) => { tcp.send( JSON.stringify({topic:'source-data-3' , value:voltageSource()}) ) }) /*** * dataSource for write/sendData method */ server.dataSource('send-data-1', (tcp) => { if(tcp.payload){ console.log(tcp.topic, tcp.payload) if(typeof tcp.payload !== 'object'){ throw 'invalid data as object' } tcp.send( tcp.payload ) } }) let testSend = 0 server.on('send-data-2', (tcp) => { // JSON.stringify({value:55}) ++testSend if(tcp.payload){ console.log(tcp.topic, tcp.payload) if(typeof tcp.payload !== 'string'){ throw 'invalid data as json string' } let d = JSON.parse(tcp.payload) if(typeof d !== 'object'){ throw 'invalid data as object' } if(testSend > 10){ tcp.send( tcp.payload ) // reply as json string } else if(testSend > 20) { tcp.send( d ) // reply as object testSend = 0 } else{ tcp.send( d ) } } }) server.on('send-data-3', (tcp) => { if(tcp.payload){ console.log(tcp.topic, tcp.payload) if(typeof tcp.payload !== 'number'){ throw 'invalid data as a number' } tcp.send( tcp.payload ) } }) server.on('send-data-4', (tcp) => { if(tcp.payload){ console.log(tcp.topic, tcp.payload) if(typeof tcp.payload !== 'string'){ throw 'invalid data as regular string' } tcp.send(tcp.payload) } }) server.on('error', (e) => { console.log('server error:', e.message) if(e.message){ throw 'invalid server error message' } }) server.on('connection', (count) => { console.log('****************** server1 connected client:', count) if(count > 50){ console.log('runaway client count!') process.exit() } }) server.listen(port) setImmediate(() => { console.log('server.listening', server.listening) console.log('server.address()', server.address()) }) /********************* client section *********************/ let secure = true // create a client w/o a callback then return the client //let ec1 = new edge.client(port) let ec1 = new edge.client({port:8125, restart:true, secure:secure }) console.log('edge client', port) ec1.on('ready', (data) => { console.log('ec1 ready', data) if(!data){ throw 'invalid ready data' } }) ec1.on('error', (e) => { console.log('ec1 error', e.message) if(e.message){ throw 'invalid client error message' } }) /*** * getResources method */ ec1.getResources((data) => { console.log('server resources', data) if(!Array.isArray(data)){ throw 'invalid getResources data' } }) setInterval(() => { ec1.read('server-pub-1', (data) => { // tcp.send( voltageSource() ) console.log('ec1 read latest server-pub-1', typeof data, data.toString()) if(!Buffer.isBuffer(data) && serverPayload.type === 'number'){ throw 'invalid data as buffer' } }) }, 1000) /*** * subscribe method */ ec1.subscribe('server-pub-1', (data) => { // tcp.send( voltageSource() ) console.log('server-pub-1', typeof data, data, data.toString()) if(!Buffer.isBuffer(data) && serverPayload.data.type === 'number' && serverPayload.data.value === parseInt(data)){ throw 'invalid data as buffer' } let v = parseInt(data) //console.log('server-pub-1', v) if(v < 53){ ec1.send('source-data-1', 'on') //, (data) => { console.log('***send source-data-1 on', data) }) // ok } else{ ec1.send('source-data-1', 'off', (data) => { console.log('***send source-data-1 off', data) }) } }) ec1.sub('server-pub-2', (data) => { // tcp.send( {value:voltageSource()} ) console.log('server-pub-2', data) const hash = createHash('sha256') hash.update( JSON.stringify(data) ) let dataHash = hash.digest('hex') if(serverPayload.data.type === 'object' && serverPayload.data.value === data && serverPayload.data.hash === dataHash ){ throw 'invalid data as object' } }) ec1.sub('server-pub-3', (data) => { // tcp.send( JSON.stringify({topic:'server-pub-3', value:voltageSource()}) ) console.log('server-pub-3', typeof data, secure, data, serverPayload.data.value) // expect a string json due to JSON.stringify({topic:'server-pub-3', value:voltageSource()}) const hash = createHash('sha256') hash.update(data.toString()) let dataHash = hash.digest('hex') if(serverPayload.data.value === data.toString() && serverPayload.data.hash === dataHash ){ throw 'invalid rcvd data as json string' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } let d = JSON.parse(data) if(typeof d !== 'object'){ throw 'invalid parse data from json string' } }) ec1.subscribe('server-pub-4', (data) => { // tcp.send( '155' ) console.log('server-pub-4', typeof data, data) if(!Buffer.isBuffer(data) && serverPayload.data.type === 'regular string' && serverPayload.data.value === data.toString()){ throw 'invalid data as buffer' } let v = parseInt(data) // data is buffer //console.log('edge-pub-', v) if(v > 53){ ec1.send('source-data-1', 'on', (data) => { console.log('***send source-data-1 on', data) }) } else{ ec1.send('source-data-1', 'off') //, (data) => { console.log('***send source-data-1 off', data) }) } }) /*** * publish method */ ec1.publish('client-pub-1', (tcp) => { // dynamic payload test let pl = voltageSource() // tcp.send(pl) if(pl <= 50){ tcp.send(pl.toString()) //throw 'string' } if(pl > 50 && pl < 55){ tcp.send(pl) //throw 'number' } else if(pl > 55 && pl < 60){ tcp.send({value:pl}) //throw 'object' } else{ tcp.send(JSON.stringify({value:pl})) //throw 'json as string' } }) ec1.pub('client-pub-2', (tcp) => { let pl = voltageSource() tcp.send({value:pl}) }) ec1.pub('client-pub-3', (tcp) => { let pl = voltageSource() tcp.send(JSON.stringify({value:pl})) }) setInterval(() => { // dynamic payload stress test ec1.read('client-pub-1', (data) => { // tcp.send( voltageSource() ) or tcp.send({value:pl}) or tcp.send(JSON.stringify({value:pl})) console.log('ec1 read latest client-pub-1', typeof data, data, data.toString()) if(!Buffer.isBuffer(data) && typeof data !== 'object'){ throw 'invalid data as buffer' } }) }, 1200) setInterval(() => { ec1.read('client-pub-3', (data) => { // tcp.send(JSON.stringify({value:pl})) console.log('ec1 read latest client-pub-3', typeof data, data, data.toString()) if(!Buffer.isBuffer(data)){ // secure = false/true throw 'invalid data as buffer' } }) }, 1200) /*** * read/getData method */ ec1.read('source-data-1', (data) => { // expect data as buffer from a regular string data source console.log('ec1 source-data-2', data.toString() , data) if(typeof data !== 'object'){ throw 'invalid data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) ec1.read('source-data-2', (data) => { // expect data as buffer from a number data source console.log('ec1 source-data-2', data.toString() , data) if(typeof data !== 'object'){ throw 'invalid data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) ec1.getData('source-data-3', (data) => { // expect data as object {topic:'source-data-3' , value:voltageSource()} console.log('ec1 source-data-3', data) console.log('ec1 source-data-3 data.topic', data.topic) if(typeof data !== 'object'){ throw 'invalid data as object' } }) ec1.getData('source-data-4', (data) => { // expect data as object JSON.stringify({topic:'source-data-3' , value:voltageSource()}) console.log('ec1 source-data-3', data) console.log('ec1 source-data-3 data.topic', data.topic) if(!Buffer.isBuffer(data)){ // secure = false/true fixed 3/14/23 throw 'invalid data as buffer' } let d = JSON.parse(data) if(typeof d !== 'object'){ throw 'invalid parse data from json string' } }) // getData stress test setInterval(() => { ec1.read('source-data-2', (data) => { console.log('stress test - read ec1 source-data-2', data.toString() , data) // expect data as buffer from a number or regular string data source send if(typeof data !== 'object'){ throw 'invalid data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) }, 500) /*** * send/write/sendData or sendData method */ ec1.sendData('send-data-1', {value:55}, (data) => { // rcvd data is an object console.log('*send-data-1', data) if(typeof data !== 'object'){ throw 'invalid rcvd data as object' } }) ec1.write('send-data-2', JSON.stringify({value:55}), (data) => { // need to JSON.parse(rcvd data) in dataSource console.log('*send-data-2', typeof data, secure, data) if(typeof data !== 'string' && typeof data !== 'object'){ throw 'invalid payload type' } if(testSend > 21){ throw 'runaway testSend' } }) ec1.sendData('send-data-3', 105, (data) => { // rcvd data is a buffer console.log('*send-data-3', data) if(typeof data !== 'object'){ throw 'invalid rcvd data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) ec1.send('send-data-4', '105', (data) => { // rcvd data is a buffer console.log('*send-data-4', data.toString(), data) if(typeof data !== 'object'){ throw 'invalid rcvd data as buffer' } if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) // sendData stress test setInterval(() => { ec1.sendData('send-data-1', {value:55}, (data) => { // rcvd data is an object console.log('* stress test - send-data-1', data) if(typeof data !== 'object'){ throw 'invalid rcvd data as object' } }) ec1.write('send-data-2', JSON.stringify({value:55}), (data) => { // need to JSON.parse(rcvd data) in dataSource console.log('*send-data-2', typeof data, secure, data) if(typeof data !== 'string' && typeof data !== 'object'){ throw 'invalid payload type' } }) }, 400) setTimeout(() => { /*** * unsubscribe method */ console.log('>>>>>>>> unsub') ec1.unsubscribe('server-pub-1', (data) => { console.log('unsub server-pub-1', typeof data, data.toString()) //if(typeof data !== 'boolean'){ // secure = true, not the case anymore - fixed 3/14/23 //throw 'invalid data as boolean' //} if(!Buffer.isBuffer(data)){ // valid for secure/unsecure throw 'invalid data as buffer' } }) ec1.unsub('server-pub-2', (data) => { console.log('unsub server-pub-2', data.toString()) //if(typeof data !== 'boolean'){ //throw 'invalid data as boolean' //} if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) ec1.unsub('server-pub-3', (data) => { console.log('unsub server-pub-3', data.toString()) //if(typeof data !== 'boolean'){ //throw 'invalid data as boolean' //} if(!Buffer.isBuffer(data)){ throw 'invalid data as buffer' } }) }, 20000) setTimeout(() => { /*** * subscribe again method */ console.log('>>>>>>>> sub again') // callback should not be executed if successful ec1.subscribe('server-pub-1', (data) => { console.log('sub again server-pub-1', data.toString()) if(data){ throw 'invalid return data' } }) ec1.sub('server-pub-2') ec1.sub('server-pub-3') }, 30000) let count = 0 setInterval(() => { ++count console.log('count', count) if(secure && count > 5){ secure = false count = 0 } else if(secure === false && count > 5){ secure = true count = 0 } console.log('secure', secure) }, 10000)