WIP: CLI running of plugs
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { assertEquals } from "../../test_deps.ts";
|
||||
import { pageIndexSyscalls } from "./index.ts";
|
||||
|
||||
Deno.test("Test KV index", async () => {
|
||||
const ctx: any = {};
|
||||
const calls = pageIndexSyscalls();
|
||||
await calls["index.set"](ctx, "page", "test", "value");
|
||||
assertEquals(await calls["index.get"](ctx, "page", "test"), "value");
|
||||
await calls["index.delete"](ctx, "page", "test");
|
||||
assertEquals(await calls["index.get"](ctx, "page", "test"), null);
|
||||
await calls["index.batchSet"](ctx, "page", [{
|
||||
key: "attr:test",
|
||||
value: "value",
|
||||
}, {
|
||||
key: "attr:test2",
|
||||
value: "value2",
|
||||
}, { key: "random", value: "value3" }]);
|
||||
await calls["index.batchSet"](ctx, "page2", [{
|
||||
key: "attr:test",
|
||||
value: "value",
|
||||
}, {
|
||||
key: "attr:test2",
|
||||
value: "value2",
|
||||
}, { key: "random", value: "value3" }]);
|
||||
let results = await calls["index.queryPrefix"](ctx, "attr:");
|
||||
assertEquals(results.length, 4);
|
||||
await calls["index.clearPageIndexForPage"](ctx, "page");
|
||||
results = await calls["index.queryPrefix"](ctx, "attr:");
|
||||
assertEquals(results.length, 2);
|
||||
await calls["index.clearPageIndex"](ctx);
|
||||
results = await calls["index.queryPrefix"](ctx, "");
|
||||
assertEquals(results.length, 0);
|
||||
await calls["index.close"](ctx);
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
/// <reference lib="deno.unstable" />
|
||||
|
||||
import type { SysCallMapping } from "../../plugos/system.ts";
|
||||
|
||||
type Item = {
|
||||
page: string;
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
export type KV = {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
// Keyspace:
|
||||
// ["index", page, key] -> value
|
||||
// ["indexByKey", key, page] -> value
|
||||
|
||||
/**
|
||||
* Implements the index syscalls using Deno's KV store.
|
||||
* @param dbFile
|
||||
* @returns
|
||||
*/
|
||||
export function pageIndexSyscalls(dbFile?: string): SysCallMapping {
|
||||
const kv = Deno.openKv(dbFile);
|
||||
const apiObj: SysCallMapping = {
|
||||
"index.set": async (_ctx, page: string, key: string, value: any) => {
|
||||
const res = await (await kv).atomic()
|
||||
.set(["index", page, key], value)
|
||||
.set(["indexByKey", key, page], value)
|
||||
.commit();
|
||||
if (!res.ok) {
|
||||
throw res;
|
||||
}
|
||||
},
|
||||
"index.batchSet": async (_ctx, page: string, kvs: KV[]) => {
|
||||
// await items.bulkPut(kvs);
|
||||
for (const { key, value } of kvs) {
|
||||
await apiObj["index.set"](_ctx, page, key, value);
|
||||
}
|
||||
},
|
||||
"index.delete": async (_ctx, page: string, key: string) => {
|
||||
const res = await (await kv).atomic()
|
||||
.delete(["index", page, key])
|
||||
.delete(["indexByKey", key, page])
|
||||
.commit();
|
||||
if (!res.ok) {
|
||||
throw res;
|
||||
}
|
||||
},
|
||||
"index.get": async (_ctx, page: string, key: string) => {
|
||||
return (await (await kv).get(["index", page, key])).value;
|
||||
},
|
||||
"index.queryPrefix": async (_ctx, prefix: string) => {
|
||||
const results: { key: string; page: string; value: any }[] = [];
|
||||
for await (
|
||||
const result of (await kv).list({
|
||||
start: ["indexByKey", prefix],
|
||||
end: [
|
||||
"indexByKey",
|
||||
prefix.slice(0, -1) +
|
||||
// This is a hack to get the next character in the ASCII table (e.g. "a" -> "b")
|
||||
String.fromCharCode(prefix.charCodeAt(prefix.length - 1) + 1),
|
||||
],
|
||||
})
|
||||
) {
|
||||
results.push({
|
||||
key: result.key[1] as string,
|
||||
page: result.key[2] as string,
|
||||
value: result.value,
|
||||
});
|
||||
}
|
||||
return results;
|
||||
},
|
||||
"index.clearPageIndexForPage": async (ctx, page: string) => {
|
||||
await apiObj["index.deletePrefixForPage"](ctx, page, "");
|
||||
},
|
||||
"index.deletePrefixForPage": async (_ctx, page: string, prefix: string) => {
|
||||
for await (
|
||||
const result of (await kv).list({
|
||||
start: ["index", page, prefix],
|
||||
end: ["index", page, prefix + "~"],
|
||||
})
|
||||
) {
|
||||
await apiObj["index.delete"](_ctx, page, result.key[2]);
|
||||
}
|
||||
},
|
||||
"index.clearPageIndex": async (ctx) => {
|
||||
for await (
|
||||
const result of (await kv).list({
|
||||
prefix: ["index"],
|
||||
})
|
||||
) {
|
||||
await apiObj["index.delete"](ctx, result.key[1], result.key[2]);
|
||||
}
|
||||
},
|
||||
"index.close": async () => {
|
||||
(await kv).close();
|
||||
},
|
||||
};
|
||||
return apiObj;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { SysCallMapping } from "../../plugos/system.ts";
|
||||
import type { Space } from "../../web/space.ts";
|
||||
import { AttachmentMeta, PageMeta } from "../../web/types.ts";
|
||||
|
||||
/**
|
||||
* Almost the same as web/syscalls/space.ts except leaving out client-specific stuff
|
||||
*/
|
||||
export function spaceSyscalls(space: Space): SysCallMapping {
|
||||
return {
|
||||
"space.listPages": (): Promise<PageMeta[]> => {
|
||||
return space.fetchPageList();
|
||||
},
|
||||
"space.readPage": async (
|
||||
_ctx,
|
||||
name: string,
|
||||
): Promise<string> => {
|
||||
return (await space.readPage(name)).text;
|
||||
},
|
||||
"space.getPageMeta": (_ctx, name: string): Promise<PageMeta> => {
|
||||
return space.getPageMeta(name);
|
||||
},
|
||||
"space.writePage": (
|
||||
_ctx,
|
||||
name: string,
|
||||
text: string,
|
||||
): Promise<PageMeta> => {
|
||||
return space.writePage(name, text);
|
||||
},
|
||||
"space.deletePage": async (_ctx, name: string) => {
|
||||
await space.deletePage(name);
|
||||
},
|
||||
"space.listPlugs": (): Promise<string[]> => {
|
||||
return space.listPlugs();
|
||||
},
|
||||
"space.listAttachments": async (): Promise<AttachmentMeta[]> => {
|
||||
return await space.fetchAttachmentList();
|
||||
},
|
||||
"space.readAttachment": async (
|
||||
_ctx,
|
||||
name: string,
|
||||
): Promise<Uint8Array> => {
|
||||
return (await space.readAttachment(name)).data;
|
||||
},
|
||||
"space.getAttachmentMeta": async (
|
||||
_ctx,
|
||||
name: string,
|
||||
): Promise<AttachmentMeta> => {
|
||||
return await space.getAttachmentMeta(name);
|
||||
},
|
||||
"space.writeAttachment": (
|
||||
_ctx,
|
||||
name: string,
|
||||
data: Uint8Array,
|
||||
): Promise<AttachmentMeta> => {
|
||||
return space.writeAttachment(name, data);
|
||||
},
|
||||
"space.deleteAttachment": async (_ctx, name: string) => {
|
||||
await space.deleteAttachment(name);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user