utils.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import merge from "lodash/merge";
  2. import { Socket } from "socket.io-client";
  3. import { IdMessage, storeClientId } from "../../src/context/utils";
  4. import { WsMessage, sendWsMessage } from "../../src/context/wsUtils";
  5. import { TaipyApp } from "./app";
  6. import { DataManager, ModuleData } from "./dataManager";
  7. interface MultipleUpdatePayload {
  8. name: string;
  9. payload: { value: unknown };
  10. }
  11. interface AlertMessage extends WsMessage {
  12. atype: string;
  13. message: string;
  14. }
  15. const initWsMessageTypes = ["ID", "AID", "GMC"];
  16. export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
  17. socket.on("connect", () => {
  18. if (taipyApp.clientId === "" || taipyApp.appId === "") {
  19. taipyApp.init();
  20. }
  21. });
  22. // Send a request to get App ID to verify that the app has not been reloaded
  23. socket.io.on("reconnect", () => {
  24. console.log("WebSocket reconnected")
  25. sendWsMessage(socket, "AID", "reconnect", taipyApp.appId, taipyApp.clientId, taipyApp.context);
  26. });
  27. // try to reconnect on connect_error
  28. socket.on("connect_error", (err) => {
  29. console.log("Error connecting WebSocket: ", err);
  30. setTimeout(() => {
  31. socket && socket.connect();
  32. }, 500);
  33. });
  34. // try to reconnect on server disconnection
  35. socket.on("disconnect", (reason, details) => {
  36. console.log("WebSocket disconnected due to: ", reason, details);
  37. if (reason === "io server disconnect") {
  38. socket && socket.connect();
  39. }
  40. });
  41. // handle message data from backend
  42. socket.on("message", (message: WsMessage) => {
  43. processWsMessage(message, taipyApp);
  44. });
  45. // only now does the socket tries to open/connect
  46. if (!socket.connected) {
  47. socket.connect();
  48. }
  49. };
  50. const processWsMessage = (message: WsMessage, taipyApp: TaipyApp) => {
  51. if (message.type) {
  52. if (message.type === "MU" && Array.isArray(message.payload)) {
  53. for (const muPayload of message.payload as [MultipleUpdatePayload]) {
  54. const encodedName = muPayload.name;
  55. const { value } = muPayload.payload;
  56. taipyApp.variableData?.update(encodedName, value);
  57. taipyApp.onChange && taipyApp.onChange(taipyApp, encodedName, value);
  58. }
  59. } else if (message.type === "ID") {
  60. const { id } = message as unknown as IdMessage;
  61. storeClientId(id);
  62. taipyApp.clientId = id;
  63. taipyApp.updateContext(taipyApp.path);
  64. } else if (message.type === "GMC") {
  65. const mc = (message.payload as Record<string, unknown>).data as string;
  66. window.localStorage.setItem("ModuleContext", mc);
  67. taipyApp.context = mc;
  68. } else if (message.type === "GDT") {
  69. const payload = message.payload as Record<string, ModuleData>;
  70. const variableData = payload.variable;
  71. const functionData = payload.function;
  72. if (taipyApp.variableData && taipyApp.functionData) {
  73. const varChanges = taipyApp.variableData.init(variableData);
  74. const functionChanges = taipyApp.functionData.init(functionData);
  75. const changes = merge(varChanges, functionChanges);
  76. if (varChanges || functionChanges) {
  77. taipyApp.onReload && taipyApp.onReload(taipyApp, changes);
  78. }
  79. } else {
  80. taipyApp.variableData = new DataManager(variableData);
  81. taipyApp.functionData = new DataManager(functionData);
  82. taipyApp.onInit && taipyApp.onInit(taipyApp);
  83. }
  84. } else if (message.type === "AID") {
  85. const payload = message.payload as Record<string, unknown>;
  86. if (payload.name === "reconnect") {
  87. return taipyApp.init();
  88. }
  89. taipyApp.appId = payload.id as string;
  90. } else if (message.type === "GR") {
  91. const payload = message.payload as [string, string][];
  92. taipyApp.routes = payload;
  93. } else if (message.type === "AL" && taipyApp.onNotify) {
  94. const payload = message as AlertMessage;
  95. taipyApp.onNotify(taipyApp, payload.atype, payload.message);
  96. }
  97. postWsMessageProcessing(message, taipyApp);
  98. }
  99. };
  100. const postWsMessageProcessing = (message: WsMessage, taipyApp: TaipyApp) => {
  101. // perform data population only when all necessary metadata is ready
  102. if (
  103. initWsMessageTypes.includes(message.type) &&
  104. taipyApp.clientId !== "" &&
  105. taipyApp.appId !== "" &&
  106. taipyApp.context !== "" &&
  107. taipyApp.routes !== undefined
  108. ) {
  109. sendWsMessage(taipyApp.socket, "GDT", "get_data_tree", {}, taipyApp.clientId, taipyApp.context);
  110. }
  111. };