about summary refs log tree commit diff
path: root/assets/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-02-19 19:47:44 +0100
committerMel <einebeere@gmail.com>2022-02-19 19:58:33 +0100
commit5384c34952b031995ecb8aa58d72954b0c685e18 (patch)
treeba7c9dfe77d77e5c4bce03c60d08f056f40235c0 /assets/src
parentd5f7201eb7b10826e77eccb33f9cca784261091f (diff)
downloadrook-5384c34952b031995ecb8aa58d72954b0c685e18.tar.zst
rook-5384c34952b031995ecb8aa58d72954b0c685e18.zip
Re-architect event handler for simplicity
Diffstat (limited to 'assets/src')
-rw-r--r--assets/src/network/channel/messages/event_handler.ts166
-rw-r--r--assets/src/network/channel/messages/message_handler.ts25
-rw-r--r--assets/src/network/channel/messages/messages.ts5
3 files changed, 25 insertions, 171 deletions
diff --git a/assets/src/network/channel/messages/event_handler.ts b/assets/src/network/channel/messages/event_handler.ts
deleted file mode 100644
index d0936e0..0000000
--- a/assets/src/network/channel/messages/event_handler.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import type { Channel } from "phoenix";
-import type {
-    AnyMessage,
-    EventName,
-    MessageForEvent,
-    TokenizedMessage,
-} from "./messages";
-
-// The single handler for all events, which is used to dispatch to the correct
-// handler for each event and token.
-// Every event can only have either one single handler, or multiple handlers for different tokens.
-export type EventHandler = {
-    [EN in EventName]?: HandlerForMessage<MessageForEvent<EN>>;
-};
-
-// A handler for a specific event and message.
-// A message handler can either be a single handler or can have multiple handlers for different tokens
-type HandlerForMessage<M extends AnyMessage> =
-    // A single handler
-    | { type: "single"; handler: HandlerFn<M> }
-    // A group of handlers for different tokens
-    // Can only be used for messages which have a "token" field.
-    | (M extends TokenizedMessage
-          ? {
-                type: "token";
-                handler: HandlerForTokenizedMessage<M>;
-            }
-          : never);
-
-// A map of token to handler for a specific event.
-export type HandlerForTokenizedMessage<M extends TokenizedMessage> = Map<
-    string,
-    HandlerFn<M>
->;
-
-// A function which handles a message for a specific event.
-export type HandlerFn<M extends AnyMessage> = (message?: M) => void;
-
-// A function that unregisters a single event handler.
-export type UnregisterFn = () => void;
-
-// Adds a single handler for a specific event.
-export function registerHandler<M extends AnyMessage>(
-    eventHandler: EventHandler,
-    channel: Channel,
-    event: M["event_name"],
-    handler: HandlerFn<M>
-) {
-    const messageHandler: HandlerForMessage<M> = {
-        type: "single",
-        handler,
-    };
-
-    let unregisterChannelEvent: UnregisterFn | null = null;
-    if (typeof eventHandler[event] === "undefined") {
-        // Register a new event handler, since this is the first handler for this event
-        unregisterChannelEvent = registerNewEvent<M>(
-            channel,
-            messageHandler,
-            event
-        );
-    } else {
-        throw new Error("Event already has a handler attached to it.");
-    }
-
-    // TODO: Check if we there is a possibility for TS to accept this.
-    // Technically this should work, because TS is afraid of the generic type parameter
-    // not matching the message type of the handler. But it should match, since
-    // the handler should accept only the exact message type from which the event_name was derived.
-    // @ts-ignore
-    eventHandler[event] = messageHandler;
-
-    // This could cause problems if we would allow to redefine the handler,
-    // as that would cause the Unsubscribe function to no longer apply to this specific handler,
-    // but as we throw an error on redefinition, this should be fine.
-    return () => {
-        delete eventHandler[event];
-
-        // If we registered a new event on the channel, we need to unregister it
-        if (unregisterChannelEvent !== null) {
-            unregisterChannelEvent();
-        }
-    };
-}
-
-export function registerHandlerForSpecificToken<M extends TokenizedMessage>(
-    eventHandler: EventHandler,
-    channel: Channel,
-    event: M["event_name"],
-    token: string,
-    handler: HandlerFn<M>
-): UnregisterFn {
-    const messageHandler = eventHandler[event];
-
-    if (typeof messageHandler === "undefined") {
-        // TODO: Same as above, this should probably be valid.
-        // @ts-ignore
-        eventHandler[event] = {
-            type: "token",
-            handler: new Map<string, HandlerFn<M>>(),
-        };
-        // @ts-ignore
-        registerNewEvent<M>(channel, eventHandler[event], event);
-    } else if (
-        messageHandler.type === "token" &&
-        messageHandler.handler.size === 0
-    ) {
-        // If there is already a token handler with no token, we need to register the event again
-        // @ts-ignore
-        registerNewEvent<M>(channel, messageHandler, event);
-    } else if (messageHandler.type === "single") {
-        throw new Error("Event already has a handler attached to it.");
-    }
-
-    // @ts-ignore This shoudl be valid, as we derive the event name from the message type.
-    const tokenHandler: HandlerForTokenizedMessage<M> =
-        eventHandler[event].handler;
-    tokenHandler.set(token, handler);
-
-    return () => {
-        // Unregister the handler for this specific token
-        tokenHandler.delete(token);
-        // If there are no more handlers for this event, we can unregister the event
-        if (tokenHandler.size === 0) {
-            // We should technically use the ref here, but we don't yet have a way to get it, as the event
-            // could have been registered outside of this function call.
-            channel.off(event);
-        }
-    };
-}
-
-// Adds a callback for a new event
-function registerNewEvent<M extends AnyMessage>(
-    channel: Channel,
-    messageHandler: HandlerForMessage<M>,
-    event: M["event_name"]
-): UnregisterFn {
-    const callback = (data: M) => {
-        // Add event_name to message, so the type definitions match
-        const message = { event_name: event, ...data };
-        onEvent<M>(messageHandler, message);
-    };
-
-    const ref = channel.on(event, callback);
-
-    return () => channel.off(event, ref);
-}
-
-function onEvent<M extends AnyMessage>(
-    messageHandler: HandlerForMessage<M>,
-    message: M
-) {
-    if (messageHandler.type === "token") {
-        const token: string = message["token"];
-
-        const handler = messageHandler.handler.get(token);
-
-        if (typeof handler !== "undefined") {
-            (handler as HandlerFn<M>)(message);
-        } else {
-            console.warn(`Received message for unknown token: ${token}`);
-        }
-    } else {
-        messageHandler.handler(message);
-    }
-}
diff --git a/assets/src/network/channel/messages/message_handler.ts b/assets/src/network/channel/messages/message_handler.ts
new file mode 100644
index 0000000..2aefa1d
--- /dev/null
+++ b/assets/src/network/channel/messages/message_handler.ts
@@ -0,0 +1,25 @@
+import type { AnyMessage, RequestMessage, ShareMessage } from "./messages";
+
+export type HandlerFn<Message> = (message: Message) => void;
+
+export type MessageHandler<Messages extends AnyMessage> = {
+    [M in Messages as M["event_name"]]?: HandlerFn<M>;
+};
+
+export type RequestMessageHandler = MessageHandler<RequestMessage>;
+export type ShareMessageHandler = MessageHandler<ShareMessage>;
+
+const defaultHandlerFn: HandlerFn<AnyMessage> = m => {
+    console.error(
+        `Received unknown event "${m.event_name}": ${JSON.stringify(m)}`
+    );
+};
+
+export function routeEventToHandler(
+    event: string,
+    message: any,
+    handlers: MessageHandler<AnyMessage>
+): void {
+    const handler = handlers[event] || defaultHandlerFn;
+    handler(message);
+}
diff --git a/assets/src/network/channel/messages/messages.ts b/assets/src/network/channel/messages/messages.ts
index 24380ae..7eee4a8 100644
--- a/assets/src/network/channel/messages/messages.ts
+++ b/assets/src/network/channel/messages/messages.ts
@@ -1,11 +1,6 @@
 export type AnyMessage = ShareMessage | RequestMessage;
 
 export type EventName = AnyMessage["event_name"];
-export type MessageForEvent<EN> = Extract<AnyMessage, { event_name: EN }>;
-
-export type TokenizedMessage = {
-    token: string;
-} & AnyMessage;
 
 // Messages for the sharer