summaryrefslogtreecommitdiff
path: root/frontend/src/plugin-loader.ts
diff options
context:
space:
mode:
authorJonas Dellinger <jonas@dellinger.dev>2022-05-13 19:14:47 +0200
committerJonas Dellinger <jonas@dellinger.dev>2022-05-13 19:14:47 +0200
commit74438a31458af8bddd08d90eacc6d63677bab844 (patch)
treea7bfc044941f65c7f9971c5386c463eac31be768 /frontend/src/plugin-loader.ts
parent945db5de4788feefebc845817752472419051640 (diff)
downloaddecky-loader-74438a31458af8bddd08d90eacc6d63677bab844.tar.gz
decky-loader-74438a31458af8bddd08d90eacc6d63677bab844.zip
Work on react frontend loader
Diffstat (limited to 'frontend/src/plugin-loader.ts')
-rw-r--r--frontend/src/plugin-loader.ts131
1 files changed, 131 insertions, 0 deletions
diff --git a/frontend/src/plugin-loader.ts b/frontend/src/plugin-loader.ts
new file mode 100644
index 00000000..9a72ea84
--- /dev/null
+++ b/frontend/src/plugin-loader.ts
@@ -0,0 +1,131 @@
+import Logger from './logger';
+import TabsHook from './tabs-hook';
+
+interface Plugin {
+ title: any;
+ content: any;
+ icon: any;
+ onDismount?(): void;
+}
+
+class PluginLoader extends Logger {
+ private pluginInstances: Record<string, Plugin> = {};
+ private tabsHook: TabsHook;
+ private lock = 0;
+
+ constructor() {
+ super(PluginLoader.name);
+
+ this.log('Initialized');
+ this.tabsHook = new TabsHook();
+ }
+
+ dismountPlugin(name: string) {
+ this.log(`Dismounting ${name}`);
+ this.pluginInstances[name]?.onDismount?.();
+ delete this.pluginInstances[name];
+ this.tabsHook.removeById(name);
+ }
+
+ async loadAllPlugins() {
+ this.log('Loading all plugins');
+ const plugins = await (await fetch(`http://127.0.0.1:1337/plugins`)).json();
+ this.log('Received:', plugins);
+
+ return Promise.all(plugins.map((plugin) => this.loadPlugin(plugin.name)));
+ }
+
+ async loadPlugin(name) {
+ this.log('Loading Plugin:', name);
+
+ try {
+ while (this.lock === 1) {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ this.lock = 1;
+
+ if (this.pluginInstances[name]) {
+ this.dismountPlugin(name);
+ }
+
+ const response = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`);
+ const code = await response.text();
+
+ const pluginAPI = PluginLoader.createPluginAPI(name);
+ this.pluginInstances[name] = await eval(code)(pluginAPI);
+
+ const { title, icon, content } = this.pluginInstances[name];
+ this.tabsHook.add({
+ id: name,
+ title,
+ icon,
+ content,
+ });
+ } catch (e) {
+ console.error(e);
+ } finally {
+ this.lock = 0;
+ }
+ }
+
+ dismountAll() {
+ for (const name of Object.keys(this.pluginInstances)) {
+ this.dismountPlugin(name);
+ }
+ }
+
+ static createPluginAPI(pluginName) {
+ return {
+ async callServerMethod(methodName, args = {}) {
+ const response = await fetch(`http://127.0.0.1:1337/methods/${methodName}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(args),
+ });
+
+ return response.json();
+ },
+ async callPluginMethod(methodName, args = {}) {
+ const response = await fetch(`http://127.0.0.1:1337/plugins/${pluginName}/methods/${methodName}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ args,
+ }),
+ });
+
+ return response.json();
+ },
+ fetchNoCors(url, request: any = {}) {
+ let args = { method: 'POST', headers: {}, body: '' };
+ const req = { ...args, ...request, url, data: request.body };
+ return this.callServerMethod('http_request', req);
+ },
+ executeInTab(tab, runAsync, code) {
+ return this.callServerMethod('execute_in_tab', {
+ tab,
+ run_async: runAsync,
+ code,
+ });
+ },
+ injectCssIntoTab(tab, style) {
+ return this.callServerMethod('inject_css_into_tab', {
+ tab,
+ style,
+ });
+ },
+ removeCssFromTab(tab, cssId) {
+ return this.callServerMethod('remove_css_from_tab', {
+ tab,
+ css_id: cssId,
+ });
+ },
+ };
+ }
+}
+
+export default PluginLoader;