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
JavaScript
/*
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,