Skip to content

Commit

Permalink
Get Routes with type frontend decouple (#1370)
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhlongviolin1 authored Jun 10, 2024
1 parent 9aa2c7a commit f0656ce
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 36 deletions.
23 changes: 16 additions & 7 deletions frontend/taipy-gui/base/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,31 @@ import { Socket, io } from "socket.io-client";
import { DataManager, ModuleData } from "./dataManager";
import { initSocket } from "./utils";

export type OnInitHandler = (appManager: TaipyApp) => void;
export type OnChangeHandler = (appManager: TaipyApp, encodedName: string, value: unknown) => void;
export type OnNotifyHandler = (appManager: TaipyApp, type: string, message: string) => void;
export type onReloadHandler = (appManager: TaipyApp, removedChanges: ModuleData) => 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;
type Route = [string, string];

export class TaipyApp {
socket: Socket;
_onInit: OnInitHandler | undefined;
_onChange: OnChangeHandler | undefined;
_onNotify: OnNotifyHandler | undefined;
_onReload: onReloadHandler | undefined;
_onReload: OnReloadHandler | undefined;
variableData: DataManager | undefined;
functionData: DataManager | undefined;
appId: string;
clientId: string;
context: string;
path: string | undefined;
routes: Route[] | undefined;

constructor(
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;
Expand All @@ -38,6 +40,7 @@ export class TaipyApp {
this.clientId = "";
this.context = "";
this.appId = "";
this.routes = undefined;
this.path = path;
this.socket = socket;
initSocket(socket, this);
Expand Down Expand Up @@ -77,7 +80,7 @@ export class TaipyApp {
get onReload() {
return this._onReload;
}
set onReload(handler: onReloadHandler | undefined) {
set onReload(handler: OnReloadHandler | undefined) {
if (handler !== undefined && handler?.length !== 2) {
throw new Error("_onReload() requires two parameters");
}
Expand All @@ -89,9 +92,11 @@ export class TaipyApp {
this.clientId = "";
this.context = "";
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);
if (id !== "") {
this.clientId = id;
this.updateContext(this.path);
Expand Down Expand Up @@ -128,6 +133,10 @@ export class TaipyApp {
return Object.keys(functionData || {});
}

getRoutes() {
return this.routes;
}

// 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) {
Expand Down
60 changes: 32 additions & 28 deletions frontend/taipy-gui/base/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ interface AlertMessage extends WsMessage {

const initWsMessageTypes = ["ID", "AID", "GMC"];

export const initSocket = (socket: Socket, appManager: TaipyApp) => {
export const initSocket = (socket: Socket, taipyApp: TaipyApp) => {
socket.on("connect", () => {
if (appManager.clientId === "" || appManager.appId === "") {
appManager.init();
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", appManager.appId, appManager.clientId, appManager.context);
sendWsMessage(socket, "AID", "reconnect", taipyApp.appId, taipyApp.clientId, taipyApp.context);
});
// try to reconnect on connect_error
socket.on("connect_error", (err) => {
Expand All @@ -44,70 +44,74 @@ export const initSocket = (socket: Socket, appManager: TaipyApp) => {
});
// handle message data from backend
socket.on("message", (message: WsMessage) => {
processWsMessage(message, appManager);
processWsMessage(message, taipyApp);
});
// only now does the socket tries to open/connect
if (!socket.connected) {
socket.connect();
}
};

const processWsMessage = (message: WsMessage, appManager: TaipyApp) => {
const processWsMessage = (message: WsMessage, taipyApp: TaipyApp) => {
if (message.type) {
if (message.type === "MU" && Array.isArray(message.payload)) {
for (const muPayload of message.payload as [MultipleUpdatePayload]) {
const encodedName = muPayload.name;
const { value } = muPayload.payload;
appManager.variableData?.update(encodedName, value);
appManager.onChange && appManager.onChange(appManager, encodedName, value);
taipyApp.variableData?.update(encodedName, value);
taipyApp.onChange && taipyApp.onChange(taipyApp, encodedName, value);
}
} else if (message.type === "ID") {
const { id } = message as unknown as IdMessage;
storeClientId(id);
appManager.clientId = id;
appManager.updateContext(appManager.path);
taipyApp.clientId = id;
taipyApp.updateContext(taipyApp.path);
} else if (message.type === "GMC") {
const mc = (message.payload as Record<string, unknown>).data as string;
window.localStorage.setItem("ModuleContext", mc);
appManager.context = mc;
taipyApp.context = mc;
} else if (message.type === "GDT") {
const payload = message.payload as Record<string, ModuleData>;
const variableData = payload.variable;
const functionData = payload.function;
if (appManager.variableData && appManager.functionData) {
const varChanges = appManager.variableData.init(variableData);
const functionChanges = appManager.functionData.init(functionData);
if (taipyApp.variableData && taipyApp.functionData) {
const varChanges = taipyApp.variableData.init(variableData);
const functionChanges = taipyApp.functionData.init(functionData);
const changes = merge(varChanges, functionChanges);
if (varChanges || functionChanges) {
appManager.onReload && appManager.onReload(appManager, changes);
taipyApp.onReload && taipyApp.onReload(taipyApp, changes);
}
} else {
appManager.variableData = new DataManager(variableData);
appManager.functionData = new DataManager(functionData);
appManager.onInit && appManager.onInit(appManager);
taipyApp.variableData = new DataManager(variableData);
taipyApp.functionData = new DataManager(functionData);
taipyApp.onInit && taipyApp.onInit(taipyApp);
}
} else if (message.type === "AID") {
const payload = message.payload as Record<string, unknown>;
if (payload.name === "reconnect") {
return appManager.init();
return taipyApp.init();
}
appManager.appId = payload.id as string;
} else if (message.type === "AL" && appManager.onNotify) {
taipyApp.appId = payload.id as string;
} else if (message.type === "GR") {
const payload = message.payload as [string, string][];
taipyApp.routes = payload;
} else if (message.type === "AL" && taipyApp.onNotify) {
const payload = message as AlertMessage;
appManager.onNotify(appManager, payload.atype, payload.message);
taipyApp.onNotify(taipyApp, payload.atype, payload.message);
}
postWsMessageProcessing(message, appManager);
postWsMessageProcessing(message, taipyApp);
}
};

const postWsMessageProcessing = (message: WsMessage, appManager: TaipyApp) => {
const postWsMessageProcessing = (message: WsMessage, taipyApp: TaipyApp) => {
// perform data population only when all necessary metadata is ready
if (
initWsMessageTypes.includes(message.type) &&
appManager.clientId !== "" &&
appManager.appId !== "" &&
appManager.context !== ""
taipyApp.clientId !== "" &&
taipyApp.appId !== "" &&
taipyApp.context !== "" &&
taipyApp.routes !== undefined
) {
sendWsMessage(appManager.socket, "GDT", "get_data_tree", {}, appManager.clientId, appManager.context);
sendWsMessage(taipyApp.socket, "GDT", "get_data_tree", {}, taipyApp.clientId, taipyApp.context);
}
};
3 changes: 2 additions & 1 deletion frontend/taipy-gui/src/context/wsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export type WsMessageType =
| "ACK"
| "GMC"
| "GDT"
| "AID";
| "AID"
| "GR";

export interface WsMessage {
type: WsMessageType;
Expand Down
20 changes: 20 additions & 0 deletions taipy/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@ def _manage_message(self, msg_type: _WsType, message: dict) -> None:
self.__handle_ws_get_data_tree()
elif msg_type == _WsType.APP_ID.value:
self.__handle_ws_app_id(message)
elif msg_type == _WsType.GET_ROUTES.value:
self.__handle_ws_get_routes()
self.__send_ack(message.get("ack_id"))
except Exception as e: # pragma: no cover
if isinstance(e, AttributeError) and (name := message.get("name")):
Expand Down Expand Up @@ -1167,6 +1169,24 @@ def __handle_ws_app_id(self, message: t.Any):
}
)

def __handle_ws_get_routes(self):
routes = (
[[self._config.root_page._route, self._config.root_page._renderer.page_type]]
if self._config.root_page
else []
)
routes += [
[page._route, page._renderer.page_type]
for page in self._config.pages
if page._route != Gui.__root_page_name
]
self.__send_ws(
{
"type": _WsType.GET_ROUTES.value,
"payload": routes,
}
)

def __send_ws(self, payload: dict, allow_grouping=True, send_back_only=False) -> None:
grouping_message = self.__get_message_grouping() if allow_grouping else None
if grouping_message is None:
Expand Down
2 changes: 2 additions & 0 deletions taipy/gui/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Page:
your application variables and interact with them.
"""

page_type: str = "Taipy"

def __init__(self, **kwargs) -> None:
from .custom import Page as CustomPage

Expand Down
1 change: 1 addition & 0 deletions taipy/gui/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class _WsType(Enum):
ACKNOWLEDGEMENT = "ACK"
GET_MODULE_CONTEXT = "GMC"
GET_DATA_TREE = "GDT"
GET_ROUTES = "GR"


NumberTypes = {"int", "int64", "float", "float64"}
Expand Down

0 comments on commit f0656ce

Please sign in to comment.