about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-06-03 02:10:52 +0200
committerMelonai <einebeere@gmail.com>2021-06-03 02:10:52 +0200
commit1348f3402c9c15c37501c7cf48f6c63ae7f8c1d8 (patch)
tree991147a82958413ed7a5c4a30ce6861bbdabb918
parent6f7ce856f784dce0952db2272a85ee70e6e1b159 (diff)
downloadrook-1348f3402c9c15c37501c7cf48f6c63ae7f8c1d8.tar.zst
rook-1348f3402c9c15c37501c7cf48f6c63ae7f8c1d8.zip
Dynamic event handling architecture
-rw-r--r--assets/src/network/channel/connection.ts32
-rw-r--r--assets/src/network/channel/messages/handler.ts93
-rw-r--r--assets/src/network/channel/request.ts2
-rw-r--r--assets/src/network/channel/share.ts8
4 files changed, 126 insertions, 9 deletions
diff --git a/assets/src/network/channel/connection.ts b/assets/src/network/channel/connection.ts
index 52d85d1..6d6f3de 100644
--- a/assets/src/network/channel/connection.ts
+++ b/assets/src/network/channel/connection.ts
@@ -1,4 +1,11 @@
 import { Channel, Push, Socket } from "phoenix";
+import {
+    Handler,
+    Handlers,
+    registerTokenHandler,
+    UnregisterHandler,
+} from "./messages/handler";
+import type { AnyMessage } from "./messages/messages";
 import { startRequest } from "./request";
 import { startShare } from "./share";
 import { connectSocket, fetchToken } from "./socket";
@@ -22,6 +29,7 @@ export type Connection = {
     channel: Channel | null;
     token: string | null;
     state: ConnectionState;
+    handlers: Handlers;
     type: Type;
 };
 
@@ -30,6 +38,7 @@ const connection: Connection = {
     channel: null,
     token: null,
     state: ConnectionState.CONNECTING_SOCKET,
+    handlers: {},
     type: Type.NONE,
 };
 
@@ -55,6 +64,21 @@ export function send(event: string, data: any): Push {
     return connection.channel.push(event, data);
 }
 
+export function onWithToken<Message extends AnyMessage>(
+    event: string,
+    token: string | null,
+    handler: Handler<Message>
+): UnregisterHandler {
+    return registerTokenHandler(connection.handlers, event, token, handler);
+}
+
+export function on<Message extends AnyMessage>(
+    event: string,
+    handler: Handler<Message>
+): UnregisterHandler {
+    return onWithToken(event, null, handler);
+}
+
 export function getOwnToken(): string {
     if (connection.state <= ConnectionState.FETCHING_TOKEN) {
         throw new Error("There is no token yet.");
@@ -63,6 +87,14 @@ export function getOwnToken(): string {
     return connection.token;
 }
 
+export function getChannel(): Channel {
+    if (connection.state <= ConnectionState.FETCHING_TOKEN) {
+        throw new Error("There is no channel yet.");
+    }
+
+    return connection.channel;
+}
+
 function updateState(state: ConnectionState) {
     // TODO: Notify state listeners
     connection.state = state;
diff --git a/assets/src/network/channel/messages/handler.ts b/assets/src/network/channel/messages/handler.ts
new file mode 100644
index 0000000..5cfe327
--- /dev/null
+++ b/assets/src/network/channel/messages/handler.ts
@@ -0,0 +1,93 @@
+import { getChannel } from "../connection";
+import type { AnyMessage } from "./messages";
+
+export type Handlers = {
+    [event: string]: EventHandler<unknown>;
+};
+
+type EventHandler<Message extends AnyMessage> = {
+    tokenHandler: TokenHandler<Message>;
+    directHandlers: Handler<Message>[];
+};
+
+export type TokenHandler<Message extends AnyMessage> = {
+    [token: string]: Handler<Message>;
+};
+
+export type Handler<Message extends AnyMessage> = (message?: Message) => void;
+
+export type UnregisterHandler = () => void;
+
+export function registerTokenHandler<Message extends AnyMessage>(
+    handlers: Handlers,
+    event: string,
+    token: string | null,
+    handler: Handler<Message>
+): UnregisterHandler {
+    let eventHandler = handlers[event];
+
+    // If this event did not yet have any handlers registered we have to register it
+    if (eventHandler === undefined) {
+        eventHandler = {
+            tokenHandler: {},
+            directHandlers: [],
+        };
+
+        handlers[event] = eventHandler;
+
+        registerNewEvent<Message>(eventHandler, event);
+    }
+
+    let unregister: UnregisterHandler;
+
+    if (token === null) {
+        const directHandlers = eventHandler.directHandlers;
+        directHandlers.push(handler);
+
+        unregister = () => {
+            const index = directHandlers.findIndex(h => h === handler);
+            directHandlers.splice(index, 1);
+        };
+    } else {
+        const tokenHandler = eventHandler.tokenHandler;
+        tokenHandler[token] = handler;
+
+        unregister = () => {
+            delete tokenHandler[token];
+        };
+    }
+
+    return unregister;
+}
+
+function registerNewEvent<Message extends AnyMessage>(
+    eventHandler: EventHandler<Message>,
+    event: string
+) {
+    const callback = (data: Message) => {
+        handleEvent<Message>(eventHandler, data);
+    };
+
+    getChannel().on(event, callback);
+}
+
+function handleEvent<Message extends AnyMessage>(
+    eventHandler: EventHandler<Message>,
+    message: Message
+) {
+    if (message["token"] !== undefined) {
+        const token = message["token"];
+
+        const handler: Handler<Message> = eventHandler.tokenHandler[token];
+
+        if (handler === undefined) {
+            throw new Error("Received message for an unknown token.");
+        }
+
+        handler(message);
+    }
+
+    for (const handler of eventHandler.directHandlers) {
+        handler(message);
+    }
+}
diff --git a/assets/src/network/channel/request.ts b/assets/src/network/channel/request.ts
index 801eee1..dd18aab 100644
--- a/assets/src/network/channel/request.ts
+++ b/assets/src/network/channel/request.ts
@@ -9,6 +9,4 @@ export async function startRequest(connection: Connection) {
         getShareToken()
     );
     connection.channel = requestChannel;
-
-    // TODO: Handle incoming messages from the request channel
 }
diff --git a/assets/src/network/channel/share.ts b/assets/src/network/channel/share.ts
index 10a34fa..f93e8cb 100644
--- a/assets/src/network/channel/share.ts
+++ b/assets/src/network/channel/share.ts
@@ -8,10 +8,4 @@ export async function startShare(connection: Connection) {
         connection.token
     );
     connection.channel = shareChannel;
-
-    shareChannel.on("new_request", onNewRequest);
-}
-
-function onNewRequest(data) {
-    requests.addRequest(data);
-}
+}
\ No newline at end of file