ecosystem-variable.js

// 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 {InfoType, WarningType} from '../information/informationCode.js';
import {ErrorCode} from '../exception/exceptionDesc.js';
import {Rapid, Pending, Success} from '../store/const.js';
import Store from '../store/store.js';

const factoryApiVariableMonitor = function (es) {
  const logModule = 'ecosystem-variable';

  /**
   * The API.VARIABLEMONITOR namespace provides a set of interfaces for easily and quickly adding RAPID variable monitoring and processing transactions
   * @alias API.VARIABLEMONITOR
   * @namespace
   */
  es.VARIABLEMONITOR = new (function () {
    const subscribedVariables = {};

    const subscribeRes = async function (variable, func) {
      if (es.isSubscriptionBlocked) {
        Logger.w(
          WarningType.RWSSubscriptionBlocked,
          'API.VARIABLEMONITOR: Subscription disabled when trying to monitor variable',
        );
        return;
      }
      variable.addCallbackOnChanged(func);
      await variable.subscribe();
    };

    this.unsubscribeRes = async function (mappingKey) {
      const variableInfo = subscribedVariables[mappingKey];
      if (variableInfo && variableInfo.variable) {
        variableInfo.variable.unsubscribe();
        delete subscribedVariables[mappingKey];
      }
    };

    /**
     * Subscribes to a RAPID variable.
     * @alias monitorVariable
     * @memberof API.VARIABLEMONITOR
     * @param {object} [variableObj] The variable attributes including the variable name and other necessary information.
     * @param {function} [callback] The callback function that is called when the variable changes.
     *
     * @example
     * API.VARIABLEMONITOR.monitorVariable(
     *  {type: 'tooldata', task: 'task1', module: 'module1', name: 'Wobj_1'},
     *  (v)=>{
     *    console.log(v);
     *  }
     * )
     */
    this.monitorVariable = async function (
      variableObj = {
        type: 'tooldata',
        task: 'task1',
        module: 'module1',
        name: 'Wobj_1',
      },
      callback = null,
    ) {
      const mappingKey = Store.generateMappingKey(Rapid, [
        variableObj.type,
        variableObj.task,
        variableObj.module,
        variableObj.name,
      ]);

      if (es.isFetchControllerBlocked) {
        Logger.w(
          WarningType.RWSRequestBlocked,
          `API.VARIABLEMONITOR: HttpRequest disabled when trying to monitor variable ${mappingKey}`,
        );
        return;
      }
      const {state, value} = Store.getNamespace(Rapid).getMapping(mappingKey) || {state: undefined, value: undefined};
      // 1.if the variable is not in the store, read its initial value and store it
      if (state === undefined) {
        try {
          Store.getNamespace(Rapid).setMapping(mappingKey, {
            state: Pending,
            value: undefined,
          });
          const initialValue = await API.RWS.RAPID.getVariableRawValue(
            variableObj.module,
            variableObj.name,
            variableObj.task,
          );
          Store.getNamespace(Rapid).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 variable ${variableObj.name}'s value before subscription.`,
            error,
            {errorCode: ErrorCode.FailedToGetVariableValue},
          );
        }
      } 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.VARIABLEMONITOR: Subscription disabled when trying to monitor variable ${mappingKey}`,
        );
        return;
      }

      // 2.if the variable is not subscribed yet, subscribe to it
      es._events.on(mappingKey, callback);
      if (!subscribedVariables[mappingKey]) {
        try {
          subscribedVariables[mappingKey] = {
            state: Pending,
          };
          const cbVariable = function (data) {
            Store.getNamespace(Rapid).setMapping(mappingKey, {
              state: Success,
              value: data,
            });
            es._events.trigger(mappingKey, data);
            Logger.i(logModule, `Triggered :${variableObj.name} - ${data}`);
          };

          const variableData = await RWS.Rapid.getData(variableObj.task, variableObj.module, variableObj.name);
          await subscribeRes(variableData, cbVariable.bind(this));
          subscribedVariables[mappingKey].state = Success;
          subscribedVariables[mappingKey].variable = variableData;

          Logger.i(logModule, `Subscribed variable: ${mappingKey}`);
        } catch (e) {
          return API.rejectWithStatus(`Subscription to ${variableObj.name} failed.`, e, {
            errorCode: ErrorCode.FailedToSubscribeVariable,
          });
        }
      }
    };
  })();

  es.constructedVariableMonitor = true;
};

if (typeof API.constructedVariableMonitor === 'undefined') {
  factoryApiVariableMonitor(API);
}

export default API;
export {factoryApiVariableMonitor};