UNPKG

btnexus-node

Version:
297 lines (248 loc) 8.61 kB
/** * Ophion Cloud client node * * @author Marc Fiedler * @copyright 2020 Blackout Technologies, all rights reserved, all rights reserved */ // Use Strict mode ECMA Script 5+ "use_strict"; // System imports const os = require('os'); const fs = require('fs'); // 3rd party imports const io = require('socket.io-client'); const uniqid = require('uniqid'); const ip = require('ip'); const findRoot = require('find-root'); const chalk = require('chalk'); // local imports const Message = require('./message'); const BTRequest = require('./btRequest'); const ConnectHash = require('./connectHash'); module.exports = class Node { constructor(btNexusConfig){ // load connect hash const root = findRoot(process.cwd()); const ch = new ConnectHash(); if( ch.isValid() ){ this.settings = ch.data; }else{ this.error(ch.error); process.exit(-1); } this.defaultMaxListeners = 10; // once per start setup this.nodeId = uniqid(); // configuration this.config = JSON.parse(fs.readFileSync(root+'/package.json', 'utf-8')); this.btNexus = btNexusConfig; // message callbacks for topics. Format: messageCallbacks["topic"] = callback this.messageCallbacks = {}; this.groups = {}; // define the namespace of the topic this.namespace = "ai.blackout"; this.hostName = os.hostname(); this.hostAddress = ip.address(); this.nodeNamespace = undefined; this.connectionAlive = false; this.protocol = "wss"; this.heartBeatRate = 50000; this.heartBeatCheckRate = 30000; this.shouldCheckHeartbeat = true; if( this.btNexus == undefined ){ if( config.btNexus != undefined ){ this.btNexus = config.btNexus; }else{ this.emit('error', 'Unable to find btNexus connect config'); } } // Remove in >= 2.3.x // legacy dependency, will be removed in later releases if( this.btNexus.interface != undefined ){ this.warning("Deprication warning: btNexus.interface will no longer be supported from version >= 2.3.x"); this.btNexus.token = this.btNexus.interface; } var accessRequest = { applicationId: this.settings.id, applicationType: this.config.type } this.api = new BTRequest(this.settings.host, this.settings.token); this.api.post("applicationAccessRequest", accessRequest, (success, resp) => { if( success ){ this.sessionId = resp.sessionId; this.run(); }else{ this.error("Unable to register with btNexus instance: "+resp.error+" Code: "+resp.code); } }); } run(){ // start connecting this.connect(); } connect(){ // in case of reconnect, clear intervals if( this.heartbeatInterval != undefined ){ this.heartbeatInterval.cancel(); } this.messageCallbacks = {}; this.groups = {}; var host = undefined; if( this.btNexus.protocol != undefined ){ protocol = this.btNexus.protocol; } if( this.settings.host != undefined ){ host = this.settings.host; } if( this.btNexus.port != undefined ){ host += ':'+this.btNexus.port; } // load the WebSocket var protocol = "wss"; if( host.indexOf("http://") > -1 ){ protocol = "ws"; } host = host.replace('https://', ''); host = host.replace('http://', ''); host = host.replace('wss://', ''); host = host.replace('ws://'); // make connect this.info("Connecting to: "+protocol+'://'+host); this.ws = io(protocol+'://'+host, { query: 'instance='+this.settings.hostId }); var self = this; this.ws.on('btnexus-registration', function(msg) { if( msg.success === true ){ self.connectionAlive = true; if( self.btNexus.onConnected != undefined ){ self.btNexus.onConnected(); } }else if(msg.success === false ){ self.error("Registration with btNexus failed. Please verify your accessToken and sessionId"); process.exit(-1); }else{ // after connection is established, register with service var rMsg = new Message('register'); rMsg.data.sessionId = self.sessionId; rMsg.data.id = msg.id; rMsg.data.host = self.hostName; rMsg.data.ip = self.hostAddress; rMsg.data.node = self.config; this.nodeId = msg.id; self.ws.emit('btnexus-registration', rMsg.toString()); } }); this.ws.on('pong', function(data) { // ignore pong message if( process.env.DEBUG_MEMORY != undefined ){ console.log(new Date()+" pong"); } }); this.ws.on('error', function(error) { if( self.btNexus.onError != undefined ){ self.btNexus.onError(error); }else{ console.log('btNexus Error: '+error) } }); this.ws.on('disconnect', function(code, reason) { self.connectionAlive = false; // reconnect if( self.btNexus.onClose != undefined ){ self.btNexus.onClose(); }else{ console.log("Connection to btNexus lost."); } }); } publish(group, topic, payload){ var acMsg = new Message('publish'); acMsg.data.nodeId = this.nodeId; if( topic.indexOf(".") == -1 ){ topic = this.namespace+"."+topic; } acMsg.data.topic = topic; acMsg.data.payload = payload; acMsg.data.group = group; // send message over the wire this.ws.emit('btnexus-publish', acMsg.toString()); } subscribe(group, topic, callback){ if( this[group] != undefined ){ if( topic.indexOf(".") == -1 ){ topic = this.namespace+"."+topic; } if( this[group][topic] == undefined ){ this[group][topic] = callback; this.ws.on(topic, (msg) => { this[group][topic](msg); }); }else{ this.warning("Multiple subscriptions to topic: "+topic+" in group "+group); } }else{ this.error("Unable to subscribe to topic "+topic+" of unknown group "+group); } } publishError(group, error){ this.publish(group, 'error', {message: error}); } publishWarning(group, warning){ this.publish(group, 'warning', {message: warning}); } publishDebug(group, debug){ this.publish(group, 'debug', {message: debug}); } join(group){ if( this[group] == undefined ){ this[group] = []; // subscribe to a specific topic var sub = new Message('join'); sub.data.group = group; this.ws.emit('btnexus-join', sub.toString()); }else{ this.warning("Duplicate join to group: "+group); } } leave(groupName, joinCallback){ // register message callbacks this.groups[groupName] = undefined; // subscribe to a specific topic var sub = new Message('leave'); sub.data.groupName = groupName; this.ws.emit('message', sub.toString()); // TODO NEEDS TO BE IMPLEMENTED // delete message after use sub = undefined; } close(){ // close connection to socket if( this.ws != undefined ){ this.ws.close(); } } error(error){ console.log( chalk.red("[")+ chalk.red("btNexus Node")+ chalk.red("]")+": "+ error ); } info(text){ console.log( chalk.white("[")+ chalk.blue("btNexus Node")+ chalk.white("] ")+": "+text ) } warning(text){ console.log( chalk.yellow("[")+ chalk.blue("btNexus Node")+ chalk.yellow("] ")+": "+ chalk.yellow(text) ) } }