Rewrote some navigation stuff based on new parser
This commit is contained in:
+10
-19
@@ -10,21 +10,17 @@ import {System} from "../system";
|
||||
import {EndpointHook, EndpointHookT} from "../hooks/endpoint";
|
||||
import {safeRun} from "../util";
|
||||
import knex from "knex";
|
||||
import {
|
||||
ensureTable,
|
||||
storeReadSyscalls,
|
||||
storeWriteSyscalls,
|
||||
} from "../syscalls/store.knex_node";
|
||||
import {ensureTable, storeSyscalls} from "../syscalls/store.knex_node";
|
||||
import {fetchSyscalls} from "../syscalls/fetch.node";
|
||||
import {EventHook, EventHookT} from "../hooks/event";
|
||||
import {eventSyscalls} from "../syscalls/event";
|
||||
|
||||
let args = yargs(hideBin(process.argv))
|
||||
.option("port", {
|
||||
type: "number",
|
||||
default: 1337,
|
||||
})
|
||||
.parse();
|
||||
.option("port", {
|
||||
type: "number",
|
||||
default: 1337,
|
||||
})
|
||||
.parse();
|
||||
|
||||
if (!args._.length) {
|
||||
console.error("Usage: plugos-server <path-to-plugs>");
|
||||
@@ -55,16 +51,11 @@ safeRun(async () => {
|
||||
system.addHook(new NodeCronHook());
|
||||
let eventHook = new EventHook();
|
||||
system.addHook(eventHook);
|
||||
system.registerSyscalls("event", [], eventSyscalls(eventHook));
|
||||
system.registerSyscalls([], eventSyscalls(eventHook));
|
||||
system.addHook(new EndpointHook(app, ""));
|
||||
system.registerSyscalls("shell", [], shellSyscalls("."));
|
||||
system.registerSyscalls("fetch", [], fetchSyscalls());
|
||||
system.registerSyscalls(
|
||||
"store",
|
||||
[],
|
||||
storeWriteSyscalls(db, "item"),
|
||||
storeReadSyscalls(db, "item")
|
||||
);
|
||||
system.registerSyscalls([], shellSyscalls("."));
|
||||
system.registerSyscalls([], fetchSyscalls());
|
||||
system.registerSyscalls([], storeSyscalls(db, "item"));
|
||||
app.listen(args.port, () => {
|
||||
console.log(`Plugbox server listening on port ${args.port}`);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { createSandbox } from "./environments/node_sandbox";
|
||||
import { expect, test } from "@jest/globals";
|
||||
import { System } from "./system";
|
||||
import {createSandbox} from "./environments/node_sandbox";
|
||||
import {expect, test} from "@jest/globals";
|
||||
import {System} from "./system";
|
||||
|
||||
test("Run a Node sandbox", async () => {
|
||||
let system = new System("server");
|
||||
system.registerSyscalls("", [], {
|
||||
system.registerSyscalls([], {
|
||||
addNumbers: (ctx, a, b) => {
|
||||
return a + b;
|
||||
},
|
||||
@@ -12,12 +12,12 @@ test("Run a Node sandbox", async () => {
|
||||
throw new Error("#fail");
|
||||
},
|
||||
});
|
||||
system.registerSyscalls("", ["restricted"], {
|
||||
system.registerSyscalls(["restricted"], {
|
||||
restrictedSyscall: () => {
|
||||
return "restricted";
|
||||
},
|
||||
});
|
||||
system.registerSyscalls("", ["dangerous"], {
|
||||
system.registerSyscalls(["dangerous"], {
|
||||
dangerousSyscall: () => {
|
||||
return "yay";
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { SysCallMapping } from "../system";
|
||||
import { EventHook } from "../hooks/event";
|
||||
import {SysCallMapping} from "../system";
|
||||
import {EventHook} from "../hooks/event";
|
||||
|
||||
export function eventSyscalls(eventHook: EventHook): SysCallMapping {
|
||||
return {
|
||||
async dispatch(ctx, eventName: string, data: any) {
|
||||
"event.dispatch": async(ctx, eventName: string, data: any) => {
|
||||
return eventHook.dispatchEvent(eventName, data);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import fetch, { RequestInfo, RequestInit } from "node-fetch";
|
||||
import { SysCallMapping } from "../system";
|
||||
import fetch, {RequestInfo, RequestInit} from "node-fetch";
|
||||
import {SysCallMapping} from "../system";
|
||||
|
||||
export function fetchSyscalls(): SysCallMapping {
|
||||
return {
|
||||
async json(ctx, url: RequestInfo, init: RequestInit) {
|
||||
"fetch.json": async (ctx, url: RequestInfo, init: RequestInit) => {
|
||||
let resp = await fetch(url, init);
|
||||
return resp.json();
|
||||
},
|
||||
async text(ctx, url: RequestInfo, init: RequestInit) {
|
||||
"fetch.text": async(ctx, url: RequestInfo, init: RequestInit) => {
|
||||
let resp = await fetch(url, init);
|
||||
return resp.text();
|
||||
},
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { promisify } from "util";
|
||||
import { execFile } from "child_process";
|
||||
import type { SysCallMapping } from "../system";
|
||||
import {promisify} from "util";
|
||||
import {execFile} from "child_process";
|
||||
import type {SysCallMapping} from "../system";
|
||||
|
||||
const execFilePromise = promisify(execFile);
|
||||
|
||||
export default function (cwd: string): SysCallMapping {
|
||||
return {
|
||||
run: async (
|
||||
"shell.run": async (
|
||||
ctx,
|
||||
cmd: string,
|
||||
args: string[]
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { createSandbox } from "../environments/node_sandbox";
|
||||
import { expect, test } from "@jest/globals";
|
||||
import { System } from "../system";
|
||||
import { storeSyscalls } from "./store.dexie_browser";
|
||||
import {createSandbox} from "../environments/node_sandbox";
|
||||
import {expect, test} from "@jest/globals";
|
||||
import {System} from "../system";
|
||||
import {storeSyscalls} from "./store.dexie_browser";
|
||||
|
||||
// For testing in node.js
|
||||
require("fake-indexeddb/auto");
|
||||
|
||||
test("Test store", async () => {
|
||||
let system = new System("server");
|
||||
system.registerSyscalls("store", [], storeSyscalls("test", "test"));
|
||||
system.registerSyscalls([], storeSyscalls("test", "test"));
|
||||
let plug = await system.load(
|
||||
"test",
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Dexie from "dexie";
|
||||
import { SysCallMapping } from "../system";
|
||||
import {SysCallMapping} from "../system";
|
||||
|
||||
export type KV = {
|
||||
key: string;
|
||||
@@ -17,26 +17,26 @@ export function storeSyscalls(
|
||||
const items = db.table(tableName);
|
||||
|
||||
return {
|
||||
async delete(ctx, key: string) {
|
||||
"store.delete": async (ctx, key: string) => {
|
||||
await items.delete(key);
|
||||
},
|
||||
|
||||
async deletePrefix(ctx, prefix: string) {
|
||||
"store.deletePrefix": async (ctx, prefix: string) => {
|
||||
await items.where("key").startsWith(prefix).delete();
|
||||
},
|
||||
|
||||
async deleteAll() {
|
||||
"store.deleteAll": async () => {
|
||||
await items.clear();
|
||||
},
|
||||
|
||||
async set(ctx, key: string, value: any) {
|
||||
"store.set": async (ctx, key: string, value: any) => {
|
||||
await items.put({
|
||||
key,
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
||||
async batchSet(ctx, kvs: KV[]) {
|
||||
"store.batchSet": async (ctx, kvs: KV[]) => {
|
||||
await items.bulkPut(
|
||||
kvs.map(({ key, value }) => ({
|
||||
key,
|
||||
@@ -45,17 +45,17 @@ export function storeSyscalls(
|
||||
);
|
||||
},
|
||||
|
||||
async get(ctx, key: string): Promise<any | null> {
|
||||
"store.get": async (ctx, key: string): Promise<any | null> => {
|
||||
let result = await items.get({
|
||||
key,
|
||||
});
|
||||
return result ? result.value : null;
|
||||
},
|
||||
|
||||
async queryPrefix(
|
||||
"store.queryPrefix": async (
|
||||
ctx,
|
||||
keyPrefix: string
|
||||
): Promise<{ key: string; value: any }[]> {
|
||||
): Promise<{ key: string; value: any }[]> => {
|
||||
let results = await items.where("key").startsWith(keyPrefix).toArray();
|
||||
return results.map((result) => ({
|
||||
key: result.key,
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { createSandbox } from "../environments/node_sandbox";
|
||||
import { expect, test } from "@jest/globals";
|
||||
import { System } from "../system";
|
||||
import {
|
||||
ensureTable,
|
||||
storeReadSyscalls,
|
||||
storeWriteSyscalls,
|
||||
} from "./store.knex_node";
|
||||
import {createSandbox} from "../environments/node_sandbox";
|
||||
import {expect, test} from "@jest/globals";
|
||||
import {System} from "../system";
|
||||
import {ensureTable, storeSyscalls} from "./store.knex_node";
|
||||
import knex from "knex";
|
||||
import fs from "fs/promises";
|
||||
|
||||
@@ -19,12 +15,7 @@ test("Test store", async () => {
|
||||
});
|
||||
await ensureTable(db, "test_table");
|
||||
let system = new System("server");
|
||||
system.registerSyscalls(
|
||||
"store",
|
||||
[],
|
||||
storeWriteSyscalls(db, "test_table"),
|
||||
storeReadSyscalls(db, "test_table")
|
||||
);
|
||||
system.registerSyscalls([], storeSyscalls(db, "test_table"));
|
||||
let plug = await system.load(
|
||||
"test",
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Knex } from "knex";
|
||||
import { SysCallMapping } from "../system";
|
||||
import {Knex} from "knex";
|
||||
import {SysCallMapping} from "../system";
|
||||
|
||||
type Item = {
|
||||
page: string;
|
||||
@@ -23,21 +23,21 @@ export async function ensureTable(db: Knex<any, unknown>, tableName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function storeWriteSyscalls(
|
||||
export function storeSyscalls(
|
||||
db: Knex<any, unknown>,
|
||||
tableName: string
|
||||
): SysCallMapping {
|
||||
const apiObj: SysCallMapping = {
|
||||
delete: async (ctx, key: string) => {
|
||||
"store.delete": async (ctx, key: string) => {
|
||||
await db<Item>(tableName).where({ key }).del();
|
||||
},
|
||||
deletePrefix: async (ctx, prefix: string) => {
|
||||
"store.deletePrefix": async (ctx, prefix: string) => {
|
||||
return db<Item>(tableName).andWhereLike("key", `${prefix}%`).del();
|
||||
},
|
||||
deleteAll: async (ctx) => {
|
||||
"store.deleteAll": async (ctx) => {
|
||||
await db<Item>(tableName).del();
|
||||
},
|
||||
set: async (ctx, key: string, value: any) => {
|
||||
"store.set": async (ctx, key: string, value: any) => {
|
||||
let changed = await db<Item>(tableName)
|
||||
.where({ key })
|
||||
.update("value", JSON.stringify(value));
|
||||
@@ -49,26 +49,17 @@ export function storeWriteSyscalls(
|
||||
}
|
||||
},
|
||||
// TODO: Optimize
|
||||
batchSet: async (ctx, kvs: KV[]) => {
|
||||
"store.batchSet": async (ctx, kvs: KV[]) => {
|
||||
for (let { key, value } of kvs) {
|
||||
await apiObj.set(ctx, key, value);
|
||||
await apiObj["store.set"](ctx, key, value);
|
||||
}
|
||||
},
|
||||
batchDelete: async (ctx, keys: string[]) => {
|
||||
"store.batchDelete": async (ctx, keys: string[]) => {
|
||||
for (let key of keys) {
|
||||
await apiObj.delete(ctx, key);
|
||||
await apiObj["store.delete"](ctx, key);
|
||||
}
|
||||
},
|
||||
};
|
||||
return apiObj;
|
||||
}
|
||||
|
||||
export function storeReadSyscalls(
|
||||
db: Knex<any, unknown>,
|
||||
tableName: string
|
||||
): SysCallMapping {
|
||||
return {
|
||||
get: async (ctx, key: string): Promise<any | null> => {
|
||||
"store.get": async (ctx, key: string): Promise<any | null> => {
|
||||
let result = await db<Item>(tableName).where({ key }).select("value");
|
||||
if (result.length) {
|
||||
return JSON.parse(result[0].value);
|
||||
@@ -76,7 +67,7 @@ export function storeReadSyscalls(
|
||||
return null;
|
||||
}
|
||||
},
|
||||
queryPrefix: async (ctx, prefix: string) => {
|
||||
"store.queryPrefix": async (ctx, prefix: string) => {
|
||||
return (
|
||||
await db<Item>(tableName)
|
||||
.andWhereLike("key", `${prefix}%`)
|
||||
@@ -87,4 +78,5 @@ export function storeReadSyscalls(
|
||||
}));
|
||||
},
|
||||
};
|
||||
return apiObj;
|
||||
}
|
||||
|
||||
+10
-13
@@ -1,7 +1,7 @@
|
||||
import { Hook, Manifest, RuntimeEnvironment } from "./types";
|
||||
import { EventEmitter } from "../common/event";
|
||||
import { SandboxFactory } from "./sandbox";
|
||||
import { Plug } from "./plug";
|
||||
import {Hook, Manifest, RuntimeEnvironment} from "./types";
|
||||
import {EventEmitter} from "../common/event";
|
||||
import {SandboxFactory} from "./sandbox";
|
||||
import {Plug} from "./plug";
|
||||
|
||||
export interface SysCallMapping {
|
||||
[key: string]: (ctx: SyscallContext, ...args: any) => Promise<any> | any;
|
||||
@@ -29,31 +29,32 @@ type Syscall = {
|
||||
};
|
||||
|
||||
export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
|
||||
readonly runtimeEnv: RuntimeEnvironment;
|
||||
protected plugs = new Map<string, Plug<HookT>>();
|
||||
protected registeredSyscalls = new Map<string, Syscall>();
|
||||
protected enabledHooks = new Set<Hook<HookT>>();
|
||||
|
||||
readonly runtimeEnv: RuntimeEnvironment;
|
||||
|
||||
constructor(env: RuntimeEnvironment) {
|
||||
super();
|
||||
this.runtimeEnv = env;
|
||||
}
|
||||
|
||||
get loadedPlugs(): Map<string, Plug<HookT>> {
|
||||
return this.plugs;
|
||||
}
|
||||
|
||||
addHook(feature: Hook<HookT>) {
|
||||
this.enabledHooks.add(feature);
|
||||
feature.apply(this);
|
||||
}
|
||||
|
||||
registerSyscalls(
|
||||
namespace: string,
|
||||
requiredCapabilities: string[],
|
||||
...registrationObjects: SysCallMapping[]
|
||||
) {
|
||||
for (const registrationObject of registrationObjects) {
|
||||
for (let [name, callback] of Object.entries(registrationObject)) {
|
||||
const callName = namespace ? `${namespace}.${name}` : name;
|
||||
this.registeredSyscalls.set(callName, {
|
||||
this.registeredSyscalls.set(name, {
|
||||
requiredPermissions: requiredCapabilities,
|
||||
callback,
|
||||
});
|
||||
@@ -116,10 +117,6 @@ export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
|
||||
this.plugs.delete(name);
|
||||
}
|
||||
|
||||
get loadedPlugs(): Map<string, Plug<HookT>> {
|
||||
return this.plugs;
|
||||
}
|
||||
|
||||
toJSON(): SystemJSON<HookT> {
|
||||
let plugJSON: { [key: string]: Manifest<HookT> } = {};
|
||||
for (let [name, plug] of this.plugs) {
|
||||
|
||||
Reference in New Issue
Block a user