useSocketConnect.ts 3.98 KB
import { useWebSocket } from '@vueuse/core';
import { Ref, unref } from 'vue';
import { DataBoardLayoutInfo } from '../types/type';
import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
import { getAuthCache } from '/@/utils/auth';
import { isNullAndUnDef } from '/@/utils/is';

interface SocketMessage {
  tsSubCmds: SocketMessageItem[];
}

interface SocketMessageItem {
  entityType: string;
  entityId: string;
  scope: string;
  cmdId: number;
  keys: string;
}

interface CmdMapping {
  componentId: string;
  deviceId: string;
  recordIndex: number;
  dataSourceIndex: number;
  attribute: string;
}

interface ResponseMessage {
  subscriptionId: number;
  errorCode: number;
  errorMsg: Nullable<string>;
  data: {
    [key: string]: [[number, string]];
  };
  latestValues: {
    [key: string]: number;
  };
}

const generateMessage = (deviceId: string, cmdId: number, attr: string): SocketMessageItem => {
  return {
    entityType: 'DEVICE',
    entityId: deviceId,
    scope: 'LATEST_TELEMETRY',
    cmdId,
    keys: attr,
  };
};

export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) {
  const token = getAuthCache(JWT_TOKEN_KEY);

  const cmdIdMapping = new Map<number, CmdMapping>();

  const waitSendQueue: string[] = [];

  const config = {
    server: `${import.meta.env.VITE_WEB_SOCKET}${token}`,
  };

  // const getNeedUpdateValueById = (componentId: string, deviceId: string) => {};

  const getNeedUpdateValueByIndex = (recordIndex: number, dataSourceIndex: number) => {
    return unref(dataSourceRef)[recordIndex].record.dataSource[dataSourceIndex];
  };

  const { close, send, open, status } = useWebSocket(config.server, {
    onConnected() {
      if (waitSendQueue.length) {
        waitSendQueue.forEach((string) => {
          send(string);
        });
        waitSendQueue.length = 0;
      }
    },
    onMessage(_ws, message) {
      try {
        const res: ResponseMessage = JSON.parse(message.data);
        const { subscriptionId, data = {} } = res;
        if (isNullAndUnDef(subscriptionId)) return;
        const mappingRecord = cmdIdMapping.get(subscriptionId);
        if (!mappingRecord) return;
        const { attribute, recordIndex, dataSourceIndex } = mappingRecord;
        const [[timespan, value]] = data[attribute];
        const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex);
        record.componentInfo.value = value;
        record.componentInfo.updateTime = timespan;
      } catch (error) {
        throw Error(error as string);
      }
    },
    // onDisconnected() {
    //   close();
    // },
  });

  const setCmdId = (cmdId: number, record: CmdMapping) => {
    cmdIdMapping.set(cmdId, record);
  };

  const transformSocketMessageItem = () => {
    const messageList: SocketMessageItem[] = [];
    let index = 0;
    unref(dataSourceRef).forEach((record, recordIndex) => {
      const componentId = record.record.id;
      for (
        let dataSourceIndex = 0;
        dataSourceIndex < record.record.dataSource.length;
        dataSourceIndex++
      ) {
        const dataSource = record.record.dataSource[dataSourceIndex];
        const { deviceId, attribute, slaveDeviceId, gatewayDevice } = dataSource;
        if (!attribute) continue;
        const cmdId = index;
        index++;
        setCmdId(cmdId, {
          componentId,
          deviceId: gatewayDevice ? deviceId : slaveDeviceId,
          recordIndex,
          dataSourceIndex,
          attribute,
        });

        messageList.push(
          generateMessage(gatewayDevice ? slaveDeviceId : deviceId, cmdId, attribute)
        );
      }
    });
    return {
      tsSubCmds: messageList,
    } as SocketMessage;
  };

  const beginSendMessage = () => {
    // close();
    cmdIdMapping.clear();

    // open();
    const messageList = transformSocketMessageItem();

    if (unref(status) !== 'OPEN') {
      waitSendQueue.push(JSON.stringify(messageList));
      return;
    }
    send(JSON.stringify(messageList));
  };

  return {
    close,
    send,
    open,
    beginSendMessage,
  };
}