From f9ff518e6d6368f65ead7634f459498b183081f2 Mon Sep 17 00:00:00 2001
From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>
Date: Tue, 9 Apr 2024 15:44:38 +0100
Subject: attempt to add plugin events to the plugin frontend api.

unable to test right now though
---
 frontend/src/plugin-loader.tsx | 46 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

(limited to 'frontend/src/plugin-loader.tsx')

diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx
index 7a87253f..75b09091 100644
--- a/frontend/src/plugin-loader.tsx
+++ b/frontend/src/plugin-loader.tsx
@@ -48,6 +48,9 @@ declare global {
   }
 }
 
+/** Map of event names to event listeners */
+type listenerMap = Map<string, Set<(...args: any) => any>>;
+
 const callPluginMethod = DeckyBackend.callable<[pluginName: string, method: string, ...args: any], any>(
   'loader/call_plugin_method',
 );
@@ -58,6 +61,8 @@ class PluginLoader extends Logger {
   private routerHook: RouterHook = new RouterHook();
   public toaster: Toaster = new Toaster();
   private deckyState: DeckyState = new DeckyState();
+  // stores a map of plugin names to all their event listeners
+  private pluginEventListeners: Map<string, listenerMap> = new Map();
 
   public frozenPluginsService = new FrozenPluginService(this.deckyState);
   public hiddenPluginsService = new HiddenPluginsService(this.deckyState);
@@ -81,6 +86,7 @@ class PluginLoader extends Logger {
     DeckyBackend.addEventListener('updater/update_download_percentage', () => {
       this.deckyState.setIsLoaderUpdating(true);
     });
+    DeckyBackend.addEventListener(`loader/plugin_event`, this.pluginEventListener);
 
     this.tabsHook.init();
 
@@ -513,6 +519,9 @@ class PluginLoader extends Logger {
           throw new Error(`Plugin ${pluginName} requested invalid backend api version ${version}.`);
         }
 
+        const eventListeners: listenerMap = new Map();
+        this.pluginEventListeners.set(pluginName, eventListeners);
+
         const backendAPI = {
           call: (methodName: string, ...args: any) => {
             return callPluginMethod(pluginName, methodName, ...args);
@@ -520,6 +529,20 @@ class PluginLoader extends Logger {
           callable: (methodName: string) => {
             return (...args: any) => callPluginMethod(pluginName, methodName, ...args);
           },
+          addEventListener: (event: string, listener: (...args: any) => any) => {
+            if (!eventListeners.has(event)) {
+              eventListeners.set(event, new Set([listener]));
+            } else {
+              eventListeners.get(event)?.add(listener);
+            }
+            return listener;
+          },
+          removeEventListener: (event: string, listener: (...args: any) => any) => {
+            if (eventListeners.has(event)) {
+              const set = eventListeners.get(event);
+              set?.delete(listener);
+            }
+          },
         };
 
         this.debug(`${pluginName} connected to backend API.`);
@@ -528,6 +551,29 @@ class PluginLoader extends Logger {
     };
   }
 
+  pluginEventListener = (data: { plugin: string; event: string; args: any }) => {
+    const { plugin, event, args } = data;
+    this.debug(`Recieved plugin event ${event} for ${plugin} with args`, args);
+    if (!this.pluginEventListeners.has(plugin)) {
+      this.warn(`plugin ${plugin} does not have event listeners`);
+      return;
+    }
+    const eventListeners = this.pluginEventListeners.get(plugin)!;
+    if (eventListeners.has(event)) {
+      for (const listener of eventListeners.get(event)!) {
+        (async () => {
+          try {
+            await listener(...args);
+          } catch (e) {
+            this.error(`error in event ${event}`, e, listener);
+          }
+        })();
+      }
+    } else {
+      this.warn(`event ${event} has no listeners`);
+    }
+  };
+
   createLegacyPluginAPI(pluginName: string) {
     const pluginAPI = {
       routerHook: this.routerHook,
-- 
cgit v1.2.3

