// used to append interfaces to omnicore sdk so that created app and AppStudio can use
import API from './ecosystem-base.js';
import {Logger} from './../function/log-helper.js';
import {ErrorCode} from './../exception/exceptionDesc.js';
import {InfoType, WarningType} from '../information/informationCode.js';
import {Signal, Pending, Success} from '../store/const.js';
import Store from '../store/store.js';
const factoryApiSignalMonitor = function (es) {
const logModule = 'ecosystem-signal';
/**
* The API.SIGNALMONITOR namespace provides a set of interfaces for easily and quickly adds signal monitoring and processing transactions.
* @alias API.SIGNALMONITOR
* @namespace
*/
es.SIGNALMONITOR = new (function () {
const subscribedSignals = {};
const UNASSIGNED_TAG = '%%UNASSIGNED%%';
const subscribeRes = async function (signal, func) {
if (es.isSubscriptionBlocked) {
Logger.w(WarningType.RWSSubscriptionBlocked, 'API.Signal: Subscription disabled when trying to monitor signal');
return;
}
signal.addCallbackOnChanged(func);
await signal.subscribe();
};
this.unsubscribeRes = async function (mappingKey) {
const signalInfo = subscribedSignals[mappingKey];
if (signalInfo && signalInfo.signal) {
signalInfo.signal.unsubscribe();
delete subscribedSignals[mappingKey];
}
};
/**
* Subscribes to a signal.
* @alias monitorSignal
* @memberof API.SIGNALMONITOR
* @param {object} [variableObj] The signal attributes including the signal name and other necessary information.
* @param {function} [callback] The callback function that is called when the signal changes.
*
* @example
* API.SIGNALMONITOR.monitorSignal(
* {type: 'digitalsignal', name: 'ManualMode', network: 'Network1', device: 'Device1'},
* (v)=>{
* console.log(v);
* }
* )
*/
this.monitorSignal = async function (
signalObj = {type: 'digitalsignal', network: '', device: '', name: 'ManualMode'},
callback = null,
) {
const mappingKey = Store.generateMappingKey(Signal, [
signalObj.type,
signalObj.network || UNASSIGNED_TAG,
signalObj.device || UNASSIGNED_TAG,
signalObj.name,
]);
if (es.isFetchControllerBlocked) {
Logger.w(
WarningType.RWSRequestBlocked,
`API.SIGNALMONITOR: HttpRequest disabled when trying to monitor signal ${mappingKey}`,
);
return;
}
// 1.if the variable is not in the store, read its initial value and store it
const {state, value} = Store.getNamespace(Signal).getMapping(mappingKey) || {state: undefined, value: undefined};
if (state === undefined) {
try {
Store.getNamespace(Signal).setMapping(mappingKey, {
state: Pending,
value: undefined,
});
const initialValue = await API.RWS.SIGNAL.getSignalValue(signalObj.name, {
deviceType: signalObj.device,
networkType: signalObj.network,
});
Store.getNamespace(Signal).setMapping(mappingKey, {
state: Success,
value: initialValue,
});
typeof callback === 'function' && callback(initialValue);
es._events.trigger(mappingKey + '_fetch', initialValue);
} catch (error) {
return API.rejectWithStatus(`Failed to read signal ${signalObj.name}'s value before subscription.`, error, {
errorCode: ErrorCode.FailedToGetSignalValue,
});
}
} else if (state === Pending) {
es._events.once(mappingKey + '_fetch', (v) => {
typeof callback === 'function' && callback(v);
});
} else {
typeof callback === 'function' && callback(value);
}
if (es.isSubscriptionBlocked) {
Logger.w(
WarningType.RWSSubscriptionBlocked,
`API.SIGNALMONITOR: Subscription disabled when trying to monitor signal ${mappingKey}`,
);
return;
}
// 2.if the variable is not subscribed yet, subscribe to it
es._events.on(mappingKey, callback);
if (!subscribedSignals[mappingKey]) {
try {
subscribedSignals[mappingKey] = {
state: Pending,
};
const cbDigitalSignal = function (data) {
const validValue = JSON.parse(data.toString() || -1);
Store.getNamespace(Signal).setMapping(mappingKey, {
state: Success,
value: validValue,
});
es._events.trigger(mappingKey, validValue);
Logger.i(InfoType.RobotOperation, `Triggered signal value:${validValue}. The new value is ${validValue}`);
};
const signalData = await API.SIGNAL.getSignal(
signalObj.name,
signalObj.network || UNASSIGNED_TAG,
signalObj.device || UNASSIGNED_TAG,
);
await subscribeRes(signalData.signal, cbDigitalSignal.bind(this));
subscribedSignals[mappingKey].state = Success;
subscribedSignals[mappingKey].signal = signalData.signal;
Logger.i(InfoType.RobotOperation, `Signal subscribed:${mappingKey}`);
} catch (e) {
return API.rejectWithStatus(`Failed to subscribe signal ${signalObj.name}`, e, {
errorCode: ErrorCode.FailedToSubscribeSignal,
});
}
}
};
/**
* Subscribes to a digital signal.
* @deprecated Please use this.monitorSignal instead
* @alias monitorDigitalSignal
* @memberof API.SIGNALMONITOR
* @param {object} [variableObj] The signal attributes including the signal name and other necessary information.
* @param {function} [callback] The callback function that is called when the signal changes.
*
* @example
* API.SIGNALMONITOR.monitorDigitalSignal(
* {type: 'digitalsignal', name: 'ManualMode'},
* (v)=>{
* console.log(v);
* }
* )
*/
this.monitorDigitalSignal = this.monitorSignal;
})();
es.constructedSignalMonitor = true;
};
if (typeof API.constructedSignalMonitor === 'undefined') {
factoryApiSignalMonitor(API);
}
export default API;
export {factoryApiSignalMonitor};