node-red-contrib-iiot-opcua
Version:
An Industrial IoT OPC UA toolbox contribution package for Node-RED based on node-opcua.
276 lines (273 loc) • 12.6 kB
JavaScript
/*
The BSD 3-Clause License
Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
Copyright 2015,2016 - Mika Karaila, Valmet Automation Inc. (node-red-contrib-opcua)
All rights reserved.
node-red-contrib-iiot-opcua
*/
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const opcua_iiot_core_1 = require("./core/opcua-iiot-core");
const opcua_iiot_core_browser_1 = __importDefault(require("./core/opcua-iiot-core-browser"));
const assertion_1 = require("./types/assertion");
/**
* Crawler Node-RED nodeConfig.
*
* @param RED
*/
module.exports = (RED) => {
// SOURCE-MAP-REQUIRED
function OPCUAIIoTCrawler(config) {
RED.nodes.createNode(this, config);
this.name = config.name;
this.justValue = config.justValue;
this.singleResult = config.singleResult;
this.showStatusActivities = config.showStatusActivities;
this.showErrors = config.showErrors;
this.activateUnsetFilter = config.activateUnsetFilter;
this.activateFilters = config.activateFilters;
this.negateFilter = config.negateFilter;
this.filters = config.filters;
this.delayPerMessage = config.delayPerMessage || 0.2;
this.timeout = config.timeout || 30;
this.connector = RED.nodes.getNode(config.connector);
let self = this;
const { iiot, browseTopic } = opcua_iiot_core_browser_1.default.initBrowserNode();
self.browseTopic = browseTopic;
self.iiot = iiot;
self.iiot.delayMessageTimer = [];
const filterCrawlerResults = function (crawlerResultToFilter) {
let crawlerResult = crawlerResultToFilter || [];
let filteredEntries = [];
if (self.activateFilters && self.filters && self.filters.length > 0) {
crawlerResult.forEach(function (item) {
if (itemIsNotToFilter(item)) {
filteredEntries.push(item);
}
});
crawlerResult = filteredEntries;
}
if (self.justValue) {
crawlerResult.forEach(function (item) {
if (item.references) {
delete item['references'];
}
});
}
return crawlerResult;
};
const itemIsNotToFilter = function (item) {
let result = (0, opcua_iiot_core_1.checkItemForUnsetState)(self, item);
if (result) {
result = self.filters.every((element) => {
return (0, opcua_iiot_core_1.checkCrawlerItemIsNotToFilter)(self, item, element, result) !== 0;
}) ? 1 : 0;
}
return (self.negateFilter) ? !result : result;
};
const crawl = (session, payload, statusHandler) => __awaiter(this, void 0, void 0, function* () {
if ((0, opcua_iiot_core_1.checkSessionNotValid)(self.connector.iiot.opcuaSession, 'Crawler')) {
return;
}
opcua_iiot_core_browser_1.default.internalDebugLog('Browse Topic To Call Crawler ' + self.browseTopic);
if (self.showStatusActivities && self.oldStatusParameter) {
self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'crawling', self.oldStatusParameter, self.showStatusActivities, statusHandler);
}
opcua_iiot_core_browser_1.default.crawl(session, self.browseTopic, payload, getSendWrapper(payload));
});
const callError = (err, msg) => {
this.error(err, msg);
};
const statusHandler = (status) => {
this.status(status);
};
const crawlForSingleResult = function (session, payload) {
opcua_iiot_core_browser_1.default.crawlAddressSpaceItems(session, payload, getSendWrapper(payload), self.timeout);
};
const handleResultArray = (results, payload) => {
// map each result 1-to-1 input to output
const crawlerResult = results.map(function (result) {
if (result.value instanceof Error) {
return result.value.toString();
}
else {
return filterCrawlerResults(result.value);
}
});
// combine the valid results into payload.value
const value = crawlerResult.filter((result) => {
return !(typeof result === 'string');
}).flatMap((result) => {
return result;
});
// list errors in payload.error
const error = results.filter((result) => {
return (result.value instanceof Error);
}).map((result) => {
return result.value;
});
if (error.length > 0) {
payload.error = error;
}
payload.value = value;
sendMessage(payload, crawlerResult);
};
/**
* Returns a sendWrapper function with the correct payload context
*/
const getSendWrapper = (payload) => {
return (result) => {
if (result.promises) {
handleResultArray(result.crawlerResult, payload);
}
else if (result instanceof Error) {
opcua_iiot_core_browser_1.default.browseErrorHandling(self, result, payload, undefined, callError, statusHandler, self.oldStatusParameter, self.showErrors, self.showStatusActivities);
}
else {
opcua_iiot_core_browser_1.default.internalDebugLog(result.rootNodeId + ' Crawler Results ' + result.crawlerResult.length);
const filteredResults = filterCrawlerResults(result.crawlerResult);
payload.value = [filteredResults];
sendMessage(payload, filteredResults);
}
};
};
const crawlForResults = function (session, payload) {
var _a;
(_a = payload.addressSpaceItems) === null || _a === void 0 ? void 0 : _a.forEach((entry) => {
opcua_iiot_core_browser_1.default.crawl(session, entry.nodeId, payload, getSendWrapper(payload));
});
};
const crawlNodeList = function (session, payload) {
if (self.showStatusActivities && self.oldStatusParameter) {
self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'crawling', self.oldStatusParameter, self.showStatusActivities, statusHandler);
}
if (self.singleResult) {
crawlForSingleResult(session, payload);
}
else {
crawlForResults(session, payload);
}
};
const sendMessage = (payload, crawlerResult) => {
const { _msgid, topic } = payload, restMessage = __rest(payload, ["_msgid", "topic"]);
restMessage.nodetype = 'crawl';
try {
RED.util.setMessageProperty(restMessage, 'crawlerResults', JSON.parse(JSON.stringify(crawlerResult, null, 2)));
}
catch (err) {
opcua_iiot_core_browser_1.default.internalDebugLog(err);
if (self.showErrors) {
this.error(err, restMessage);
}
restMessage.resultsConverted = JSON.stringify(crawlerResult, null, 2);
restMessage.error = err.message;
}
if (self.browseTopic && self.browseTopic !== '') {
restMessage.browseTopic = self.browseTopic;
}
if (restMessage.crawlerResults.length === 1 && (0, assertion_1.isArray)(restMessage.crawlerResults[0])) {
restMessage.crawlerResults = restMessage.crawlerResults[0];
}
if (!self.justValue) {
restMessage.crawlerResultsCount = crawlerResult.length;
if (self.connector) {
restMessage.endpoint = self.connector.endpoint;
}
restMessage.session = self.connector.iiot.opcuaSession.name || 'none';
}
const msg = {
_msgid,
topic,
payload: restMessage
};
self.iiot.messageList.push(msg);
if (self.showStatusActivities && self.oldStatusParameter) {
self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'active', self.oldStatusParameter, self.showStatusActivities, statusHandler);
}
// TODO: maybe here RED.util.set ...
self.iiot.delayMessageTimer.push(setTimeout(() => {
this.send(self.iiot.messageList.shift());
}, self.delayPerMessage * opcua_iiot_core_1.FAKTOR_SEC_TO_MSEC));
};
const resetAllTimer = function () {
self.iiot.delayMessageTimer.forEach((timerId) => {
clearTimeout(timerId);
timerId = null;
});
};
const startCrawling = (payload) => __awaiter(this, void 0, void 0, function* () {
if (!self.connector) {
return;
}
if (self.connector.functions.hasNoSession()) {
yield self.connector.functions.startSession(self.id);
}
if (self.browseTopic && self.browseTopic !== '') {
crawl(self.connector.iiot.opcuaSession, payload, statusHandler);
}
else {
if (payload.addressSpaceItems && payload.addressSpaceItems.length) {
opcua_iiot_core_browser_1.default.internalDebugLog('Start Crawling On AddressSpace Items');
crawlNodeList(self.connector.iiot.opcuaSession, payload);
}
else {
this.error(new Error('No AddressSpace Items Or Root To Crawl'), payload);
}
}
});
const errorHandler = (err, msg) => {
this.error(err, msg);
};
const setStatus = (status) => {
this.status(status);
};
const emitHandler = (msg) => {
this.emit(msg);
};
const onAlias = (event, callback) => {
this.on(event, callback);
};
this.on('input', function (msg) {
const payload = msg.payload;
self.browseTopic = opcua_iiot_core_browser_1.default.extractNodeIdFromTopic(payload, self);
payload._msgid = msg._msgid;
payload.topic = msg.topic;
startCrawling(msg.payload).finally();
});
(0, opcua_iiot_core_1.registerToConnector)(this, setStatus, onAlias, errorHandler);
this.on('close', (done) => {
self.removeAllListeners();
resetAllTimer();
(0, opcua_iiot_core_1.deregisterToConnector)(this, () => {
(0, opcua_iiot_core_1.resetIiotNode)(this);
done();
});
});
}
RED.nodes.registerType('OPCUA-IIoT-Crawler', OPCUAIIoTCrawler);
};
//# sourceMappingURL=opcua-iiot-crawler.js.map