Переглянути джерело

Decouple Acknowledgement (#1477)

* Decouple Acknowledgement

* revert export
Dinh Long Nguyen 10 місяців тому
батько
коміт
d11c2c109b

+ 37 - 7
frontend/taipy-gui/base/src/app.ts

@@ -6,11 +6,13 @@ import { Socket, io } from "socket.io-client";
 import { DataManager, ModuleData } from "./dataManager";
 import { initSocket } from "./socket";
 import { TaipyWsAdapter, WsAdapter } from "./wsAdapter";
+import { WsMessageType } from "./packaging/taipy-gui-base";
 
 export type OnInitHandler = (taipyApp: TaipyApp) => void;
 export type OnChangeHandler = (taipyApp: TaipyApp, encodedName: string, value: unknown) => void;
 export type OnNotifyHandler = (taipyApp: TaipyApp, type: string, message: string) => void;
 export type OnReloadHandler = (taipyApp: TaipyApp, removedChanges: ModuleData) => void;
+export type OnWsStatusUpdate = (taipyApp: TaipyApp, messageQueue: string[]) => void;
 type Route = [string, string];
 
 export class TaipyApp {
@@ -19,6 +21,8 @@ export class TaipyApp {
     _onChange: OnChangeHandler | undefined;
     _onNotify: OnNotifyHandler | undefined;
     _onReload: OnReloadHandler | undefined;
+    _onWsStatusUpdate: OnWsStatusUpdate | undefined;
+    _ackList: string[];
     variableData: DataManager | undefined;
     functionData: DataManager | undefined;
     appId: string;
@@ -33,7 +37,7 @@ export class TaipyApp {
         onInit: OnInitHandler | undefined = undefined,
         onChange: OnChangeHandler | undefined = undefined,
         path: string | undefined = undefined,
-        socket: Socket | undefined = undefined,
+        socket: Socket | undefined = undefined
     ) {
         socket = socket || io("/", { autoConnect: false });
         this.onInit = onInit;
@@ -48,6 +52,7 @@ export class TaipyApp {
         this.path = path;
         this.socket = socket;
         this.wsAdapters = [new TaipyWsAdapter()];
+        this._ackList = [];
         // Init socket io connection
         initSocket(socket, this);
     }
@@ -96,6 +101,16 @@ export class TaipyApp {
         this._onReload = handler;
     }
 
+    get onWsStatusUpdate() {
+        return this._onWsStatusUpdate;
+    }
+    set onWsStatusUpdate(handler: OnWsStatusUpdate | undefined) {
+        if (handler !== undefined && handler?.length !== 2) {
+            throw new Error("_onWsStatusUpdate() requires two parameters");
+        }
+        this._onWsStatusUpdate = handler;
+    }
+
     // Utility methods
     init() {
         this.clientId = "";
@@ -103,15 +118,26 @@ export class TaipyApp {
         this.appId = "";
         this.routes = undefined;
         const id = getLocalStorageValue(TAIPY_CLIENT_ID, "");
-        sendWsMessage(this.socket, "ID", TAIPY_CLIENT_ID, id, id, undefined, false);
-        sendWsMessage(this.socket, "AID", "connect", "", id, undefined, false);
-        sendWsMessage(this.socket, "GR", "", "", id, undefined, false);
+        this.sendWsMessage("ID", TAIPY_CLIENT_ID, id);
+        this.sendWsMessage("AID", "connect", "");
+        this.sendWsMessage("GR", "", "");
         if (id !== "") {
             this.clientId = id;
             this.updateContext(this.path);
         }
     }
 
+    sendWsMessage(type: WsMessageType, id: string, payload: unknown, context: string | undefined = undefined) {
+        if (context === undefined) {
+            context = this.context;
+        }
+        const ackId = sendWsMessage(this.socket, type, id, payload, this.clientId, context);
+        if (ackId) {
+            this._ackList.push(ackId);
+            this.onWsStatusUpdate && this.onWsStatusUpdate(this, this._ackList);
+        }
+    }
+
     // Public methods
     registerWsAdapter(wsAdapter: WsAdapter) {
         this.wsAdapters.unshift(wsAdapter);
@@ -153,7 +179,7 @@ export class TaipyApp {
     // This update will only send the request to Taipy Gui backend
     // the actual update will be handled when the backend responds
     update(encodedName: string, value: unknown) {
-        sendWsMessage(this.socket, "U", encodedName, { value: value }, this.clientId, this.context);
+        this.sendWsMessage("U", encodedName, { value: value });
     }
 
     getContext() {
@@ -164,12 +190,12 @@ export class TaipyApp {
         if (!path || path === "") {
             path = window.location.pathname.slice(1);
         }
-        sendWsMessage(this.socket, "GMC", "get_module_context", { path: path || "/" }, this.clientId);
+        this.sendWsMessage("GMC", "get_module_context", { path: path || "/" });
     }
 
     trigger(actionName: string, triggerId: string, payload: Record<string, unknown> = {}) {
         payload["action"] = actionName;
-        sendWsMessage(this.socket, "A", triggerId, payload, this.clientId, this.context);
+        this.sendWsMessage("A", triggerId, payload);
     }
 
     upload(encodedName: string, files: FileList, progressCallback: (val: number) => void) {
@@ -179,6 +205,10 @@ export class TaipyApp {
     getPageMetadata() {
         return this.metadata;
     }
+
+    getWsStatus() {
+        return this._ackList;
+    }
 }
 
 export const createApp = (onInit?: OnInitHandler, onChange?: OnChangeHandler, path?: string, socket?: Socket) => {

+ 0 - 2
frontend/taipy-gui/base/src/exports.ts

@@ -1,9 +1,7 @@
 import { WsAdapter } from "./wsAdapter";
-import { sendWsMessage } from "../../src/context/wsUtils";
 // import { TaipyApp } from "./app";
 
 export {
     WsAdapter,
-    sendWsMessage,
     // TaipyApp,
 };

+ 28 - 30
frontend/taipy-gui/base/src/packaging/taipy-gui-base.d.ts

@@ -20,10 +20,29 @@ declare class DataManager {
     getAllData(): Record<string, unknown>;
     update(encodedName: string, value: unknown): void;
 }
+export type WsMessageType =
+    | "A"
+    | "U"
+    | "DU"
+    | "MU"
+    | "RU"
+    | "AL"
+    | "BL"
+    | "NA"
+    | "ID"
+    | "MS"
+    | "DF"
+    | "PR"
+    | "ACK"
+    | "GMC"
+    | "GDT"
+    | "AID"
+    | "GR";
 export type OnInitHandler = (taipyApp: TaipyApp) => void;
 export type OnChangeHandler = (taipyApp: TaipyApp, encodedName: string, value: unknown) => void;
 export type OnNotifyHandler = (taipyApp: TaipyApp, type: string, message: string) => void;
 export type OnReloadHandler = (taipyApp: TaipyApp, removedChanges: ModuleData) => void;
+export type OnWsStatusUpdate = (taipyApp: TaipyApp, messageQueue: string[]) => void;
 export type Route = [string, string];
 export declare class TaipyApp {
     socket: Socket;
@@ -31,11 +50,14 @@ export declare class TaipyApp {
     _onChange: OnChangeHandler | undefined;
     _onNotify: OnNotifyHandler | undefined;
     _onReload: OnReloadHandler | undefined;
+    _onWsStatusUpdate: OnWsStatusUpdate | undefined;
+    _ackList: string[];
     variableData: DataManager | undefined;
     functionData: DataManager | undefined;
     appId: string;
     clientId: string;
     context: string;
+    metadata: Record<string, unknown>;
     path: string | undefined;
     routes: Route[] | undefined;
     wsAdapters: WsAdapter[];
@@ -53,7 +75,10 @@ export declare class TaipyApp {
     set onNotify(handler: OnNotifyHandler | undefined);
     get onReload(): OnReloadHandler | undefined;
     set onReload(handler: OnReloadHandler | undefined);
+    get onWsStatusUpdate(): OnWsStatusUpdate | undefined;
+    set onWsStatusUpdate(handler: OnWsStatusUpdate | undefined);
     init(): void;
+    sendWsMessage(type: WsMessageType | string, id: string, payload: unknown, context?: string | undefined): void;
     registerWsAdapter(wsAdapter: WsAdapter): void;
     getEncodedName(varName: string, module: string): string | undefined;
     getName(encodedName: string): [string, string] | undefined;
@@ -68,28 +93,11 @@ export declare class TaipyApp {
     updateContext(path?: string | undefined): void;
     trigger(actionName: string, triggerId: string, payload?: Record<string, unknown>): void;
     upload(encodedName: string, files: FileList, progressCallback: (val: number) => void): Promise<string>;
-    getPageMetadata(): any;
+    getPageMetadata(): Record<string, unknown>;
+    getWsStatus(): string[];
 }
-export type WsMessageType =
-    | "A"
-    | "U"
-    | "DU"
-    | "MU"
-    | "RU"
-    | "AL"
-    | "BL"
-    | "NA"
-    | "ID"
-    | "MS"
-    | "DF"
-    | "PR"
-    | "ACK"
-    | "GMC"
-    | "GDT"
-    | "AID"
-    | "GR";
 export interface WsMessage {
-    type: WsMessageType | str;
+    type: WsMessageType | string;
     name: string;
     payload: Record<string, unknown> | unknown;
     propagate: boolean;
@@ -97,16 +105,6 @@ export interface WsMessage {
     module_context: string;
     ack_id?: string;
 }
-export declare const sendWsMessage: (
-    socket: Socket | undefined,
-    type: WsMessageType | str,
-    name: string,
-    payload: Record<string, unknown> | unknown,
-    id: string,
-    moduleContext?: string,
-    propagate?: boolean,
-    serverAck?: (val: unknown) => void
-) => string;
 export declare abstract class WsAdapter {
     abstract supportedMessageTypes: string[];
     abstract handleWsMessage(message: WsMessage, app: TaipyApp): boolean;

+ 2 - 2
frontend/taipy-gui/base/src/socket.ts

@@ -1,5 +1,5 @@
 import { Socket } from "socket.io-client";
-import { WsMessage, sendWsMessage } from "../../src/context/wsUtils";
+import { WsMessage } from "../../src/context/wsUtils";
 import { TaipyApp } from "./app";
 
 export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
@@ -11,7 +11,7 @@ export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
     // Send a request to get App ID to verify that the app has not been reloaded
     socket.io.on("reconnect", () => {
         console.log("WebSocket reconnected");
-        sendWsMessage(socket, "AID", "reconnect", taipyApp.appId, taipyApp.clientId, taipyApp.context);
+        taipyApp.sendWsMessage("AID", "reconnect", taipyApp.appId);
     });
     // try to reconnect on connect_error
     socket.on("connect_error", (err) => {

+ 7 - 3
frontend/taipy-gui/base/src/wsAdapter.ts

@@ -1,7 +1,7 @@
 import merge from "lodash/merge";
 import { TaipyApp } from "./app";
 import { IdMessage, storeClientId } from "../../src/context/utils";
-import { WsMessage, sendWsMessage } from "../../src/context/wsUtils";
+import { WsMessage } from "../../src/context/wsUtils";
 import { DataManager, ModuleData } from "./dataManager";
 
 export abstract class WsAdapter {
@@ -25,7 +25,7 @@ export class TaipyWsAdapter extends WsAdapter {
     initWsMessageTypes: string[];
     constructor() {
         super();
-        this.supportedMessageTypes = ["MU", "ID", "GMC", "GDT", "AID", "GR", "AL"];
+        this.supportedMessageTypes = ["MU", "ID", "GMC", "GDT", "AID", "GR", "AL", "ACK"];
         this.initWsMessageTypes = ["ID", "AID", "GMC"];
     }
     handleWsMessage(message: WsMessage, taipyApp: TaipyApp): boolean {
@@ -81,6 +81,10 @@ export class TaipyWsAdapter extends WsAdapter {
             } else if (message.type === "AL" && taipyApp.onNotify) {
                 const payload = message as AlertMessage;
                 taipyApp.onNotify(taipyApp, payload.atype, payload.message);
+            } else if (message.type === "ACK") {
+                const {id} = message as unknown as Record<string, string>;
+                taipyApp._ackList = taipyApp._ackList.filter((v) => v !== id);
+                taipyApp.onWsStatusUpdate && taipyApp.onWsStatusUpdate(taipyApp, taipyApp._ackList);
             }
             this.postWsMessageProcessing(message, taipyApp);
             return true;
@@ -96,7 +100,7 @@ export class TaipyWsAdapter extends WsAdapter {
             taipyApp.context !== "" &&
             taipyApp.routes !== undefined
         ) {
-            sendWsMessage(taipyApp.socket, "GDT", "get_data_tree", {}, taipyApp.clientId, taipyApp.context);
+            taipyApp.sendWsMessage("GDT", "get_data_tree", {});
         }
     }
 }

+ 8 - 4
taipy/gui/gui.py

@@ -1133,7 +1133,8 @@ class Gui:
                     {
                         "type": _WsType.GET_MODULE_CONTEXT.value,
                         "payload": {"context": mc, "metadata": meta_return},
-                    }
+                    },
+                    send_back_only=True,
                 )
 
     def __get_variable_tree(self, data: t.Dict[str, t.Any]):
@@ -1177,7 +1178,8 @@ class Gui:
                     "variable": self.__get_variable_tree(data),
                     "function": self.__get_variable_tree(function_data),
                 },
-            }
+            },
+            send_back_only=True,
         )
 
     def __handle_ws_app_id(self, message: t.Any):
@@ -1192,7 +1194,8 @@ class Gui:
             {
                 "type": _WsType.APP_ID.value,
                 "payload": {"name": name, "id": app_id},
-            }
+            },
+            send_back_only=True,
         )
 
     def __handle_ws_get_routes(self):
@@ -1210,7 +1213,8 @@ class Gui:
             {
                 "type": _WsType.GET_ROUTES.value,
                 "payload": routes,
-            }
+            },
+            send_back_only=True,
         )
 
     def __send_ws(self, payload: dict, allow_grouping=True, send_back_only=False) -> None: