Lazy plugs (#596)

* Manifest caching and lazy loading of plug workers
* Fixes #546 Plug unloading after time out
This commit is contained in:
Zef Hemel
2023-12-06 18:44:48 +01:00
committed by GitHub
parent 8451680c01
commit 8527528af4
16 changed files with 226 additions and 67 deletions
+47 -20
View File
@@ -38,6 +38,12 @@ import { languageSyscalls } from "../common/syscalls/language.ts";
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
import { codeWidgetSyscalls } from "./syscalls/code_widget.ts";
import { clientCodeWidgetSyscalls } from "./syscalls/client_code_widget.ts";
import {
InMemoryManifestCache,
KVPrimitivesManifestCache,
} from "../plugos/manifest_cache.ts";
const plugNameExtractRegex = /\/(.+)\.plug\.js$/;
export class ClientSystem {
commandHook: CommandHook;
@@ -51,11 +57,18 @@ export class ClientSystem {
private client: Client,
private mq: MessageQueue,
private ds: DataStore,
// private dbPrefix: string,
private eventHook: EventHook,
) {
// Only set environment to "client" when running in thin client mode, otherwise we run everything locally (hybrid)
this.system = new System(client.syncMode ? undefined : "client");
this.system = new System(
client.syncMode ? undefined : "client",
{
manifestCache: new KVPrimitivesManifestCache<SilverBulletHooks>(
ds.kv,
"manifest",
),
},
);
this.system.addHook(this.eventHook);
@@ -93,22 +106,28 @@ export class ClientSystem {
this.slashCommandHook = new SlashCommandHook(this.client);
this.system.addHook(this.slashCommandHook);
this.eventHook.addLocalListener("file:changed", async (path: string) => {
if (path.startsWith("_plug/") && path.endsWith(".plug.js")) {
console.log("Plug updated, reloading:", path);
this.system.unload(path);
const plug = await this.system.load(
new URL(`/${path}`, location.href),
createSandbox,
this.client.settings.plugOverrides,
);
if ((plug.manifest! as Manifest).syntax) {
// If there are syntax extensions, rebuild the markdown parser immediately
this.updateMarkdownParser();
this.eventHook.addLocalListener(
"file:changed",
async (path: string, _selfUpdate, _oldHash, newHash) => {
if (path.startsWith("_plug/") && path.endsWith(".plug.js")) {
const plugName = plugNameExtractRegex.exec(path)![1];
console.log("Plug updated, reloading", plugName, "from", path);
this.system.unload(path);
const plug = await this.system.load(
new URL(`/${path}`, location.href),
plugName,
newHash,
createSandbox,
this.client.settings.plugOverrides,
);
if ((plug.manifest! as Manifest).syntax) {
// If there are syntax extensions, rebuild the markdown parser immediately
this.updateMarkdownParser();
}
this.client.debouncedPlugsUpdatedEvent();
}
this.client.debouncedPlugsUpdatedEvent();
}
});
},
);
// Debugging
// this.eventHook.addLocalListener("file:listed", (files) => {
@@ -177,15 +196,23 @@ export class ClientSystem {
await space.updatePageList();
await this.system.unloadAll();
console.log("(Re)loading plugs");
await Promise.all((await space.listPlugs()).map(async (plugName) => {
await Promise.all((await space.listPlugs()).map(async (plugMeta) => {
try {
const plugName = plugNameExtractRegex.exec(plugMeta.name)![1];
await this.system.load(
new URL(plugName, location.origin),
new URL(plugMeta.name, location.origin),
plugName,
plugMeta.lastModified,
createSandbox,
this.client.settings.plugOverrides,
);
} catch (e: any) {
console.error("Could not load plug", plugName, "error:", e.message);
console.error(
"Could not load plug",
plugMeta.name,
"error:",
e.message,
);
}
}));
}