From 61ba3398adaa2547c3c866bd6b3a63f79b71e39a Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Wed, 14 Sep 2022 09:32:47 +0200 Subject: [PATCH] Initiate safer boot sequence on upgrades --- .../plugos-silverbullet-syscall/system.ts | 4 - packages/plugos/syscalls/store.knex_node.ts | 2 +- packages/plugos/system.ts | 13 ++++ packages/plugs/core/core.plug.yaml | 7 -- packages/plugs/core/editor.ts | 30 -------- packages/plugs/core/page.ts | 2 +- packages/server/express_server.ts | 76 +++++++++++++++++-- packages/server/syscalls/system.ts | 3 - packages/web/editor.tsx | 11 +-- packages/web/syscalls/system.ts | 4 - 10 files changed, 89 insertions(+), 63 deletions(-) delete mode 100644 packages/plugs/core/editor.ts diff --git a/packages/plugos-silverbullet-syscall/system.ts b/packages/plugos-silverbullet-syscall/system.ts index 709a226e..79748eb5 100644 --- a/packages/plugos-silverbullet-syscall/system.ts +++ b/packages/plugos-silverbullet-syscall/system.ts @@ -19,10 +19,6 @@ export async function listCommands(): Promise<{ [key: string]: CommandDef }> { return syscall("system.listCommands"); } -export async function getVersion(): Promise { - return syscall("system.getVersion"); -} - export async function reloadPlugs() { syscall("system.reloadPlugs"); } diff --git a/packages/plugos/syscalls/store.knex_node.ts b/packages/plugos/syscalls/store.knex_node.ts index 18d48ea6..f05b7f68 100644 --- a/packages/plugos/syscalls/store.knex_node.ts +++ b/packages/plugos/syscalls/store.knex_node.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { SysCallMapping } from "../system"; -type Item = { +export type Item = { page: string; key: string; value: any; diff --git a/packages/plugos/system.ts b/packages/plugos/system.ts index 9de99355..4b3ff28d 100644 --- a/packages/plugos/system.ts +++ b/packages/plugos/system.ts @@ -82,6 +82,19 @@ export class System extends EventEmitter> { return Promise.resolve(syscall.callback(ctx, ...args)); } + async localSyscall( + contextPlugName: string, + syscallName: string, + args: any[] + ): Promise { + return this.syscallWithContext( + // Mock the plug + { plug: { name: contextPlugName } as any }, + syscallName, + args + ); + } + async load( manifest: Manifest, sandboxFactory: SandboxFactory diff --git a/packages/plugs/core/core.plug.yaml b/packages/plugs/core/core.plug.yaml index e8b408bd..db06363e 100644 --- a/packages/plugs/core/core.plug.yaml +++ b/packages/plugs/core/core.plug.yaml @@ -46,13 +46,6 @@ functions: path: "./page.ts:deletePage" command: name: "Page: Delete" - - editorInit: - path: "./editor.ts:editorInit" - env: client - events: - - plugs:loaded - # Backlinks indexLinks: path: "./page.ts:indexLinks" diff --git a/packages/plugs/core/editor.ts b/packages/plugs/core/editor.ts deleted file mode 100644 index 4d9b545a..00000000 --- a/packages/plugs/core/editor.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { get, set } from "@plugos/plugos-syscall/store"; -import { flashNotification } from "@silverbulletmd/plugos-silverbullet-syscall/editor"; -import { - getVersion, - invokeFunction, -} from "@silverbulletmd/plugos-silverbullet-syscall/system"; - -export async function editorInit() { - let currentVersion = await getVersion(); - console.log("Running version check", currentVersion); - let lastVersion = await get("$silverBulletVersion"); - console.log("Last version", lastVersion); - if (lastVersion !== currentVersion) { - await flashNotification( - "Version update detected, going to reload plugs..." - ); - await set("$spaceIndexed", false); - await set("$silverBulletVersion", currentVersion); - invokeFunction("client", "updatePlugsCommand"); - } else { - let spaceIndexed = await get("$spaceIndexed"); - console.log("Space indexed", spaceIndexed); - if (!spaceIndexed) { - await set("$spaceIndexed", true); - await invokeFunction("client", "reindexSpaceCommand"); - // Resetting this, because part of the reindex will be to wipe this too - await set("$silverBulletVersion", currentVersion); - } - } -} diff --git a/packages/plugs/core/page.ts b/packages/plugs/core/page.ts index ac2b713a..4e13a576 100644 --- a/packages/plugs/core/page.ts +++ b/packages/plugs/core/page.ts @@ -200,7 +200,6 @@ async function getBackLinks(pageName: string): Promise { export async function reindexCommand() { await flashNotification("Reindexing..."); await invokeFunction("server", "reindexSpace"); - await storeSet("$spaceIndexed", true); await flashNotification("Reindexing done"); } @@ -235,6 +234,7 @@ export async function reindexSpace() { tree: parsed, }); } + console.log("Indexing completed!"); } export async function clearPageIndex(page: string) { diff --git a/packages/server/express_server.ts b/packages/server/express_server.ts index 1976e861..bc043836 100644 --- a/packages/server/express_server.ts +++ b/packages/server/express_server.ts @@ -1,7 +1,7 @@ import express, { Express } from "express"; import { Manifest, SilverBulletHooks } from "@silverbulletmd/common/manifest"; import { EndpointHook } from "@plugos/plugos/hooks/endpoint"; -import { readdir, readFile } from "fs/promises"; +import { readdir, readFile, rm } from "fs/promises"; import { System } from "@plugos/plugos/system"; import { DiskSpacePrimitives } from "@silverbulletmd/common/spaces/disk_space_primitives"; import path from "path"; @@ -47,6 +47,8 @@ import { import { parseYamlSettings } from "@silverbulletmd/common/util"; import { SpacePrimitives } from "@silverbulletmd/common/spaces/space_primitives"; +import { version } from "./package.json"; + const globalModules: any = JSON.parse( readFileSync( nodeModulesDir + "/node_modules/@silverbulletmd/web/dist/global.plug.json", @@ -63,6 +65,10 @@ export type ServerOptions = { builtinPlugDir: string; password?: string; }; + +const storeVersionKey = "$silverBulletVersion"; +const indexRequiredKey = "$spaceIndexed"; + export class ExpressServer { app: Express; system: System; @@ -196,9 +202,6 @@ export class ExpressServer { setInterval(() => { this.space.updatePageList().catch(console.error); }, 5000); - - // Load plugs - this.reloadPlugs().catch(console.error); } rebuildMdExtensions() { @@ -243,20 +246,78 @@ export class ExpressServer { } async reloadPlugs() { + // Version check + let lastRunningVersion = await this.system.localSyscall( + "core", + "store.get", + [storeVersionKey] + ); + let upgrading = false; + if (lastRunningVersion !== version) { + upgrading = true; + console.log("Version change detected!"); + console.log("Going to re-bootstrap with the builtin set of plugs..."); + console.log("First removing existing plug files..."); + const existingPlugFiles = ( + await this.spacePrimitives.fetchFileList() + ).filter((meta) => meta.name.startsWith(plugPrefix)); + for (let plugFile of existingPlugFiles) { + await this.spacePrimitives.deleteFile(plugFile.name); + } + console.log("Now writing the default set of plugs..."); + await this.bootstrapBuiltinPlugs(); + await this.system.localSyscall("core", "store.set", [ + storeVersionKey, + version, + ]); + await this.system.localSyscall("core", "store.set", [ + "$spaceIndexed", + false, + ]); + } + await this.space.updatePageList(); + let allPlugs = await this.space.listPlugs(); + + // Sanity check: are there any plugs at all? If not, let's put back the core set if (allPlugs.length === 0) { await this.bootstrapBuiltinPlugs(); allPlugs = await this.space.listPlugs(); } await this.system.unloadAll(); - console.log("Loading plugs"); - console.log(allPlugs); + + console.log("Loading plugs", allPlugs); for (let plugName of allPlugs) { let { data } = await this.space.readAttachment(plugName, "string"); await this.system.load(JSON.parse(data as string), createSandbox); } this.rebuildMdExtensions(); + + let corePlug = this.system.loadedPlugs.get("core"); + if (!corePlug) { + console.error("Something went very wrong, 'core' plug not found"); + return; + } + + // If we're upgrading, update plugs from PLUGS file + // This will automatically reinvoke an plugReload() call + if (upgrading) { + console.log("Now updating plugs"); + await corePlug.invoke("updatePlugs", []); + } + + // Do we need to reindex this space? + if ( + !(await this.system.localSyscall("core", "store.get", [indexRequiredKey])) + ) { + console.log("Now reindexing space..."); + await corePlug.invoke("reindexSpace", []); + await this.system.localSyscall("core", "store.set", [ + indexRequiredKey, + true, + ]); + } } async start() { @@ -278,6 +339,9 @@ export class ExpressServer { await ensureFTSTable(this.db, "fts"); await this.ensureAndLoadSettings(); + // Load plugs + this.reloadPlugs().catch(console.error); + // Serve static files (javascript, css, html) this.app.use("/", express.static(this.distDir)); diff --git a/packages/server/syscalls/system.ts b/packages/server/syscalls/system.ts index 32786c16..73ad6e91 100644 --- a/packages/server/syscalls/system.ts +++ b/packages/server/syscalls/system.ts @@ -18,8 +18,5 @@ export function systemSyscalls(expressServer: ExpressServer): SysCallMapping { "system.reloadPlugs": async () => { return expressServer.reloadPlugs(); }, - "system.getVersion": async () => { - return version; - }, }; } diff --git a/packages/web/editor.tsx b/packages/web/editor.tsx index 04d85947..6ce1f934 100644 --- a/packages/web/editor.tsx +++ b/packages/web/editor.tsx @@ -224,13 +224,10 @@ export class Editor { // console.log("Navigating to anchor", pos); // We're going to look up the anchor through a direct page store query... - // TODO: This is a bit hacky, but it works for now - let posLookup = await this.system.syscallWithContext( - // Mock the "core" plug - { plug: { name: "core" } as any }, - "index.get", - [pageName, `a:${pageName}:@${pos}`] - ); + let posLookup = await this.system.localSyscall("core", "index.get", [ + pageName, + `a:${pageName}:@${pos}`, + ]); if (!posLookup) { return this.flashNotification( diff --git a/packages/web/syscalls/system.ts b/packages/web/syscalls/system.ts index 9e064c3f..c1bea876 100644 --- a/packages/web/syscalls/system.ts +++ b/packages/web/syscalls/system.ts @@ -1,7 +1,6 @@ import { SysCallMapping } from "@plugos/plugos/system"; import type { Editor } from "../editor"; import { CommandDef } from "../hooks/command"; -import { version } from "../package.json"; export function systemSyscalls(editor: Editor): SysCallMapping { return { @@ -33,9 +32,6 @@ export function systemSyscalls(editor: Editor): SysCallMapping { } return allCommands; }, - "system.getVersion": async () => { - return version; - }, "system.reloadPlugs": async () => { return editor.reloadPlugs(); },