فهرست منبع

Expose websocket decouple frontend (#1501)

* Expose websocket decouple frontend

* add useEvent per Fred

* per Fred and Fabien
Dinh Long Nguyen 10 ماه پیش
والد
کامیت
87065e19c0

+ 44 - 1
frontend/taipy-gui/base/src/app.ts

@@ -12,7 +12,15 @@ 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 OnWsMessage = (taipyApp: TaipyApp, event: string, payload: unknown) => void;
 export type OnWsStatusUpdate = (taipyApp: TaipyApp, messageQueue: string[]) => void;
+export type OnEvent =
+    | OnInitHandler
+    | OnChangeHandler
+    | OnNotifyHandler
+    | OnReloadHandler
+    | OnWsMessage
+    | OnWsStatusUpdate;
 type Route = [string, string];
 
 export class TaipyApp {
@@ -21,6 +29,7 @@ export class TaipyApp {
     _onChange: OnChangeHandler | undefined;
     _onNotify: OnNotifyHandler | undefined;
     _onReload: OnReloadHandler | undefined;
+    _onWsMessage: OnWsMessage | undefined;
     _onWsStatusUpdate: OnWsStatusUpdate | undefined;
     _ackList: string[];
     variableData: DataManager | undefined;
@@ -69,6 +78,10 @@ export class TaipyApp {
         this._onInit = handler;
     }
 
+    onInitEvent() {
+        this.onInit && this.onInit(this);
+    }
+
     get onChange() {
         return this._onChange;
     }
@@ -80,6 +93,10 @@ export class TaipyApp {
         this._onChange = handler;
     }
 
+    onChangeEvent(encodedName: string, value: unknown) {
+        this.onChange && this.onChange(this, encodedName, value);
+    }
+
     get onNotify() {
         return this._onNotify;
     }
@@ -91,6 +108,10 @@ export class TaipyApp {
         this._onNotify = handler;
     }
 
+    onNotifyEvent(type: string, message: string) {
+        this.onNotify && this.onNotify(this, type, message);
+    }
+
     get onReload() {
         return this._onReload;
     }
@@ -101,6 +122,24 @@ export class TaipyApp {
         this._onReload = handler;
     }
 
+    onReloadEvent(removedChanges: ModuleData) {
+        this.onReload && this.onReload(this, removedChanges);
+    }
+
+    get onWsMessage() {
+        return this._onWsMessage;
+    }
+    set onWsMessage(handler: OnWsMessage | undefined) {
+        if (handler !== undefined && handler?.length !== 3) {
+            throw new Error("onWsMessage() requires three parameters");
+        }
+        this._onWsMessage = handler;
+    }
+
+    onWsMessageEvent(event: string, payload: unknown) {
+        this.onWsMessage && this.onWsMessage(this, event, payload);
+    }
+
     get onWsStatusUpdate() {
         return this._onWsStatusUpdate;
     }
@@ -111,6 +150,10 @@ export class TaipyApp {
         this._onWsStatusUpdate = handler;
     }
 
+    onWsStatusUpdateEvent(messageQueue: string[]) {
+        this.onWsStatusUpdate && this.onWsStatusUpdate(this, messageQueue);
+    }
+
     // Utility methods
     init() {
         this.clientId = "";
@@ -134,7 +177,7 @@ export class TaipyApp {
         const ackId = sendWsMessage(this.socket, type, id, payload, this.clientId, context);
         if (ackId) {
             this._ackList.push(ackId);
-            this.onWsStatusUpdate && this.onWsStatusUpdate(this, this._ackList);
+            this.onWsStatusUpdateEvent(this._ackList);
         }
     }
 

+ 21 - 10
frontend/taipy-gui/base/src/packaging/taipy-gui-base.d.ts

@@ -37,11 +37,22 @@ export type WsMessageType =
     | "GMC"
     | "GDT"
     | "AID"
-    | "GR";
+    | "GR"
+    | "FV";
+export interface WsMessage {
+    type: WsMessageType | string;
+    name: string;
+    payload: Record<string, unknown> | unknown;
+    propagate: boolean;
+    client_id: string;
+    module_context: string;
+    ack_id?: string;
+}
 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 OnWsMessage = (taipyApp: TaipyApp, event: string, payload: unknown) => void;
 export type OnWsStatusUpdate = (taipyApp: TaipyApp, messageQueue: string[]) => void;
 export type Route = [string, string];
 export declare class TaipyApp {
@@ -50,6 +61,7 @@ export declare class TaipyApp {
     _onChange: OnChangeHandler | undefined;
     _onNotify: OnNotifyHandler | undefined;
     _onReload: OnReloadHandler | undefined;
+    _onWsMessage: OnWsMessage | undefined;
     _onWsStatusUpdate: OnWsStatusUpdate | undefined;
     _ackList: string[];
     variableData: DataManager | undefined;
@@ -69,14 +81,22 @@ export declare class TaipyApp {
     );
     get onInit(): OnInitHandler | undefined;
     set onInit(handler: OnInitHandler | undefined);
+    onInitEvent(): void;
     get onChange(): OnChangeHandler | undefined;
     set onChange(handler: OnChangeHandler | undefined);
+    onChangeEvent(encodedName: string, value: unknown): void;
     get onNotify(): OnNotifyHandler | undefined;
     set onNotify(handler: OnNotifyHandler | undefined);
+    onNotifyEvent(type: string, message: string): void;
     get onReload(): OnReloadHandler | undefined;
     set onReload(handler: OnReloadHandler | undefined);
+    onReloadEvent(removedChanges: ModuleData): void;
+    get onWsMessage(): OnWsMessage | undefined;
+    set onWsMessage(handler: OnWsMessage | undefined);
+    onWsMessageEvent(event: string, payload: unknown): void;
     get onWsStatusUpdate(): OnWsStatusUpdate | undefined;
     set onWsStatusUpdate(handler: OnWsStatusUpdate | undefined);
+    onWsStatusUpdateEvent(messageQueue: string[]): void;
     init(): void;
     sendWsMessage(type: WsMessageType | string, id: string, payload: unknown, context?: string | undefined): void;
     registerWsAdapter(wsAdapter: WsAdapter): void;
@@ -96,15 +116,6 @@ export declare class TaipyApp {
     getPageMetadata(): Record<string, unknown>;
     getWsStatus(): string[];
 }
-export interface WsMessage {
-    type: WsMessageType | string;
-    name: string;
-    payload: Record<string, unknown> | unknown;
-    propagate: boolean;
-    client_id: string;
-    module_context: string;
-    ack_id?: string;
-}
 export declare abstract class WsAdapter {
     abstract supportedMessageTypes: string[];
     abstract handleWsMessage(message: WsMessage, app: TaipyApp): boolean;

+ 5 - 0
frontend/taipy-gui/base/src/socket.ts

@@ -4,17 +4,20 @@ import { TaipyApp } from "./app";
 
 export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
     socket.on("connect", () => {
+        taipyApp.onWsMessageEvent("connect", null);
         if (taipyApp.clientId === "" || taipyApp.appId === "") {
             taipyApp.init();
         }
     });
     // Send a request to get App ID to verify that the app has not been reloaded
     socket.io.on("reconnect", () => {
+        taipyApp.onWsMessageEvent("reconnect", null);
         console.log("WebSocket reconnected");
         taipyApp.sendWsMessage("AID", "reconnect", taipyApp.appId);
     });
     // try to reconnect on connect_error
     socket.on("connect_error", (err) => {
+        taipyApp.onWsMessageEvent("connect_error", { err });
         console.log("Error connecting WebSocket: ", err);
         setTimeout(() => {
             socket && socket.connect();
@@ -22,6 +25,7 @@ export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
     });
     // try to reconnect on server disconnection
     socket.on("disconnect", (reason, details) => {
+        taipyApp.onWsMessageEvent("disconnect", { reason, details });
         console.log("WebSocket disconnected due to: ", reason, details);
         if (reason === "io server disconnect") {
             socket && socket.connect();
@@ -29,6 +33,7 @@ export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
     });
     // handle message data from backend
     socket.on("message", (message: WsMessage) => {
+        taipyApp.onWsMessageEvent("message", message);
         // handle messages with registered websocket adapters
         for (const adapter of taipyApp.wsAdapters) {
             if (adapter.supportedMessageTypes.includes(message.type)) {

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

@@ -35,7 +35,7 @@ export class TaipyWsAdapter extends WsAdapter {
                     const encodedName = muPayload.name;
                     const { value } = muPayload.payload;
                     taipyApp.variableData?.update(encodedName, value);
-                    taipyApp.onChange && taipyApp.onChange(taipyApp, encodedName, value);
+                    taipyApp.onChangeEvent(encodedName, value);
                 }
             } else if (message.type === "ID") {
                 const { id } = message as unknown as IdMessage;
@@ -61,12 +61,12 @@ export class TaipyWsAdapter extends WsAdapter {
                     const functionChanges = taipyApp.functionData.init(functionData);
                     const changes = merge(varChanges, functionChanges);
                     if (varChanges || functionChanges) {
-                        taipyApp.onReload && taipyApp.onReload(taipyApp, changes);
+                        taipyApp.onReloadEvent(changes);
                     }
                 } else {
                     taipyApp.variableData = new DataManager(variableData);
                     taipyApp.functionData = new DataManager(functionData);
-                    taipyApp.onInit && taipyApp.onInit(taipyApp);
+                    taipyApp.onInitEvent();
                 }
             } else if (message.type === "AID") {
                 const payload = message.payload as Record<string, unknown>;
@@ -78,13 +78,13 @@ export class TaipyWsAdapter extends WsAdapter {
             } else if (message.type === "GR") {
                 const payload = message.payload as [string, string][];
                 taipyApp.routes = payload;
-            } else if (message.type === "AL" && taipyApp.onNotify) {
+            } else if (message.type === "AL") {
                 const payload = message as AlertMessage;
-                taipyApp.onNotify(taipyApp, payload.atype, payload.message);
+                taipyApp.onNotifyEvent(payload.atype, payload.message);
             } else if (message.type === "ACK") {
-                const {id} = message as unknown as Record<string, string>;
+                const { id } = message as unknown as Record<string, string>;
                 taipyApp._ackList = taipyApp._ackList.filter((v) => v !== id);
-                taipyApp.onWsStatusUpdate && taipyApp.onWsStatusUpdate(taipyApp, taipyApp._ackList);
+                taipyApp.onWsStatusUpdateEvent(taipyApp._ackList);
             }
             this.postWsMessageProcessing(message, taipyApp);
             return true;