Plugbox cleanup
This commit is contained in:
+12
-1
@@ -19,9 +19,20 @@
|
||||
"@parcel/validator-typescript": "^2.3.2",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"assert": "^2.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"events": "^3.3.0",
|
||||
"os-browserify": "^0.3.0",
|
||||
"parcel": "^2.3.2",
|
||||
"path-browserify": "^1.0.1",
|
||||
"querystring-es3": "^0.2.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tty-browserify": "^0.0.1",
|
||||
"typescript": ">=3.0.0",
|
||||
"uglify-js": "^3.15.1"
|
||||
"uglify-js": "^3.15.1",
|
||||
"url": "^0.11.0",
|
||||
"util": "^0.12.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"@lezer/common": "git://github.com/zefhemel/common.git#046c880d1fcab713cadad327a5b7d8bb5de6522c"
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
|
||||
import React, { useEffect, useReducer } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import coreManifest from "./generated/core.plugin.json";
|
||||
import coreManifest from "./generated/core.plug.json";
|
||||
// @ts-ignore
|
||||
window.coreManifest = coreManifest;
|
||||
import { AppEvent, AppEventDispatcher, ClickEvent } from "./app_event";
|
||||
@@ -36,9 +36,10 @@ import { lineWrapper } from "./lineWrapper";
|
||||
import { markdown } from "./markdown";
|
||||
import { IPageNavigator, PathPageNavigator } from "./navigator";
|
||||
import customMarkDown from "./parser";
|
||||
import { BrowserSystem } from "./plugins/browser_system";
|
||||
import { Plugin } from "./plugins/runtime";
|
||||
import { slashCommandRegexp } from "./plugins/types";
|
||||
import { BrowserSystem } from "./plugbox_browser/browser_system";
|
||||
import { Plugin } from "../../plugbox/src/runtime";
|
||||
import { slashCommandRegexp } from "../../plugbox/src/types";
|
||||
|
||||
import reducer from "./reducer";
|
||||
import { smartQuoteKeymap } from "./smart_quotes";
|
||||
import { Space } from "./space";
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
import { PluginLoader, System } from "./runtime";
|
||||
import { Manifest } from "./types";
|
||||
import { PluginLoader, System } from "../../../plugbox/src/runtime";
|
||||
import { Manifest } from "../../../plugbox/src/types";
|
||||
import { sleep } from "../util";
|
||||
|
||||
export class BrowserLoader implements PluginLoader {
|
||||
@@ -43,7 +43,7 @@ export class BrowserSystem extends System {
|
||||
async bootServiceWorker() {
|
||||
// @ts-ignore
|
||||
let reg = navigator.serviceWorker.register(
|
||||
new URL("../plugin_sw.ts", import.meta.url),
|
||||
new URL("../plugbox_sw.ts", import.meta.url),
|
||||
{
|
||||
type: "module",
|
||||
scope: "/",
|
||||
@@ -1,12 +1,10 @@
|
||||
import { Manifest } from "./plugins/types";
|
||||
import { Manifest } from "../../plugbox/src/types";
|
||||
|
||||
import { openDB, wrap, unwrap } from "idb";
|
||||
import { openDB } from "idb";
|
||||
|
||||
const rootUrl = location.origin + "/plugin";
|
||||
|
||||
// Storing manifests in IndexedDB, y'all
|
||||
let manifestCache = caches.open("manifests");
|
||||
|
||||
const db = openDB("manifests-store", undefined, {
|
||||
upgrade(db) {
|
||||
db.createObjectStore("manifests");
|
||||
@@ -1,187 +0,0 @@
|
||||
import { Manifest } from "./types";
|
||||
|
||||
interface SysCallMapping {
|
||||
// TODO: Better typing
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export class FunctionWorker {
|
||||
private worker: Worker;
|
||||
private inited: Promise<any>;
|
||||
private initCallback: any;
|
||||
private invokeResolve?: (result?: any) => void;
|
||||
private invokeReject?: (reason?: any) => void;
|
||||
private plugin: Plugin;
|
||||
|
||||
constructor(plugin: Plugin, pathPrefix: string, name: string) {
|
||||
// this.worker = new Worker(new URL("function_worker.ts", import.meta.url), {
|
||||
// type: "classic",
|
||||
// });
|
||||
let worker = window.Worker;
|
||||
this.worker = new worker("/function_worker.js");
|
||||
|
||||
// console.log("Starting worker", this.worker);
|
||||
this.worker.onmessage = this.onmessage.bind(this);
|
||||
this.worker.postMessage({
|
||||
type: "boot",
|
||||
prefix: pathPrefix,
|
||||
name: name,
|
||||
// @ts-ignore
|
||||
userAgent: navigator.userAgent,
|
||||
});
|
||||
this.inited = new Promise((resolve) => {
|
||||
this.initCallback = resolve;
|
||||
});
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
async onmessage(evt: MessageEvent) {
|
||||
let data = evt.data;
|
||||
if (!data) return;
|
||||
switch (data.type) {
|
||||
case "inited":
|
||||
this.initCallback();
|
||||
break;
|
||||
case "syscall":
|
||||
let result = await this.plugin.system.syscall(data.name, data.args);
|
||||
|
||||
this.worker.postMessage({
|
||||
type: "syscall-response",
|
||||
id: data.id,
|
||||
data: result,
|
||||
});
|
||||
break;
|
||||
case "result":
|
||||
this.invokeResolve!(data.result);
|
||||
break;
|
||||
case "error":
|
||||
this.invokeReject!(data.reason);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown message type", data);
|
||||
}
|
||||
}
|
||||
|
||||
async invoke(args: Array<any>): Promise<any> {
|
||||
await this.inited;
|
||||
this.worker.postMessage({
|
||||
type: "invoke",
|
||||
args: args,
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
this.invokeResolve = resolve;
|
||||
this.invokeReject = reject;
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.worker.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
export interface PluginLoader {
|
||||
load(name: string, manifest: Manifest): Promise<void>;
|
||||
}
|
||||
|
||||
export class Plugin {
|
||||
pathPrefix: string;
|
||||
system: System;
|
||||
private runningFunctions: Map<string, FunctionWorker>;
|
||||
public manifest?: Manifest;
|
||||
private name: string;
|
||||
|
||||
constructor(system: System, pathPrefix: string, name: string) {
|
||||
this.name = name;
|
||||
this.pathPrefix = `${pathPrefix}/${name}`;
|
||||
this.system = system;
|
||||
this.runningFunctions = new Map<string, FunctionWorker>();
|
||||
}
|
||||
|
||||
async load(manifest: Manifest) {
|
||||
this.manifest = manifest;
|
||||
await this.system.pluginLoader.load(this.name, manifest);
|
||||
await this.dispatchEvent("load");
|
||||
}
|
||||
|
||||
async invoke(name: string, args: Array<any>): Promise<any> {
|
||||
if (!this.runningFunctions.has(name)) {
|
||||
this.runningFunctions.set(
|
||||
name,
|
||||
new FunctionWorker(this, this.pathPrefix, name)
|
||||
);
|
||||
}
|
||||
return await this.runningFunctions.get(name)!.invoke(args);
|
||||
}
|
||||
|
||||
async dispatchEvent(name: string, data?: any): Promise<any[]> {
|
||||
let functionsToSpawn = this.manifest!.events[name];
|
||||
if (functionsToSpawn) {
|
||||
return await Promise.all(
|
||||
functionsToSpawn.map(
|
||||
async (functionToSpawn: string) =>
|
||||
await this.invoke(functionToSpawn, [data])
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async stop() {
|
||||
for (const [functionname, worker] of Object.entries(
|
||||
this.runningFunctions
|
||||
)) {
|
||||
console.log(`Stopping ${functionname}`);
|
||||
worker.stop();
|
||||
}
|
||||
this.runningFunctions = new Map<string, FunctionWorker>();
|
||||
}
|
||||
}
|
||||
|
||||
export class System {
|
||||
protected plugins: Map<string, Plugin>;
|
||||
protected pathPrefix: string;
|
||||
registeredSyscalls: SysCallMapping;
|
||||
pluginLoader: PluginLoader;
|
||||
|
||||
constructor(PluginLoader: PluginLoader, pathPrefix: string) {
|
||||
this.pluginLoader = PluginLoader;
|
||||
this.pathPrefix = pathPrefix;
|
||||
this.plugins = new Map<string, Plugin>();
|
||||
this.registeredSyscalls = {};
|
||||
}
|
||||
|
||||
registerSyscalls(...registrationObjects: Array<SysCallMapping>) {
|
||||
for (const registrationObject of registrationObjects) {
|
||||
for (let p in registrationObject) {
|
||||
this.registeredSyscalls[p] = registrationObject[p];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async syscall(name: string, args: Array<any>): Promise<any> {
|
||||
const callback = this.registeredSyscalls[name];
|
||||
if (!name) {
|
||||
throw Error(`Unregistered syscall ${name}`);
|
||||
}
|
||||
if (!callback) {
|
||||
throw Error(`Registered but not implemented syscall ${name}`);
|
||||
}
|
||||
return Promise.resolve(callback(...args));
|
||||
}
|
||||
|
||||
async load(name: string, manifest: Manifest): Promise<Plugin> {
|
||||
const plugin = new Plugin(this, this.pathPrefix, name);
|
||||
await plugin.load(manifest);
|
||||
this.plugins.set(name, plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
async stop(): Promise<void[]> {
|
||||
return Promise.all(
|
||||
Array.from(this.plugins.values()).map((plugin) => plugin.stop())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Starting");
|
||||
@@ -1,30 +0,0 @@
|
||||
export interface Manifest {
|
||||
events: { [key: string]: string[] };
|
||||
commands: {
|
||||
[key: string]: CommandDef;
|
||||
};
|
||||
functions: {
|
||||
[key: string]: FunctionDef;
|
||||
};
|
||||
}
|
||||
|
||||
export const slashCommandRegexp = /\/[\w\-]*/;
|
||||
|
||||
export interface CommandDef {
|
||||
// Function name to invoke
|
||||
invoke: string;
|
||||
|
||||
// Bind to keyboard shortcut
|
||||
key?: string;
|
||||
mac?: string;
|
||||
|
||||
// If to show in slash invoked menu and if so, with what label
|
||||
// should match slashCommandRegexp
|
||||
slashCommand?: string;
|
||||
}
|
||||
|
||||
export interface FunctionDef {
|
||||
path: string;
|
||||
functionName?: string;
|
||||
code?: string;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { CommandDef } from "./plugins/types";
|
||||
import { CommandDef } from "../../plugbox/src/types";
|
||||
|
||||
export type PageMeta = {
|
||||
name: string;
|
||||
|
||||
+963
-3
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user