/** * @module node-opcua-client */ import chalk from "chalk"; import { assert } from "node-opcua-assert"; import type { UInt32 } from "node-opcua-basic-types"; import type { TimestampsToReturn } from "node-opcua-data-value"; import { checkDebugFlag, make_debugLog } from "node-opcua-debug"; import { CreateMonitoredItemsRequest, type CreateMonitoredItemsResponse, ModifyMonitoredItemsRequest, ModifyMonitoredItemsResponse, MonitoredItemModifyRequest, type MonitoredItemModifyResult, type MonitoringMode, type SetMonitoringModeResponse } from "node-opcua-service-subscription"; import type { Callback, ErrorCallback, StatusCode } from "node-opcua-status-code"; import type { MonitoredItemCreateRequestOptions, MonitoringParametersOptions } from "node-opcua-types"; import type { ClientMonitoredItemBase } from "./client_monitored_item_base"; import type { SetMonitoringModeRequestLike } from "./client_session"; import type { ClientSubscription } from "./client_subscription"; import type { ClientMonitoredItemImpl } from "./private/client_monitored_item_impl"; import type { ClientSessionImpl } from "./private/client_session_impl"; const debugLog = make_debugLog(__filename); const _doDebug = checkDebugFlag(__filename); export interface ClientMonitoredItemBaseEx extends ClientMonitoredItemBase { internalSetMonitoringMode(monitoringMode: MonitoringMode): void; } /** * @internal */ export namespace ClientMonitoredItemToolbox { export function _toolbox_monitor( subscription: ClientSubscription, timestampsToReturn: TimestampsToReturn, monitoredItems: ClientMonitoredItemBase[], done: ErrorCallback ): void { assert(typeof done === "function"); // we expect subscription to be valid and have a valid session if (!subscription.hasSession) { const err0 = new Error("Invalid subscription"); done(err0); return; } // may be the subscription has been terminated or is not fully initialize, in the meantime if (!subscription.isActive) { const err1 = new Error("Subscription has been terminated or is not fully initialized"); done(err1); return; } const itemsToCreate: MonitoredItemCreateRequestOptions[] = []; for (const monitoredItem of monitoredItems) { const monitoredItemI = monitoredItem as ClientMonitoredItemImpl; const itemToCreate = monitoredItemI._prepare_for_monitoring(); if (typeof itemToCreate.error === "string") { done(new Error(itemToCreate.error)); return; } itemsToCreate.push(itemToCreate as MonitoredItemCreateRequestOptions); } const createMonitorItemsRequest = new CreateMonitoredItemsRequest({ itemsToCreate, subscriptionId: subscription.subscriptionId, timestampsToReturn }); for (let i = 0; i < monitoredItems.length; i++) { const monitoredItem = monitoredItems[i] as ClientMonitoredItemImpl; monitoredItem._before_create(); } const session = subscription.session as ClientSessionImpl; assert(session, "expecting a valid session attached to the subscription "); session.createMonitoredItems(createMonitorItemsRequest, (err?: Error | null, response?: CreateMonitoredItemsResponse) => { /* c8 ignore next */ if (err) { debugLog(chalk.red("ClientMonitoredItemBase#_toolbox_monitor: ERROR in createMonitoredItems ", err.message)); } else { /* c8 ignore next */ if (!response) { return done(new Error("Internal Error")); } response.results = response.results || []; for (let i = 0; i < response.results.length; i++) { const monitoredItemResult = response.results[i]; const monitoredItem = monitoredItems[i] as ClientMonitoredItemImpl; monitoredItem._after_create(monitoredItemResult); } } done(err ? err : undefined); }); } export function _toolbox_modify( subscription: ClientSubscription, monitoredItems: ClientMonitoredItemBase[], parameters: MonitoringParametersOptions, timestampsToReturn: TimestampsToReturn, callback: Callback ): void { assert(callback === undefined || typeof callback === "function"); const itemsToModify = monitoredItems.map((monitoredItem: ClientMonitoredItemBase) => { const clientHandle = monitoredItem.monitoringParameters.clientHandle; assert(clientHandle !== 4294967295); return new MonitoredItemModifyRequest({ monitoredItemId: monitoredItem.monitoredItemId, requestedParameters: { ...parameters, clientHandle } }); }); const modifyMonitoredItemsRequest = new ModifyMonitoredItemsRequest({ itemsToModify, subscriptionId: subscription.subscriptionId, timestampsToReturn }); const session = subscription.session as ClientSessionImpl; assert(session, "expecting a valid session attached to the subscription "); session.modifyMonitoredItems(modifyMonitoredItemsRequest, (err: Error | null, response?: ModifyMonitoredItemsResponse) => { /* c8 ignore next */ if (err) { callback(err); return; } if (!response || !(response instanceof ModifyMonitoredItemsResponse)) { callback(new Error("internal error")); return; } response.results = response.results || []; assert(response.results.length === monitoredItems.length); const res = response.results[0]; /* c8 ignore next */ if (response.results.length === 1 && res.statusCode.isNotGood()) { callback(new Error(`Error${res.statusCode.toString()}`)); return; } callback(null, response.results); }); } export function _toolbox_setMonitoringMode( subscription: ClientSubscription, monitoredItems: ClientMonitoredItemBaseEx[], monitoringMode: MonitoringMode, callback: Callback ): void { const monitoredItemIds = monitoredItems.map((monitoredItem) => monitoredItem.monitoredItemId as UInt32); const setMonitoringModeRequest: SetMonitoringModeRequestLike = { monitoredItemIds, monitoringMode, subscriptionId: subscription.subscriptionId }; const session = subscription.session as ClientSessionImpl; assert(session, "expecting a valid session attached to the subscription "); session.setMonitoringMode(setMonitoringModeRequest, (err: Error | null, response?: SetMonitoringModeResponse) => { if (err) { callback(err); return; } if (!response) { callback(new Error("internal error")); return; } monitoredItems.forEach((monitoredItem) => { monitoredItem.internalSetMonitoringMode(monitoringMode); }); response.results = response.results || []; callback(null, response.results); }); } }