UNPKG

microservicebus-core

Version:

node.js node for microServiceBus.com. Please visit https://microservicebus.com for more information.

1,108 lines (1,023 loc) 111 kB
/* The MIT License (MIT) Copyright (c) 2014 microServiceBus.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* jshint node: true */ /* jshint esversion: 6 */ /* jshint strict:false */ 'use strict'; var moment = require('moment'); var async = require('async'); var reload = require('require-reload')(require); var fs = require('fs'); var path = require('path'); var guid = require('uuid'); var util = require('./utils.js'); var webRequest = require('./WebRequest'); var Applicationinsights = require("./Applicationinsights"); var MicroService = require('./services/microService'); var Com = require("./Com.js"); var PersistHelper = require("./PersistHelper"); var Orchestrator = require('./Orchestrator'); var TTLCollection = require("./TTLCollection"); const UnitConverter = require('./UnitConverter'); function MicroServiceBusNode(settingsHelper) { var self = this; this.settingsHelper = settingsHelper; // Callbacks this.onStarted = null; this.onStopped = null; this.onSignedIn = null; this.onPingResponse = null; this.onUpdatedItineraryComplete = null; this.onLog = null; this.onAction = null; this.onCreateNode = null; this.onCreateNodeFromMacAddress = null; this.onAssertNode = null; this.onReportLocation = null; this.onRequestHistory = null; this.onTestResult = null; this.onTestComplete = null; this.onUnitTestComplete = null; this.onUpdateFirmware = null; // Handle settings var _hostPrefix = 'node'; // Used for creating new hosts var _itineraries; // all downloaded itineries for this host this._microServices = []; // all started services var _downloadedScripts = []; var _downloadedDependancyFiles = []; var _firstStart = true; var _loadingState = "none"; // node -> loading -> done -> stopped var _comSettings; var _persistHelper; var _historyCollection; var _failedHistoryCollection; var _eventHistoryCollection; var _exceptionCollection; var _restoreTimeout; var _backgroundService = null; var signInResponse; var com; var exceptionsLoadingItineraries = 0; var _startWebServer = false; var port = process.env.PORT || 1337; var app;// = express(); var server; var _applicationinsights = new Applicationinsights(); var _orchestrator = new Orchestrator(); var _unitConverter = new UnitConverter(); var http; var express; var bodyParser; var serviceCount = 0; this.nodeVersion = null; // History persistance and ttl stuff const TTLHISTORY_TTL = 7 * 24 * 60 * 60 * 1000; // one week const TTLHISTORY_CHECKINTERVAL = 5 * 60 * 1000; // every 5 minutes const TTLHISTORY_PERSISTINTERVAL = 5 * 60 * 1000; // 60 minutes const TTLEXCEPTION_PERSISTINTERVAL = 30 * 60 * 1000; // every 30 minutes const TTLEXCEPTION_INTERVAL = 15 * 60 * 1000; // every hour _historyCollection = new TTLCollection({ key: 'TRANSMIT_SUCCESS_HISTORY', ttl: TTLHISTORY_TTL, checkPeriod: TTLHISTORY_CHECKINTERVAL, // Interval to check for expired items persistPeriod: TTLHISTORY_PERSISTINTERVAL, // Interval (this.options.persistPeriod) for persising self._collection persistDir: path.resolve(settingsHelper.homeDirectory, "history"), persistFileName: 'TRANSMIT_SUCCESS_HISTORY.json' }); _failedHistoryCollection = new TTLCollection({ key: 'TRANSMIT_FAILED_HISTORY', ttl: TTLHISTORY_TTL, checkPeriod: TTLHISTORY_CHECKINTERVAL, // Interval to check for expired items persistPeriod: TTLHISTORY_PERSISTINTERVAL, // Interval (this.options.persistPeriod) for persising self._collection persistDir: path.resolve(settingsHelper.homeDirectory, "history"), persistFileName: 'TRANSMIT_FAILED_HISTORY.json' }); _eventHistoryCollection = new TTLCollection({ key: 'TRANSMIT_EVENTS_HISTORY', ttl: TTLHISTORY_TTL, checkPeriod: TTLHISTORY_CHECKINTERVAL, // Interval to check for expired items persistPeriod: TTLEXCEPTION_PERSISTINTERVAL, // Interval (this.options.persistPeriod) for persising self._collection persistDir: path.resolve(settingsHelper.homeDirectory, "history"), persistFileName: 'TRANSMIT_EVENTS_HISTORY.json' }); let aggregateExceptionInterval = TTLEXCEPTION_INTERVAL; if (settingsHelper.settings.policies.exceptionPolicy && settingsHelper.settings.policies.exceptionPolicy.aggregateExceptionInterval) { aggregateExceptionInterval = settingsHelper.settings.policies.exceptionPolicy.aggregateExceptionInterval; } _exceptionCollection = new TTLCollection({ key: 'EXCEPTION_HISTORY', ttl: aggregateExceptionInterval, checkPeriod: aggregateExceptionInterval, // Interval to check for expired items persistPeriod: aggregateExceptionInterval, // Interval (this.options.persistPeriod) for persising self._collection persistDir: path.resolve(settingsHelper.homeDirectory, "history"), persistFileName: 'EXCEPTION_HISTORY.json' }); // Called by HUB if it wasn't able to process the request MicroServiceBusNode.prototype.ErrorMessage = function (message) { self.onLog("errorMessage => " + message); self.onStarted(0, 1); }; // Called by HUB to receive all active serices /* istanbul ignore next */ MicroServiceBusNode.prototype.GetEndpoints = function (message) { self.onLog("getEndpoints => " + message); }; // Called by HUB when itineraries has been updated /* istanbul ignore next */ MicroServiceBusNode.prototype.UpdateItinerary_Legacy = function (updatedItinerary) { try { self.onLog(); self.onLog("Updating flows".green); self.onLog(); // Stop all services stopAllServices(function () { self.onLog("All services stopped".yellow); }); var itinerary = _itineraries.find(function (i) { return i.itineraryId === updatedItinerary.itineraryId; }); for (var i = _itineraries.length; i--;) { if (_itineraries[i].itineraryId === updatedItinerary.itineraryId) { _itineraries.splice(i, 1); } } _itineraries.push(updatedItinerary); startAllServices(_itineraries, function () { if (self.onUpdatedItineraryComplete) self.onUpdatedItineraryComplete(); _restoreTimeout = setTimeout(function () { restorePersistedMessages(); }, 3000); }); } catch (e) { if (self.onUpdatedItineraryComplete) self.onUpdatedItineraryComplete(e); } }; // Called by HUB when itineraries has been updated /* istanbul ignore next */ MicroServiceBusNode.prototype.UpdateItinerary = function (flowServiceUri) { try { self.onLog(); self.onLog("Updating flows".green); self.onLog(); // Stop all services stopAllServices(function () { self.onLog("All services stopped".yellow); }); getItinerary(flowServiceUri) .then((updatedItinerary) => { // remove from current list for (var i = _itineraries.length; i--;) { if (_itineraries[i].itineraryId === updatedItinerary.itineraryId) { _itineraries.splice(i, 1); } } // add updated itinerary _itineraries.push(updatedItinerary); // start it up startAllServices(_itineraries, function () { if (self.onUpdatedItineraryComplete) self.onUpdatedItineraryComplete(); _restoreTimeout = setTimeout(function () { restorePersistedMessages(); }, 3000); }); }) .catch((e) => { if (self.onUpdatedItineraryComplete) self.onUpdatedItineraryComplete(e); }); } catch (e) { if (self.onUpdatedItineraryComplete) self.onUpdatedItineraryComplete(e); } }; // Called by HUB when itineraries has been updated MicroServiceBusNode.prototype.Stop = function (callback) { self.onLog(); self.onLog("Stopping".green); self.onLog(); // Stop all services stopAllServices(function () { self.onLog("All services stopped".yellow); callback(); }); }; // Called by HUB when itineraries has been updated MicroServiceBusNode.prototype.ChangeState = function (state, callback) { self.onLog(); //_isWaitingForSignInResponse = false; settingsHelper.settings.state = state; if (state === "Active") { _downloadedScripts = []; self._microServices = []; self.onLog("Starting up COM and all services..."); startAllServices(_itineraries, function () { self.onLog("State:".white + state.green); self.onLog(); if (callback) { callback(); } }); } else { self.onLog("Stopping COM and all services..."); com.Stop(function (err) { if (err) { self.onLog("Unalble to start COM"); if (callback) { callback("Unalble to start COM"); } } else { stopAllServices(function () { self.onLog("All services stopped".yellow); self.onLog("State:".white + state.yellow); self.onLog(); if (callback) { callback(); } }); } }); } }; // Called by HUB when itineraries has been updated MicroServiceBusNode.prototype.RestartCom = function (callback) { self.onLog(); self.onLog("Restarting COM".yellow); self.onLog(); com.Stop(() => { self.onLog("COM stopped".yellow); com.Start(() => { self.onLog("COM started".green); callback(); }) }); }; MicroServiceBusNode.prototype.UpdateComState = function (state, callback) { return new Promise((resolve, reject) => { if (settingsHelper.settings.state !== "Active") { com.Start((error) => { if (error) { self.onLog(`Unable to start COM. ${error}`.red); reject(error); } else { self.onLog("COM started successfully".green); resolve(); } com.ChangeState(state, null, (error) => { if (error) { self.onLog(`Unable to update state. ${error}`.red); reject(error); } else { self.onLog("State updated successfully".green); resolve(); } }); }); } else { com.ChangeState(state, null, (error) => { if (error) { reject(error); } else { resolve(); } }); } }); }; // New token has been received from mSB.com MicroServiceBusNode.prototype.UpdateToken = function (token) { settingsHelper.settings.sas = token; settingsHelper.save(); _eventHistoryCollection.push(false, 'Token updated'); }; // Called by the HUB when disabling/enabling flow /* istanbul ignore next */ MicroServiceBusNode.prototype.UpdateFlowState = async function (itineraryId, environment, enabled) { return new Promise(async (resolve, reject) => { var itinerary = _itineraries.find(function (i) { return i.itineraryId === itineraryId; }); if (!itinerary) { self.onLog("Tracking: ".white + "Itinerary not found".red); } if (enabled) { // Remove old itinerary let oldItinerary = _itineraries.find(function (i) { return i.itineraryId === itineraryId; }); var index = _itineraries.indexOf(oldItinerary); if (index > -1) { _itineraries.splice(index, 1); } // Add updated itinerary itinerary.enabled = true; _itineraries.push(itinerary); // Restart all services startAllServices(_itineraries, function () { }); } else { let iStatus = enabled ? "enabled".green : "disabled".yellow; self.onLog(); self.onLog("Itinerary [".grey + itinerary.integrationName + "] has been ".grey + iStatus); itinerary.enabled = enabled; // Get all activities from itinerary var microServices = []; for (var i = 0; i < itinerary.activities.length; i++) { if (itinerary.activities[i].userData.config != undefined) { var host = itinerary.activities[i].userData.config.generalConfig.find(function (c) { return c.id === 'host'; }).value; if (host == settingsHelper.settings.nodeName) { microServices.push({ itinerary: itinerary, activity: itinerary.activities[i] }); } else if (settingsHelper.settings.tags !== undefined) { var tags = settingsHelper.settings.tags.find(function (tag) { return tag === host; }); if (tags !== undefined && tags.length > 0) { if (itinerary.activities[i].userData.baseType === 'onewayreceiveadapter' || itinerary.activities[i].userData.baseType === 'twowayreceiveadapter') { itinerary.activities[i].userData.config.generalConfig.find(function (c) { return c.id === 'host'; }).value = settingsHelper.settings.nodeName; } microServices.push({ itinerary: itinerary, activity: itinerary.activities[i] }); } } } } self.onLog("|" + util.padLeft("", 39, '-') + "|-----------|" + util.padLeft("", 50, '-') + "|"); self.onLog("|" + util.padRight(" MicroService", 39, ' ') + "| Status |" + util.padRight(" Flow", 50, ' ') + "|"); self.onLog("|" + util.padLeft("", 39, '-') + "|-----------|" + util.padLeft("", 50, '-') + "|"); let activeActivities = itinerary.activities.find(function (a) { return a.userData.config.generalConfig.find(function (c) { return c.id === 'enabled'; }).value; }); let activeActivitiesLength = activeActivities ? activeActivities.length : 0; serviceCount = serviceCount - activeActivitiesLength; for (var i = 0; i < microServices.length; i++) { let service = self._microServices.find(function (m) { return m.Name === microServices[i].activity.userData.id; }); if (service) { let serviceStatus = "Stopped".yellow; try { if (enabled && service.Config.general.enabled) { serviceStatus = "Started".green; if (service.StartAsync) { await service.StartAsync(); } else { service.Start(); } serviceCount++; } else { if (service.StopAsync) { await service.StopAsync(); } else { service.Stop(); } var index = self._microServices.indexOf(service); if (index > -1) { self._microServices.splice(index, 1); } } let lineStatus = formatServiceStatus(service.Name, service.Version, serviceStatus, service.IntegrationName, service.Environment); self.onLog(lineStatus); } catch (ex) { self.onLog('Unable to stop '.red + service.Name.red); self.onLog(ex.message.red); } } } } self.onLog(); resolve(); }); }; // Called by HUB to enable or disable tracking MicroServiceBusNode.prototype.SetTracking = function (enableTracking) { settingsHelper.settings.enableTracking = enableTracking; if (enableTracking) self.onLog("Tracking: ".white + "enabled".green); else self.onLog("Tracking: ".white + "disabled".yellow); }; // Update debug mode MicroServiceBusNode.prototype.ChangeDebug = function (debug) { self.onLog("Debug: ".white + debug); settingsHelper.settings.debug = debug; }; // Incoming message from HUB MicroServiceBusNode.prototype.SendMessage = function (message, destination) { //receiveMessage(message, destination); }; // Called by HUB when signin has been successful MicroServiceBusNode.prototype.SignInComplete = function (response) { let coreVersion = response.coreVersion; if (response.tags && response.tags.find(function (t) { return t === "#BETA"; })) { coreVersion = "beta"; } else if (response.tags && response.tags.find(function (t) { return t.toLowerCase() === "#experimental"; })) { coreVersion = "experimental"; } if (response.sas != undefined) { settingsHelper.settings.sas = response.sas; settingsHelper.settings.debug = undefined; settingsHelper.settings.state = undefined; settingsHelper.settings.port = undefined; settingsHelper.settings.tags = undefined; settingsHelper.settings.offlineSettings = response.policies.disconnectPolicy.offlineMode ? response : null; settingsHelper.settings.policies = response.policies; settingsHelper.settings.coreVersion = coreVersion; settingsHelper.save(); } if (settingsHelper.settings.debug != null && settingsHelper.settings.debug == true) {// jshint ignore:line self.onLog(settingsHelper.settings.nodeName.gray + ' successfully logged in'.green); } signInResponse = response; settingsHelper.settings.state = response.state; settingsHelper.settings.nodeDescription = response.nodeDescription; settingsHelper.settings.debug = response.debug; settingsHelper.settings.port = response.port == null ? 80 : response.port; settingsHelper.settings.tags = response.tags; settingsHelper.settings.enableTracking = response.enableTracking; settingsHelper.settings.timezone = response.timezone; settingsHelper.settings.policies = response.policies; settingsHelper.settings.isManaged = response.isManaged; settingsHelper.settings.location = response.location; settingsHelper.retentionPeriod = response.retentionPeriod; settingsHelper.mode = response.mode; _comSettings = response; _persistHelper = new PersistHelper(settingsHelper); if (settingsHelper.settings.enableTracking) self.onLog("Tracking: " + "Enabled".green); else self.onLog("Tracking: " + "Disabled".grey); if (settingsHelper.settings.state == "Active") self.onLog("State: " + settingsHelper.settings.state.green); else self.onLog("State: " + settingsHelper.settings.state.yellow); _applicationinsights.init(response.instrumentationKey, settingsHelper.settings.nodeName) .then(function (resp) { if (resp) self.onLog("Application Insights:" + " Successfully initiated".green); else self.onLog("Application Insights:" + " Disabled".grey); }, function (error) { self.onLog("Application Insights:" + " Failed to initiate!".green); }); if (_firstStart) { _firstStart = false; if (settingsHelper.settings.policies.backgroundServicePolicy && settingsHelper.settings.policies.backgroundServicePolicy.backgroundService) { startBackgroundService(settingsHelper.settings.policies.backgroundServicePolicy.backgroundService); } self.onLog("IoT Provider: " + response.protocol.green); com = new Com(settingsHelper.settings.nodeName, response, settingsHelper.settings.hubUri, settingsHelper); // New state received from IoT Hob com.OnStateReceived(function (stateMessage) { receiveState(stateMessage); }); // Inbound D2C message has no destination com.OnMessageReceived(function (cloudMessage, context) { receiveCloudMessage(cloudMessage, context); }); // InboundD2D message with destination (service) defined com.OnQueueMessageReceived(function (sbMessage) { var message = sbMessage.body; var service = sbMessage.applicationProperties.value.service; receiveMessage(message, service); if (com.IsConnected()) { // com is no longer in disconnected state com.dissconnectedSince = undefined; com.receivedQueueErrorCount = 0; self.onLog("COM seems to have recovered from disconnected state".green); restorePersistedMessages(); } }); /* * Unable to download NPM package * Unable to connect * Receiver error * Unable to get twin * Uncaught exception in start * Error changing state * Service is stopped * Unable to connect to Azure IoT Hub (send) * * Unable to aquire tracking token * Device twin not registered * Unable to send tracking message */ com.OnReceivedQueueError(function (message) { self.onLog("OnReceivedQueueError: ".red + message); }); // Unauthorized error on connecting receiver com.OnUnauthorizedError(function () { if (settingsHelper.isOffline) { if (com.IsConnected()) { self.onLog("Ignoring Unauthorized error as the node is offline. Stopping COM".red); com.Stop(() => { }); } return; } self.onLog("OnUnauthorizedError".red); self.onAction({ action: "restart" }); _eventHistoryCollection.push(false, 'Unauthorized error'); }); /* * Event has been sent to Azure IoT Hub * If com was not intentially stopped or the dissconnect event was triggered * com will continue trying to submit messages */ com.OnSubmitQueueSuccess(function (data) { // if (com.dissconnectedSince) { // com is no longer in disconnected state // com.dissconnectedSince = undefined; // com.receivedQueueErrorCount = 0; // self.onLog("COM seems to have recovered from disconnected state".green); // } _historyCollection.push(true); }); /* * Unable to send event to Azure IoT Hub */ com.OnSubmitQueueError(function (message) { self.onLog("OnSubmitQueueError: ".red + message); recoverDisconnectedComState(); _failedHistoryCollection.push(false); }); // Debug callback from services com.OnQueueDebugCallback(function (message) { if (settingsHelper.settings.debug != null && settingsHelper.settings.debug == true) {// jshint ignore:line self.onLog("COM: ".green + message); } else { console.log("COM: ".green + message); } }); // Disconnect event was triggered com.OnDisconnect(function (message, isFault) { if (settingsHelper.settings.debug != null && settingsHelper.settings.debug == true) {// jshint ignore:line if (isFault) { self.onLog("COM: ".yellow + "Uncontrolled disconnect.".red); } else { self.onLog("COM: ".yellow + message); } } if (isFault) { recoverDisconnectedComState(); } triggerConnectionState(false, "IoT Hub"); _eventHistoryCollection.push(false, 'Dissconnected'); }); com.OnConnect(function () { triggerConnectionState(true, "IoT Hub"); }); com.OnActionCallback(function (message) { if (message.source == "core") { switch (message.action) { default: self.onLog("Unsupported action: " + message.action); break; } } else { if (self.onAction) { self.onAction(message); } } }); // Persistance stuff com.OnPersistEventCallback(function (message) { _persistHelper.persist(message, 'event', function (err) { self.onLog("COM: Message persisted.".yellow); }); }); com.OnPersistMessageCallback(function (message) { _persistHelper.persist(message, 'message', function (err) { }); }); com.OnPersistTrackingCallback(function (message) { _persistHelper.persist(message, 'tracking', function (err) { }); }); com.OnPersistHistoryCallback(function (message) { _persistHelper.persist(message, 'history', function (err) { }); }); port = process.env.PORT || 1337; } else { com.Update(response); } getItineraries(response) .then(() => { startAllServices(_itineraries, function () { self.onPingResponse(); _restoreTimeout = setTimeout(function () { restorePersistedMessages(); }, 3000); }); }) .catch(() => { }) }; // Called by HUB when node has been successfully created /* istanbul ignore next */ MicroServiceBusNode.prototype.NodeCreated = function () { if (settingsHelper.settings.aws) { // AWS var awsSettings = { region: settingsHelper.settings.aws.region }; let pemPath = path.resolve(settingsHelper.certDirectory, settingsHelper.settings.nodeName + ".cert.pem"); let privateKeyPath = path.resolve(settingsHelper.certDirectory, settingsHelper.settings.nodeName + ".private.key"); let settingsPath = path.resolve(settingsHelper.certDirectory, settingsHelper.settings.nodeName + ".settings"); let caRootPath = path.resolve(settingsHelper.certDirectory, ".root-ca.crt"); fs.writeFileSync(pemPath, settingsHelper.settings.aws.certificatePem); fs.writeFileSync(privateKeyPath, settingsHelper.settings.aws.privateKey); fs.writeFileSync(settingsPath, JSON.stringify(awsSettings)); var caUri = "https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem"; self.onLog("AWS node certificates installed"); // TEST request(caUri, function (err, response, certificateContent) { if (response.statusCode != 200 || err != null) { self.onLog("unable to get aws root certificate"); } else { self.onLog("AWS root certificate installed"); fs.writeFileSync(caRootPath, certificateContent); self.SignIn(); } }); } else if (settingsHelper.settings.google) { let googlePrivKeyPath = path.resolve(settingsHelper.certDirectory, settingsHelper.settings.nodeName + ".google.key"); self.settingsHelper.settings.google.privateKeyFile = googlePrivKeyPath; fs.writeFileSync(googlePrivKeyPath, settingsHelper.settings.google.privateKey); self.onLog("Google certificate installed"); self.SignIn(); } else { self.SignIn(); } }; // Signing in the to HUB MicroServiceBusNode.prototype.SignIn = function (newNodeName, temporaryVerificationCode, useMacAddress, recoveredSignIn, useAssert) { if (useMacAddress) { try { let macAddress = util.getMacs(); self.onLog(`mac: ${macAddress}`); self.onCreateNodeFromMacAddress(macAddress.join(',')); } catch (macErr) { self.onLog('Unable to fetch mac address.'); } } else if (useAssert) { self.onLog("Fetching device information, please hold...".yellow); let ImeiLoginHandler = require('./ImeiLoginHandler'); let imeiLoginHandler = new ImeiLoginHandler(this.settingsHelper); imeiLoginHandler.tryGetIMEI(function (imei) { require('msb-network').get_interfaces_list(function (err, nw) { let hostName = require('os').hostname(); let request = { hostName: hostName, ipAddresses: nw.map(i => i.ip_address).filter(i => i).join(", "), macAddresses: nw.map(i => i.mac_address).filter(i => i).join(", "), imei: imei, isModule: Com.IsModule(), parentName: Com.IsModule() ? Com.GetParentName() : undefined } self.onAssertNode(request); }); }); } // Logging in using code else if (settingsHelper.settings.nodeName == null || settingsHelper.settings.nodeName.length == 0) { // jshint ignore:line if (temporaryVerificationCode != undefined && temporaryVerificationCode.length == 0) { // jshint ignore:line self.onLog('No hostname or temporary verification code has been provided.'); } else { this.onCreateNode( temporaryVerificationCode, _hostPrefix, newNodeName ); } } // Logging in using settings else { let ImeiLoginHandler = require('./ImeiLoginHandler'); let imeiLoginHandler = new ImeiLoginHandler(this.settingsHelper); imeiLoginHandler.tryGetIMEI(function (imei) { let RaucHandler = require('./RaucHandler'); let raucHandler = new RaucHandler(); var firmwareState = {}; raucHandler.raucGetSlotStatus((err, raucState) => { if (!err) { let arrayToObject = (array) => array.reduce((obj, item) => { obj[item.key] = item.val return obj }, {}) firmwareState = { rootfs0: arrayToObject(raucState.rootfs0), rootfs1: arrayToObject(raucState.rootfs1) }; } require('msb-network').get_interfaces_list((err, nw) => { var hostData = { id: "", connectionId: "", Name: settingsHelper.settings.nodeName, machineName: settingsHelper.settings.machineName, imei: imei, OrganizationID: settingsHelper.settings.organizationId, npmVersion: self.nodeVersion, sas: settingsHelper.settings.sas, recoveredSignIn: recoveredSignIn, ipAddresses: nw.map(i => i.ip_address).filter(i => i), macAddresses: nw.map(i => i.mac_address).filter(i => i), firmwareState: firmwareState }; self.onSignedIn(hostData); if (settingsHelper.settings.debug != null && settingsHelper.settings.debug && !recoveredSignIn) {// jshint ignore:line self.onLog("Waiting for signin response".grey); } }) }); }); } }; MicroServiceBusNode.prototype.InboundServices = function () { return self._microServices; }; MicroServiceBusNode.prototype.RestorePersistedMessages = function () { restorePersistedMessages(); }; MicroServiceBusNode.prototype.ServiceCountCheck = function () { serviceCountCheck(); }; MicroServiceBusNode.prototype.SetDebug = function (debug) { self.onLog(debug ? "Debug: ".white + "enabled".green : "Debug: ".white + "disabled".yellow); settingsHelper.settings.debug = debug; }; MicroServiceBusNode.prototype.TrackException = function (msg, lastActionId, status, fault, faultDescription) { trackException(msg, lastActionId, status, fault, faultDescription); }; MicroServiceBusNode.prototype.ResendHistory = function (startdate, enddate) { restorePersistedHistoryMessages(startdate, enddate); }; MicroServiceBusNode.prototype.RequestHistory = function (startdate, enddate, connId) { _historyCollection.filterCollection(startdate, enddate, 'hour', function (err, historyCollection) { _failedHistoryCollection.filterCollection(startdate, enddate, 'hour', function (err, failedHistoryCollection) { _eventHistoryCollection.filterCollection(startdate, enddate, 'hour', function (err, eventHistoryCollection) { if (self.onRequestHistory) self.onRequestHistory({ connId: connId, history: historyCollection, failed: failedHistoryCollection, events: eventHistoryCollection }); }); }); }); }; /* istanbul ignore next */ MicroServiceBusNode.prototype.ForceStop = function (callback) { stopAllServices(function () { self.onLog("All services stopped".yellow); callback(); }); }; MicroServiceBusNode.prototype.ReportEvent = function (event) { _eventHistoryCollection.push(false, event); }; MicroServiceBusNode.prototype.ReportConnectionEvent = function (connected, source) { triggerConnectionState(connected, source); } /* istanbul ignore next */ MicroServiceBusNode.prototype.RunTest = function (testDescription) { try { stopAllServices(function () { self.onLog("All services stopped".yellow); var testDirectory = path.resolve(settingsHelper.homeDirectory, "tests"); if (!fs.existsSync(testDirectory)) { fs.mkdirSync(testDirectory); } let files = JSON.parse(testDescription.config).config.dependenciesConfig.map(function (depFile) { return settingsHelper.settings.hubUri.replace('wss://', 'https://') + '/api/Scripts/' + depFile.organizationId + '/' + depFile.name }); var testScriptPath = path.resolve(testDirectory, testDescription.fileName); async.eachSeries(files, function (fileName, done) { // TEST request(fileName, function (err, response, scriptContent) { if (response.statusCode != 200 || err != null) { done("Unable to download test"); } else { try { let dependancyFilePath = path.resolve(testDirectory, path.basename(fileName)); fs.writeFileSync(dependancyFilePath, scriptContent); done(); } catch (err) { done(err); } } }); }, function (err) { if (err) { let errorMessage = "Unable to download dependancy files"; self.onTestResult({ description: "Init test", title: "Download test script", result: errorMessage, code: -1, success: false }); self.onLog(errorMessage); } else { let scriptFileUri = settingsHelper.settings.hubUri + '/api/Scripts/' + settingsHelper.settings.organizationId + '/' + testDescription.fileName; scriptFileUri = scriptFileUri.replace('wss://', 'https://'); // TEST webRequest(scriptFileUri, function (err, response, scriptContent) { if (response.statusCode != 200 || err != null) { let errorMessage = "Unable to download test"; self.onTestResult({ description: "Init test", title: "Download test script", result: errorMessage, code: -1, success: false }); self.onLog(errorMessage); } else { // Add properties scriptContent += "var testParameters = " + JSON.stringify(testDescription.parameters) + ";"; // Add functions scriptContent += "var getPropertyValue = function (propertyName) {let prop = testParameters.find(function (p) { return p.id === propertyName; }); return prop.value;};" fs.writeFileSync(testScriptPath, scriptContent); let Mocha = require('mocha'); global.microServiceBus = { utils: util, log: self.onLog, converter: _unitConverter }; let mocha = new Mocha(); mocha.addFile(testScriptPath); let testCount = 0; let runner = mocha.run(function (failures) { self.onTestComplete({ testCount: testCount, failures: failures, caller: testDescription.caller }); }); runner.on("pass", function (e) { testCount++; let result = { title: e.title, description: e.parent.title, result: "Passed", code: 0, success: true, caller: testDescription.caller }; self.onTestResult(result); self.onLog(e.parent.title + ":" + e.title + "PASSED"); }); runner.on("fail", function (e) { testCount++; let result = { description: e.parent.title, title: e.title, result: e.err.message, code: e.err.code, success: false, caller: testDescription.caller }; self.onTestResult(result); self.onLog(e.parent.title + ":" + e.title + "FAILED".red); self.onLog(JSON.stringify(e.stack)); }); } }); } }); }); } catch (error2) { self.onLog(error2.message); } }; // Events MicroServiceBusNode.prototype.OnSignedIn = function (callback) { this.onSignedIn = callback; }; MicroServiceBusNode.prototype.OnStarted = function (callback) { this.onStarted = callback; }; MicroServiceBusNode.prototype.OnStopped = function (callback) { this.onStopped = callback; }; MicroServiceBusNode.prototype.OnPingResponse = function (callback) { this.onPingResponse = callback; }; MicroServiceBusNode.prototype.OnUpdatedItineraryComplete = function (callback) { this.onUpdatedItineraryComplete = callback; }; MicroServiceBusNode.prototype.OnLog = function (callback) { this.onLog = callback; }; MicroServiceBusNode.prototype.OnAction = function (callback) { this.onAction = callback; }; MicroServiceBusNode.prototype.OnCreateNode = function (callback) { this.onCreateNode = callback; }; MicroServiceBusNode.prototype.OnCreateNodeFromMacAddress = function (callback) { this.onCreateNodeFromMacAddress = callback; }; MicroServiceBusNode.prototype.OnAssertNode = function (callback) { this.onAssertNode = callback; }; MicroServiceBusNode.prototype.OnReportLocation = function (callback) { this.onReportLocation = callback; }; MicroServiceBusNode.prototype.OnRequestHistory = function (callback) { this.onRequestHistory = callback; }; MicroServiceBusNode.prototype.PersistEvent = function (event) { _eventHistoryCollection.push(false, event); }; MicroServiceBusNode.prototype.OnTestResult = function (callback) { this.onTestResult = callback; }; MicroServiceBusNode.prototype.OnTestComplete = function (callback) { this.onTestComplete = callback; }; MicroServiceBusNode.prototype.OnUnitTestComplete = function (callback) { this.onUnitTestComplete = callback; }; MicroServiceBusNode.prototype.OnUpdateFirmware = function (callback) { this.onUpdateFirmware = callback; }; // Internal functions // Starting up all services function startAllServices(itineraries, callback) { stopAllServices(function () { loadItineraries(settingsHelper.settings.organizationId, itineraries, function () { callback(); }); }); } // This method is called then COM gets dissconnected or when unable to // transmit messages or events. function recoverDisconnectedComState(message) { if (!com.dissconnectedSince) { com.dissconnectedSince = new Date(); self.onLog("COM is in disconnected state!!".red); setInterval(function () { try { if (!com.IsConnected() && settingsHelper.settings.state === "Active") { self.onLog("Trying to recover COM from disconnected state".yellow); com.Stop(function () { self.onLog("COM has been stopped".yellow); com.Start(function (err) { if (err) { self.onLog("Still trying to recover COM from disconnected state".yellow); } }); }); } else if (!com.IsConnected() && settingsHelper.settings.state !== "Active") { self.onLog("Terminating recover from disconnected state".yellow); com.dissconnectedSince = undefined; clearInterval(this); } else { self.onLog("COM seems to have recovered from disconnected state".green); com.dissconnectedSince = undefined; clearInterval(this); restorePersistedMessages(); } } catch (e) { self.onLog("Error in interval for restarting COM: " + e); } }, 10 * 1000); let msg = { InterchangeId: guid.v1(), IntegrationId: "", IntegrationName: "", Environment: "", TrackingLevel: "", ItineraryId: "", CreatedBy: "", LastActivity: "", ContentType: "text/plain", Itinerary: "", MessageBuffer: null,//messageBuffer.toString('base64'), _messageBuffer: new Buffer("").toString('base64'), IsBinary: true, IsLargeMessage: false,