More event refactoring work
parent
593597454a
commit
c3d384330d
|
@ -5,64 +5,59 @@ import type { SpacePrimitives } from "./space_primitives.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events exposed:
|
* Events exposed:
|
||||||
* - file:changed (FileMeta)
|
* - file:changed (string, localUpdate: boolean)
|
||||||
* - file:deleted (string)
|
* - file:deleted (string)
|
||||||
* - file:listed (FileMeta[])
|
* - file:listed (FileMeta[])
|
||||||
* - page:saved (string, FileMeta)
|
* - page:saved (string, FileMeta)
|
||||||
* - page:deleted (string)
|
* - page:deleted (string)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class EventedSpacePrimitives implements SpacePrimitives {
|
export class EventedSpacePrimitives implements SpacePrimitives {
|
||||||
private fileMetaCache = new Map<string, FileMeta>();
|
alreadyFetching = false;
|
||||||
initialFileListLoad = true;
|
initialFileListLoad = true;
|
||||||
|
|
||||||
|
spaceSnapshot: Record<string, number> = {};
|
||||||
constructor(
|
constructor(
|
||||||
private wrapped: SpacePrimitives,
|
private wrapped: SpacePrimitives,
|
||||||
private eventHook: EventHook,
|
private eventHook: EventHook,
|
||||||
private eventsToDispatch = [
|
|
||||||
"file:changed",
|
|
||||||
"file:deleted",
|
|
||||||
"file:listed",
|
|
||||||
"page:saved",
|
|
||||||
"page:deleted",
|
|
||||||
],
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
dispatchEvent(name: string, ...args: any[]): Promise<any[]> {
|
dispatchEvent(name: string, ...args: any[]): Promise<any[]> {
|
||||||
if (this.eventsToDispatch.includes(name)) {
|
|
||||||
return this.eventHook.dispatchEvent(name, ...args);
|
return this.eventHook.dispatchEvent(name, ...args);
|
||||||
} else {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchFileList(): Promise<FileMeta[]> {
|
async fetchFileList(): Promise<FileMeta[]> {
|
||||||
const newFileList = await this.wrapped.fetchFileList();
|
const newFileList = await this.wrapped.fetchFileList();
|
||||||
const deletedFiles = new Set<string>(this.fileMetaCache.keys());
|
if (this.alreadyFetching) {
|
||||||
|
// Avoid race conditions
|
||||||
|
return newFileList;
|
||||||
|
}
|
||||||
|
// console.log("HEREEREEEREEREE");
|
||||||
|
this.alreadyFetching = true;
|
||||||
|
const deletedFiles = new Set<string>(Object.keys(this.spaceSnapshot));
|
||||||
for (const meta of newFileList) {
|
for (const meta of newFileList) {
|
||||||
const oldFileMeta = this.fileMetaCache.get(meta.name);
|
const oldHash = this.spaceSnapshot[meta.name];
|
||||||
const newFileMeta: FileMeta = { ...meta };
|
const newHash = meta.lastModified;
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
// New file scenario
|
// New file scenario
|
||||||
!oldFileMeta && !this.initialFileListLoad
|
!oldHash && !this.initialFileListLoad
|
||||||
) || (
|
) || (
|
||||||
// Changed file scenario
|
// Changed file scenario
|
||||||
oldFileMeta &&
|
oldHash &&
|
||||||
oldFileMeta.lastModified !== newFileMeta.lastModified
|
oldHash !== newHash
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.dispatchEvent("file:changed", newFileMeta);
|
this.dispatchEvent("file:changed", meta.name);
|
||||||
}
|
}
|
||||||
// Page found, not deleted
|
// Page found, not deleted
|
||||||
deletedFiles.delete(meta.name);
|
deletedFiles.delete(meta.name);
|
||||||
|
|
||||||
// Update in cache
|
// Update in snapshot
|
||||||
this.fileMetaCache.set(meta.name, newFileMeta);
|
this.spaceSnapshot[meta.name] = newHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const deletedFile of deletedFiles) {
|
for (const deletedFile of deletedFiles) {
|
||||||
this.fileMetaCache.delete(deletedFile);
|
delete this.spaceSnapshot[deletedFile];
|
||||||
this.dispatchEvent("file:deleted", deletedFile);
|
this.dispatchEvent("file:deleted", deletedFile);
|
||||||
|
|
||||||
if (deletedFile.endsWith(".md")) {
|
if (deletedFile.endsWith(".md")) {
|
||||||
|
@ -71,28 +66,18 @@ export class EventedSpacePrimitives implements SpacePrimitives {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileList = [...new Set(this.fileMetaCache.values())];
|
this.dispatchEvent("file:listed", newFileList);
|
||||||
this.dispatchEvent("file:listed", fileList);
|
this.alreadyFetching = false;
|
||||||
this.initialFileListLoad = false;
|
this.initialFileListLoad = false;
|
||||||
return fileList;
|
return newFileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
async readFile(
|
async readFile(
|
||||||
name: string,
|
name: string,
|
||||||
): Promise<{ data: Uint8Array; meta: FileMeta }> {
|
): Promise<{ data: Uint8Array; meta: FileMeta }> {
|
||||||
const data = await this.wrapped.readFile(name);
|
const data = await this.wrapped.readFile(name);
|
||||||
const previousMeta = this.fileMetaCache.get(name);
|
this.triggerEventsAndCache(name, data.meta.lastModified);
|
||||||
const newMeta = data.meta;
|
return data;
|
||||||
if (previousMeta) {
|
|
||||||
if (previousMeta.lastModified !== newMeta.lastModified) {
|
|
||||||
// Page changed since last cached metadata, trigger event
|
|
||||||
this.dispatchEvent("file:changed", newMeta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
data: data.data,
|
|
||||||
meta: this.metaCacher(name, newMeta),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async writeFile(
|
async writeFile(
|
||||||
|
@ -108,9 +93,9 @@ export class EventedSpacePrimitives implements SpacePrimitives {
|
||||||
meta,
|
meta,
|
||||||
);
|
);
|
||||||
if (!selfUpdate) {
|
if (!selfUpdate) {
|
||||||
this.dispatchEvent("file:changed", newMeta);
|
this.dispatchEvent("file:changed", name, true);
|
||||||
}
|
}
|
||||||
this.metaCacher(name, newMeta);
|
this.spaceSnapshot[name] = newMeta.lastModified;
|
||||||
|
|
||||||
// This can happen async
|
// This can happen async
|
||||||
if (name.endsWith(".md")) {
|
if (name.endsWith(".md")) {
|
||||||
|
@ -136,17 +121,21 @@ export class EventedSpacePrimitives implements SpacePrimitives {
|
||||||
return newMeta;
|
return newMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
triggerEventsAndCache(name: string, newHash: number) {
|
||||||
|
const oldHash = this.spaceSnapshot[name];
|
||||||
|
if (oldHash && oldHash !== newHash) {
|
||||||
|
// Page changed since last cached metadata, trigger event
|
||||||
|
this.dispatchEvent("file:changed", name);
|
||||||
|
}
|
||||||
|
this.spaceSnapshot[name] = newHash;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
async getFileMeta(name: string): Promise<FileMeta> {
|
async getFileMeta(name: string): Promise<FileMeta> {
|
||||||
try {
|
try {
|
||||||
const oldMeta = this.fileMetaCache.get(name);
|
|
||||||
const newMeta = await this.wrapped.getFileMeta(name);
|
const newMeta = await this.wrapped.getFileMeta(name);
|
||||||
if (oldMeta) {
|
this.triggerEventsAndCache(name, newMeta.lastModified);
|
||||||
if (oldMeta.lastModified !== newMeta.lastModified) {
|
return newMeta;
|
||||||
// Changed on disk, trigger event
|
|
||||||
this.dispatchEvent("file:changed", newMeta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.metaCacher(name, newMeta);
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log("Checking error", e, name);
|
console.log("Checking error", e, name);
|
||||||
if (e.message === "Not found") {
|
if (e.message === "Not found") {
|
||||||
|
@ -167,15 +156,7 @@ export class EventedSpacePrimitives implements SpacePrimitives {
|
||||||
}
|
}
|
||||||
// await this.getPageMeta(name); // Check if page exists, if not throws Error
|
// await this.getPageMeta(name); // Check if page exists, if not throws Error
|
||||||
await this.wrapped.deleteFile(name);
|
await this.wrapped.deleteFile(name);
|
||||||
this.fileMetaCache.delete(name);
|
delete this.spaceSnapshot[name];
|
||||||
this.dispatchEvent("file:deleted", name);
|
this.dispatchEvent("file:deleted", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private metaCacher(name: string, meta: FileMeta): FileMeta {
|
|
||||||
if (meta.lastModified !== 0) {
|
|
||||||
// Don't cache metadata for pages with a 0 lastModified timestamp (usualy dynamically generated pages)
|
|
||||||
this.fileMetaCache.set(name, meta);
|
|
||||||
}
|
|
||||||
return meta;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
import type { CommandDef } from "../../web/hooks/command.ts";
|
import type { CommandDef } from "../../web/hooks/command.ts";
|
||||||
import { syscall } from "./syscall.ts";
|
import { syscall } from "./syscall.ts";
|
||||||
|
|
||||||
|
export function invoke(
|
||||||
|
name: string,
|
||||||
|
...args: any[]
|
||||||
|
): Promise<any> {
|
||||||
|
return syscall("system.invoke", name, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @deprecated use invoke instead
|
||||||
export function invokeFunction(
|
export function invokeFunction(
|
||||||
env: string,
|
env: string,
|
||||||
name: string,
|
name: string,
|
||||||
|
|
|
@ -28,9 +28,7 @@ export interface Manifest<HookT> {
|
||||||
*
|
*
|
||||||
* see: common/manifest.ts#SilverBulletHooks
|
* see: common/manifest.ts#SilverBulletHooks
|
||||||
*/
|
*/
|
||||||
functions: {
|
functions: Record<string, FunctionDef<HookT>>;
|
||||||
[key: string]: FunctionDef<HookT>;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Associates hooks with a function. This is the generic base structure, that identifies the function. Hooks are defined by the type parameter. */
|
/** Associates hooks with a function. This is the generic base structure, that identifies the function. Hooks are defined by the type parameter. */
|
||||||
|
|
|
@ -37,6 +37,7 @@ functions:
|
||||||
name: "Editor: Move Cursor to Position"
|
name: "Editor: Move Cursor to Position"
|
||||||
clearPageIndex:
|
clearPageIndex:
|
||||||
path: "./page.ts:clearPageIndex"
|
path: "./page.ts:clearPageIndex"
|
||||||
|
env: server
|
||||||
events:
|
events:
|
||||||
- page:saved
|
- page:saved
|
||||||
- page:deleted
|
- page:deleted
|
||||||
|
@ -46,6 +47,7 @@ functions:
|
||||||
- query:page
|
- query:page
|
||||||
parseIndexTextRepublish:
|
parseIndexTextRepublish:
|
||||||
path: "./page.ts:parseIndexTextRepublish"
|
path: "./page.ts:parseIndexTextRepublish"
|
||||||
|
env: server
|
||||||
events:
|
events:
|
||||||
- page:index_text
|
- page:index_text
|
||||||
reindexSpaceCommand:
|
reindexSpaceCommand:
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
import { events, mq } from "$sb/plugos-syscall/mod.ts";
|
import { events, mq } from "$sb/plugos-syscall/mod.ts";
|
||||||
|
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
import { invokeFunction } from "$sb/silverbullet-syscall/system.ts";
|
import { invoke } from "$sb/silverbullet-syscall/system.ts";
|
||||||
import type { Message } from "$sb/types.ts";
|
import type { Message } from "$sb/types.ts";
|
||||||
import { sleep } from "../../common/async_util.ts";
|
import { sleep } from "../../common/async_util.ts";
|
||||||
import { cacheFileListing } from "../federation/federation.ts";
|
import { cacheFileListing } from "../federation/federation.ts";
|
||||||
|
@ -135,7 +135,7 @@ export async function reindexSpace() {
|
||||||
console.log("Clearing page index...");
|
console.log("Clearing page index...");
|
||||||
await index.clearPageIndex();
|
await index.clearPageIndex();
|
||||||
// Executed this way to not have to embed the search plug code here
|
// Executed this way to not have to embed the search plug code here
|
||||||
await invokeFunction("client", "search.clearIndex");
|
await invoke("search.clearIndex");
|
||||||
const pages = await space.listPages();
|
const pages = await space.listPages();
|
||||||
|
|
||||||
// Queue all page names to be indexed
|
// Queue all page names to be indexed
|
||||||
|
@ -172,7 +172,7 @@ export async function clearPageIndex(page: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
|
||||||
// console.log("Reindexing", name);
|
console.log("Reindexing", name);
|
||||||
await events.dispatchEvent("page:index", {
|
await events.dispatchEvent("page:index", {
|
||||||
name,
|
name,
|
||||||
tree: await markdown.parseMarkdown(text),
|
tree: await markdown.parseMarkdown(text),
|
||||||
|
|
|
@ -44,7 +44,7 @@ export async function evalDirectiveRenderer(
|
||||||
const result = await (0, eval)(
|
const result = await (0, eval)(
|
||||||
`(async () => {
|
`(async () => {
|
||||||
function invokeFunction(name, ...args) {
|
function invokeFunction(name, ...args) {
|
||||||
return syscall("system.invokeFunction", "server", name, ...args);
|
return syscall("system.invoke", name, ...args);
|
||||||
}
|
}
|
||||||
return ${replaceTemplateVars(translateJs(expression), pageMeta)};
|
return ${replaceTemplateVars(translateJs(expression), pageMeta)};
|
||||||
})()`,
|
})()`,
|
||||||
|
|
|
@ -12,6 +12,7 @@ functions:
|
||||||
|
|
||||||
searchUnindex:
|
searchUnindex:
|
||||||
path: "./search.ts:pageUnindex"
|
path: "./search.ts:pageUnindex"
|
||||||
|
env: client
|
||||||
events:
|
events:
|
||||||
- page:deleted
|
- page:deleted
|
||||||
searchQueryProvider:
|
searchQueryProvider:
|
||||||
|
|
|
@ -30,10 +30,12 @@ import { shellSyscalls } from "../plugos/syscalls/shell.deno.ts";
|
||||||
import { IDBKeyRange, indexedDB } from "https://esm.sh/fake-indexeddb@4.0.2";
|
import { IDBKeyRange, indexedDB } from "https://esm.sh/fake-indexeddb@4.0.2";
|
||||||
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
||||||
|
|
||||||
|
const fileListInterval = 30 * 1000; // 30s
|
||||||
|
|
||||||
export class ServerSystem {
|
export class ServerSystem {
|
||||||
system: System<SilverBulletHooks> = new System("server");
|
system: System<SilverBulletHooks> = new System("server");
|
||||||
spacePrimitives!: SpacePrimitives;
|
spacePrimitives!: SpacePrimitives;
|
||||||
requeueInterval?: number;
|
private requeueInterval?: number;
|
||||||
kvStore?: DenoKVStore;
|
kvStore?: DenoKVStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -114,19 +116,31 @@ export class ServerSystem {
|
||||||
|
|
||||||
await this.loadPlugs();
|
await this.loadPlugs();
|
||||||
|
|
||||||
// for (let plugPath of await space.listPlugs()) {
|
|
||||||
// plugPath = path.resolve(this.spacePath, plugPath);
|
|
||||||
// await this.system.load(
|
|
||||||
// new URL(`file://${plugPath}`),
|
|
||||||
// createSandbox,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Load markdown syscalls based on all new syntax (if any)
|
// Load markdown syscalls based on all new syntax (if any)
|
||||||
this.system.registerSyscalls(
|
this.system.registerSyscalls(
|
||||||
[],
|
[],
|
||||||
markdownSyscalls(buildMarkdown(loadMarkdownExtensions(this.system))),
|
markdownSyscalls(buildMarkdown(loadMarkdownExtensions(this.system))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
space.updatePageList().catch(console.error);
|
||||||
|
}, fileListInterval);
|
||||||
|
|
||||||
|
eventHook.addLocalListener("file:changed", (path, localChange) => {
|
||||||
|
(async () => {
|
||||||
|
// console.log("!!!!! FILE CHANGED", path, localChange);
|
||||||
|
if (!localChange && path.endsWith(".md")) {
|
||||||
|
const pageName = path.slice(0, -3);
|
||||||
|
const data = await this.spacePrimitives.readFile(path);
|
||||||
|
console.log("Outside page change: reindexing", pageName);
|
||||||
|
// Change made outside of editor, trigger reindex
|
||||||
|
await eventHook.dispatchEvent("page:index_text", {
|
||||||
|
name: pageName,
|
||||||
|
text: new TextDecoder().decode(data.data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})().catch(console.error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadPlugs() {
|
async loadPlugs() {
|
||||||
|
|
|
@ -321,12 +321,6 @@ export class Client {
|
||||||
}
|
}
|
||||||
})().catch(console.error);
|
})().catch(console.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.eventHook.addLocalListener("page:deleted", (pageName) => {
|
|
||||||
// if (pageName === this.currentPage) {
|
|
||||||
// this.flashNotification("Page does exist, creating as a new page");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initSpace(): SpacePrimitives {
|
initSpace(): SpacePrimitives {
|
||||||
|
@ -375,20 +369,15 @@ export class Client {
|
||||||
localSpacePrimitives = new EventedSpacePrimitives(
|
localSpacePrimitives = new EventedSpacePrimitives(
|
||||||
this.plugSpaceRemotePrimitives,
|
this.plugSpaceRemotePrimitives,
|
||||||
this.eventHook,
|
this.eventHook,
|
||||||
[
|
|
||||||
"file:changed",
|
|
||||||
"file:listed",
|
|
||||||
"page:deleted",
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.space = new Space(localSpacePrimitives, this.kvStore, this.eventHook);
|
this.space = new Space(localSpacePrimitives, this.kvStore, this.eventHook);
|
||||||
|
|
||||||
this.eventHook.addLocalListener("file:changed", (fileMeta: FileMeta) => {
|
this.eventHook.addLocalListener("file:changed", (path: string) => {
|
||||||
// Only reload when watching the current page (to avoid reloading when switching pages)
|
// Only reload when watching the current page (to avoid reloading when switching pages)
|
||||||
if (
|
if (
|
||||||
this.space.watchInterval && `${this.currentPage}.md` === fileMeta.name
|
this.space.watchInterval && `${this.currentPage}.md` === path
|
||||||
) {
|
) {
|
||||||
console.log("Page changed elsewhere, reloading");
|
console.log("Page changed elsewhere, reloading");
|
||||||
this.flashNotification("Page changed elsewhere, reloading");
|
this.flashNotification("Page changed elsewhere, reloading");
|
||||||
|
|
|
@ -37,7 +37,6 @@ import { indexProxySyscalls } from "./syscalls/index.proxy.ts";
|
||||||
import { storeProxySyscalls } from "./syscalls/store.proxy.ts";
|
import { storeProxySyscalls } from "./syscalls/store.proxy.ts";
|
||||||
|
|
||||||
export class ClientSystem {
|
export class ClientSystem {
|
||||||
system: System<SilverBulletHooks> = new System("client");
|
|
||||||
commandHook: CommandHook;
|
commandHook: CommandHook;
|
||||||
slashCommandHook: SlashCommandHook;
|
slashCommandHook: SlashCommandHook;
|
||||||
namespaceHook: PlugNamespaceHook;
|
namespaceHook: PlugNamespaceHook;
|
||||||
|
@ -45,15 +44,19 @@ export class ClientSystem {
|
||||||
codeWidgetHook: CodeWidgetHook;
|
codeWidgetHook: CodeWidgetHook;
|
||||||
plugsUpdated = false;
|
plugsUpdated = false;
|
||||||
mdExtensions: MDExt[] = [];
|
mdExtensions: MDExt[] = [];
|
||||||
|
system: System<SilverBulletHooks>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private client: Client,
|
private client: Client,
|
||||||
private kvStore: DexieKVStore,
|
private kvStore: DexieKVStore,
|
||||||
private mq: DexieMQ,
|
private mq: DexieMQ,
|
||||||
private dbPrefix: string,
|
dbPrefix: string,
|
||||||
private eventHook: EventHook,
|
private eventHook: EventHook,
|
||||||
private thinClientMode: boolean,
|
private thinClientMode: boolean,
|
||||||
) {
|
) {
|
||||||
|
// Only set environment to "client" when running in thin client mode, otherwise we run everything locally (hybrid)
|
||||||
|
this.system = new System(thinClientMode ? "client" : undefined);
|
||||||
|
|
||||||
this.system.addHook(this.eventHook);
|
this.system.addHook(this.eventHook);
|
||||||
|
|
||||||
// Plug page namespace hook
|
// Plug page namespace hook
|
||||||
|
|
30
web/space.ts
30
web/space.ts
|
@ -65,36 +65,6 @@ export class Space {
|
||||||
public async updatePageList() {
|
public async updatePageList() {
|
||||||
// This will trigger appropriate events automatically
|
// This will trigger appropriate events automatically
|
||||||
await this.fetchPageList();
|
await this.fetchPageList();
|
||||||
// const deletedPages = new Set<string>(this.pageMetaCache.keys());
|
|
||||||
// newPageList.forEach((meta) => {
|
|
||||||
// const pageName = meta.name;
|
|
||||||
// const oldPageMeta = this.pageMetaCache.get(pageName);
|
|
||||||
// const newPageMeta: PageMeta = { ...meta };
|
|
||||||
// if (
|
|
||||||
// !oldPageMeta &&
|
|
||||||
// (pageName.startsWith(plugPrefix) || !this.initialPageListLoad)
|
|
||||||
// ) {
|
|
||||||
// this.emit("pageCreated", newPageMeta);
|
|
||||||
// } else if (
|
|
||||||
// oldPageMeta &&
|
|
||||||
// oldPageMeta.lastModified !== newPageMeta.lastModified
|
|
||||||
// ) {
|
|
||||||
// this.emit("pageChanged", newPageMeta);
|
|
||||||
// }
|
|
||||||
// // Page found, not deleted
|
|
||||||
// deletedPages.delete(pageName);
|
|
||||||
|
|
||||||
// // Update in cache
|
|
||||||
// this.pageMetaCache.set(pageName, newPageMeta);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// for (const deletedPage of deletedPages) {
|
|
||||||
// this.pageMetaCache.delete(deletedPage);
|
|
||||||
// this.emit("pageDeleted", deletedPage);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.emit("pageListUpdated", this.listPages());
|
|
||||||
// this.initialPageListLoad = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deletePage(name: string): Promise<void> {
|
async deletePage(name: string): Promise<void> {
|
||||||
|
|
|
@ -2,17 +2,27 @@ import type { Plug } from "../../plugos/plug.ts";
|
||||||
import { SysCallMapping, System } from "../../plugos/system.ts";
|
import { SysCallMapping, System } from "../../plugos/system.ts";
|
||||||
import type { Client } from "../client.ts";
|
import type { Client } from "../client.ts";
|
||||||
import { CommandDef } from "../hooks/command.ts";
|
import { CommandDef } from "../hooks/command.ts";
|
||||||
|
import { proxySyscall } from "./util.ts";
|
||||||
|
|
||||||
export function systemSyscalls(
|
export function systemSyscalls(
|
||||||
editor: Client,
|
editor: Client,
|
||||||
system: System<any>,
|
system: System<any>,
|
||||||
): SysCallMapping {
|
): SysCallMapping {
|
||||||
return {
|
const api: SysCallMapping = {
|
||||||
"system.invokeFunction": (
|
"system.invokeFunction": (
|
||||||
ctx,
|
ctx,
|
||||||
_env: string,
|
_env: string,
|
||||||
name: string,
|
name: string,
|
||||||
...args: any[]
|
...args: any[]
|
||||||
|
) => {
|
||||||
|
// For backwards compatibility
|
||||||
|
// TODO: Remove at some point
|
||||||
|
return api["system.invoke"](ctx, name, ...args);
|
||||||
|
},
|
||||||
|
"system.invoke": (
|
||||||
|
ctx,
|
||||||
|
name: string,
|
||||||
|
...args: any[]
|
||||||
) => {
|
) => {
|
||||||
if (!ctx.plug) {
|
if (!ctx.plug) {
|
||||||
throw Error("No plug associated with context");
|
throw Error("No plug associated with context");
|
||||||
|
@ -28,6 +38,14 @@ export function systemSyscalls(
|
||||||
}
|
}
|
||||||
name = functionName;
|
name = functionName;
|
||||||
}
|
}
|
||||||
|
const functionDef = plug.manifest!.functions[name];
|
||||||
|
if (!functionDef) {
|
||||||
|
throw Error(`Function ${name} not found`);
|
||||||
|
}
|
||||||
|
if (functionDef.env && system.env && functionDef.env !== system.env) {
|
||||||
|
// Proxy to another environment
|
||||||
|
return proxySyscall(editor.remoteSpacePrimitives, name, args);
|
||||||
|
}
|
||||||
return plug.invoke(name, args);
|
return plug.invoke(name, args);
|
||||||
},
|
},
|
||||||
"system.invokeCommand": (_ctx, name: string) => {
|
"system.invokeCommand": (_ctx, name: string) => {
|
||||||
|
@ -47,4 +65,5 @@ export function systemSyscalls(
|
||||||
return system.env;
|
return system.env;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
return api;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { HttpSpacePrimitives } from "../../common/spaces/http_space_primitives.ts";
|
||||||
import { SysCallMapping } from "../../plugos/system.ts";
|
import { SysCallMapping } from "../../plugos/system.ts";
|
||||||
import { SyscallResponse } from "../../server/rpc.ts";
|
import { SyscallResponse } from "../../server/rpc.ts";
|
||||||
import { Client } from "../client.ts";
|
import { Client } from "../client.ts";
|
||||||
|
@ -5,12 +6,20 @@ import { Client } from "../client.ts";
|
||||||
export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
|
export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
|
||||||
const syscalls: SysCallMapping = {};
|
const syscalls: SysCallMapping = {};
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
syscalls[name] = async (_ctx, ...args: any[]) => {
|
syscalls[name] = (_ctx, ...args: any[]) => {
|
||||||
if (!client.remoteSpacePrimitives) {
|
return proxySyscall(client.remoteSpacePrimitives, name, args);
|
||||||
throw new Error("Not supported");
|
};
|
||||||
}
|
}
|
||||||
const resp = await client.remoteSpacePrimitives.authenticatedFetch(
|
return syscalls;
|
||||||
`${client.remoteSpacePrimitives.url}/.rpc`,
|
}
|
||||||
|
|
||||||
|
export async function proxySyscall(
|
||||||
|
httpSpacePrimitives: HttpSpacePrimitives,
|
||||||
|
name: string,
|
||||||
|
args: any[],
|
||||||
|
): Promise<any> {
|
||||||
|
const resp = await httpSpacePrimitives.authenticatedFetch(
|
||||||
|
`${httpSpacePrimitives.url}/.rpc`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
@ -27,7 +36,4 @@ export function proxySyscalls(client: Client, names: string[]): SysCallMapping {
|
||||||
} else {
|
} else {
|
||||||
return result.result;
|
return result.result;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
return syscalls;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue