Initiate safer boot sequence on upgrades

pull/80/head
Zef Hemel 2022-09-14 09:32:47 +02:00
parent 2d51b2d4c2
commit 61ba3398ad
10 changed files with 89 additions and 63 deletions

View File

@ -19,10 +19,6 @@ export async function listCommands(): Promise<{ [key: string]: CommandDef }> {
return syscall("system.listCommands");
}
export async function getVersion(): Promise<string> {
return syscall("system.getVersion");
}
export async function reloadPlugs() {
syscall("system.reloadPlugs");
}

View File

@ -1,7 +1,7 @@
import { Knex } from "knex";
import { SysCallMapping } from "../system";
type Item = {
export type Item = {
page: string;
key: string;
value: any;

View File

@ -82,6 +82,19 @@ export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
return Promise.resolve(syscall.callback(ctx, ...args));
}
async localSyscall(
contextPlugName: string,
syscallName: string,
args: any[]
): Promise<any> {
return this.syscallWithContext(
// Mock the plug
{ plug: { name: contextPlugName } as any },
syscallName,
args
);
}
async load(
manifest: Manifest<HookT>,
sandboxFactory: SandboxFactory<HookT>

View File

@ -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"

View File

@ -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);
}
}
}

View File

@ -200,7 +200,6 @@ async function getBackLinks(pageName: string): Promise<BackLink[]> {
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) {

View File

@ -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<SilverBulletHooks>;
@ -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));

View File

@ -18,8 +18,5 @@ export function systemSyscalls(expressServer: ExpressServer): SysCallMapping {
"system.reloadPlugs": async () => {
return expressServer.reloadPlugs();
},
"system.getVersion": async () => {
return version;
},
};
}

View File

@ -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(

View File

@ -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();
},