Skip to content

Commit

Permalink
Feature/wsadapter (#1423) (#1391)
Browse files Browse the repository at this point in the history
* WS adapter

* revert bundle

* add taipy designer entry

* extract bundle

* use ws adapter properly

* export wssendmessage

* dont export main app -> reduce bundle size

* ws message type to include string in d.ts

* manage external ws message

* add msg_type

* export correctly

* per Fred

* per Fabien
  • Loading branch information
dinhlongviolin1 authored Jun 22, 2024
1 parent 90e5c81 commit 8a444b6
Show file tree
Hide file tree
Showing 15 changed files with 422 additions and 168 deletions.
12 changes: 11 additions & 1 deletion frontend/taipy-gui/base/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { uploadFile } from "../../src/workers/fileupload";

import { Socket, io } from "socket.io-client";
import { DataManager, ModuleData } from "./dataManager";
import { initSocket } from "./utils";
import { initSocket } from "./socket";
import { TaipyWsAdapter, WsAdapter } from "./wsAdapter";

export type OnInitHandler = (taipyApp: TaipyApp) => void;
export type OnChangeHandler = (taipyApp: TaipyApp, encodedName: string, value: unknown) => void;
Expand All @@ -25,6 +26,7 @@ export class TaipyApp {
context: string;
path: string | undefined;
routes: Route[] | undefined;
wsAdapters: WsAdapter[];

constructor(
onInit: OnInitHandler | undefined = undefined,
Expand All @@ -43,6 +45,7 @@ export class TaipyApp {
this.routes = undefined;
this.path = path;
this.socket = socket;
this.wsAdapters = [new TaipyWsAdapter()];
// Init socket io connection
initSocket(socket, this);
}
Expand All @@ -51,6 +54,7 @@ export class TaipyApp {
get onInit() {
return this._onInit;
}

set onInit(handler: OnInitHandler | undefined) {
if (handler !== undefined && handler.length !== 1) {
throw new Error("onInit() requires one parameter");
Expand All @@ -61,6 +65,7 @@ export class TaipyApp {
get onChange() {
return this._onChange;
}

set onChange(handler: OnChangeHandler | undefined) {
if (handler !== undefined && handler.length !== 3) {
throw new Error("onChange() requires three parameters");
Expand All @@ -71,6 +76,7 @@ export class TaipyApp {
get onNotify() {
return this._onNotify;
}

set onNotify(handler: OnNotifyHandler | undefined) {
if (handler !== undefined && handler.length !== 3) {
throw new Error("onNotify() requires three parameters");
Expand Down Expand Up @@ -105,6 +111,10 @@ export class TaipyApp {
}

// Public methods
registerWsAdapter(wsAdapter: WsAdapter) {
this.wsAdapters.unshift(wsAdapter);
}

getEncodedName(varName: string, module: string) {
return this.variableData?.getEncodedName(varName, module);
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/taipy-gui/base/src/dataManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type ModuleData = Record<string, VarName>;

export type VarName = Record<string, VarData>;

interface VarData {
export interface VarData {
type: string;
value: unknown;
encoded_name: string;
Expand Down
9 changes: 9 additions & 0 deletions frontend/taipy-gui/base/src/exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { WsAdapter } from "./wsAdapter";
import { sendWsMessage } from "../../src/context/wsUtils";
// import { TaipyApp } from "./app";

export {
WsAdapter,
sendWsMessage,
// TaipyApp,
};
7 changes: 7 additions & 0 deletions frontend/taipy-gui/base/src/packaging/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "taipy-gui-base",
"version": "3.2.0",
"private": true,
"main": "./taipy-gui-base.js",
"types": "./taipy-gui-base.d.ts"
}
113 changes: 113 additions & 0 deletions frontend/taipy-gui/base/src/packaging/taipy-gui-base.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Socket } from "socket.io-client";

export type ModuleData = Record<string, VarName>;
export type VarName = Record<string, VarData>;
export interface VarData {
type: string;
value: unknown;
encoded_name: string;
}
declare class DataManager {
_data: Record<string, unknown>;
_init_data: ModuleData;
constructor(variableModuleData: ModuleData);
init(variableModuleData: ModuleData): ModuleData;
getEncodedName(varName: string, module: string): string | undefined;
getName(encodedName: string): [string, string] | undefined;
get(encodedName: string): unknown;
getInfo(encodedName: string): VarData | undefined;
getDataTree(): ModuleData;
getAllData(): Record<string, unknown>;
update(encodedName: string, value: unknown): void;
}
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 Route = [string, string];
export declare class TaipyApp {
socket: Socket;
_onInit: OnInitHandler | undefined;
_onChange: OnChangeHandler | undefined;
_onNotify: OnNotifyHandler | undefined;
_onReload: OnReloadHandler | undefined;
variableData: DataManager | undefined;
functionData: DataManager | undefined;
appId: string;
clientId: string;
context: string;
path: string | undefined;
routes: Route[] | undefined;
wsAdapters: WsAdapter[];
constructor(
onInit?: OnInitHandler | undefined,
onChange?: OnChangeHandler | undefined,
path?: string | undefined,
socket?: Socket | undefined
);
get onInit(): OnInitHandler | undefined;
set onInit(handler: OnInitHandler | undefined);
get onChange(): OnChangeHandler | undefined;
set onChange(handler: OnChangeHandler | undefined);
get onNotify(): OnNotifyHandler | undefined;
set onNotify(handler: OnNotifyHandler | undefined);
get onReload(): OnReloadHandler | undefined;
set onReload(handler: OnReloadHandler | undefined);
init(): void;
registerWsAdapter(wsAdapter: WsAdapter): void;
getEncodedName(varName: string, module: string): string | undefined;
getName(encodedName: string): [string, string] | undefined;
get(encodedName: string): unknown;
getInfo(encodedName: string): VarData | undefined;
getDataTree(): ModuleData | undefined;
getAllData(): Record<string, unknown> | undefined;
getFunctionList(): string[];
getRoutes(): Route[] | undefined;
update(encodedName: string, value: unknown): void;
getContext(): string;
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;
}
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;
name: string;
payload: Record<string, unknown> | unknown;
propagate: boolean;
client_id: string;
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;
}
46 changes: 46 additions & 0 deletions frontend/taipy-gui/base/src/socket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Socket } from "socket.io-client";
import { WsMessage, sendWsMessage } from "../../src/context/wsUtils";
import { TaipyApp } from "./app";

export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
socket.on("connect", () => {
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", () => {
console.log("WebSocket reconnected");
sendWsMessage(socket, "AID", "reconnect", taipyApp.appId, taipyApp.clientId, taipyApp.context);
});
// try to reconnect on connect_error
socket.on("connect_error", (err) => {
console.log("Error connecting WebSocket: ", err);
setTimeout(() => {
socket && socket.connect();
}, 500);
});
// try to reconnect on server disconnection
socket.on("disconnect", (reason, details) => {
console.log("WebSocket disconnected due to: ", reason, details);
if (reason === "io server disconnect") {
socket && socket.connect();
}
});
// handle message data from backend
socket.on("message", (message: WsMessage) => {
// handle messages with registered websocket adapters
for (const adapter of taipyApp.wsAdapters) {
if (adapter.supportedMessageTypes.includes(message.type)) {
const messageResolved = adapter.handleWsMessage(message, taipyApp);
if (messageResolved) {
return;
}
}
}
});
// only now does the socket tries to open/connect
if (!socket.connected) {
socket.connect();
}
};
117 changes: 0 additions & 117 deletions frontend/taipy-gui/base/src/utils.ts

This file was deleted.

Loading

0 comments on commit 8a444b6

Please sign in to comment.