Tons of refactoring, moving commands and slash commands into hooks

This commit is contained in:
Zef Hemel
2022-03-29 11:21:32 +02:00
parent bf32d6d0bd
commit b89aee97d7
42 changed files with 330 additions and 224 deletions
+22 -22
View File
@@ -2,29 +2,29 @@
import express from "express";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { DiskPlugLoader } from "../plug_loader";
import { CronHook, NodeCronFeature } from "../feature/node_cron";
import shellSyscalls from "../syscall/shell.node";
import { System } from "../system";
import { EndpointFeature, EndpointHook } from "../feature/endpoint";
import { safeRun } from "../util";
import {hideBin} from "yargs/helpers";
import {DiskPlugLoader} from "../plug_loader";
import {CronHookT, NodeCronHook} from "../hooks/node_cron";
import shellSyscalls from "../syscalls/shell.node";
import {System} from "../system";
import {EndpointHook, EndpointHookT} from "../hooks/endpoint";
import {safeRun} from "../util";
import knex from "knex";
import {
ensureTable,
storeReadSyscalls,
storeWriteSyscalls,
} from "../syscall/store.knex_node";
import { fetchSyscalls } from "../syscall/fetch.node";
import { EventFeature, EventHook } from "../feature/event";
import { eventSyscalls } from "../syscall/event";
} 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>");
@@ -35,7 +35,7 @@ const plugPath = args._[0] as string;
const app = express();
type ServerHook = EndpointHook & CronHook & EventHook;
type ServerHook = EndpointHookT & CronHookT & EventHookT;
const system = new System<ServerHook>("server");
safeRun(async () => {
@@ -52,11 +52,11 @@ safeRun(async () => {
let plugLoader = new DiskPlugLoader(system, plugPath);
await plugLoader.loadPlugs();
plugLoader.watcher();
system.addFeature(new NodeCronFeature());
let eventFeature = new EventFeature();
system.addFeature(eventFeature);
system.registerSyscalls("event", [], eventSyscalls(eventFeature));
system.addFeature(new EndpointFeature(app, ""));
system.addHook(new NodeCronHook());
let eventHook = new EventHook();
system.addHook(eventHook);
system.registerSyscalls("event", [], eventSyscalls(eventHook));
system.addHook(new EndpointHook(app, ""));
system.registerSyscalls("shell", [], shellSyscalls("."));
system.registerSyscalls("fetch", [], fetchSyscalls());
system.registerSyscalls(
@@ -50,7 +50,6 @@ parentPort.on("message", (data: any) => {
safeRun(async () => {
switch (data.type) {
case "load":
console.log("Booting", data.name);
loadedFunctions.set(data.name, new VMScript(wrapScript(data.code)));
parentPort.postMessage({
type: "inited",
@@ -48,7 +48,6 @@ self.addEventListener("message", (event: { data: WorkerMessage }) => {
let data = messageEvent.data;
switch (data.type) {
case "load":
console.log("Booting", data.name);
loadedFunctions.set(data.name!, new Function(wrapScript(data.code!)));
postMessage(
{
@@ -1,13 +1,13 @@
import { createSandbox } from "../environment/node_sandbox";
import { createSandbox } from "../environments/node_sandbox";
import { expect, test } from "@jest/globals";
import { Manifest } from "../types";
import express from "express";
import request from "supertest";
import { EndpointFeature, EndpointHook } from "./endpoint";
import { EndpointHook, EndpointHookT } from "./endpoint";
import { System } from "../system";
test("Run a plugos endpoint server", async () => {
let system = new System<EndpointHook>("server");
let system = new System<EndpointHookT>("server");
let plug = await system.load(
"test",
{
@@ -26,14 +26,14 @@ test("Run a plugos endpoint server", async () => {
})()`,
},
},
} as Manifest<EndpointHook>,
} as Manifest<EndpointHookT>,
createSandbox
);
const app = express();
const port = 3123;
system.addFeature(new EndpointFeature(app, "/_"));
system.addHook(new EndpointHook(app, "/_"));
let server = app.listen(port, () => {
console.log(`Listening on port ${port}`);
@@ -1,4 +1,4 @@
import { Feature, Manifest } from "../types";
import { Hook, Manifest } from "../types";
import { Express, NextFunction, Request, Response } from "express";
import { System } from "../system";
@@ -16,7 +16,7 @@ export type EndpointResponse = {
body: any;
};
export type EndpointHook = {
export type EndpointHookT = {
http?: EndPointDef | EndPointDef[];
};
@@ -25,7 +25,7 @@ export type EndPointDef = {
path: string;
};
export class EndpointFeature implements Feature<EndpointHook> {
export class EndpointHook implements Hook<EndpointHookT> {
private app: Express;
private prefix: string;
@@ -34,7 +34,7 @@ export class EndpointFeature implements Feature<EndpointHook> {
this.prefix = prefix;
}
apply(system: System<EndpointHook>): void {
apply(system: System<EndpointHookT>): void {
this.app.use((req: Request, res: Response, next: NextFunction) => {
if (!req.path.startsWith(this.prefix)) {
return next();
@@ -106,7 +106,7 @@ export class EndpointFeature implements Feature<EndpointHook> {
});
}
validateManifest(manifest: Manifest<EndpointHook>): string[] {
validateManifest(manifest: Manifest<EndpointHookT>): string[] {
let errors = [];
for (const [name, functionDef] of Object.entries(manifest.functions)) {
if (!functionDef.http) {
@@ -1,19 +1,19 @@
import { Feature, Manifest } from "../types";
import { Hook, Manifest } from "../types";
import { System } from "../system";
// System events:
// - plug:load (plugName: string)
export type EventHook = {
export type EventHookT = {
events?: string[];
};
export class EventFeature implements Feature<EventHook> {
private system?: System<EventHook>;
export class EventHook implements Hook<EventHookT> {
private system?: System<EventHookT>;
async dispatchEvent(eventName: string, data?: any): Promise<any[]> {
if (!this.system) {
throw new Error("EventFeature is not initialized");
throw new Error("Event hook is not initialized");
}
let promises: Promise<any>[] = [];
for (const plug of this.system.loadedPlugs.values()) {
@@ -31,7 +31,7 @@ export class EventFeature implements Feature<EventHook> {
return Promise.all(promises);
}
apply(system: System<EventHook>): void {
apply(system: System<EventHookT>): void {
this.system = system;
this.system.on({
plugLoaded: (name) => {
@@ -40,7 +40,7 @@ export class EventFeature implements Feature<EventHook> {
});
}
validateManifest(manifest: Manifest<EventHook>): string[] {
validateManifest(manifest: Manifest<EventHookT>): string[] {
let errors = [];
for (const [name, functionDef] of Object.entries(manifest.functions)) {
if (functionDef.events && !Array.isArray(functionDef.events)) {
@@ -1,14 +1,14 @@
import { Feature, Manifest } from "../types";
import { Hook, Manifest } from "../types";
import cron, { ScheduledTask } from "node-cron";
import { safeRun } from "../util";
import { System } from "../system";
export type CronHook = {
export type CronHookT = {
cron?: string | string[];
};
export class NodeCronFeature implements Feature<CronHook> {
apply(system: System<CronHook>): void {
export class NodeCronHook implements Hook<CronHookT> {
apply(system: System<CronHookT>): void {
let tasks: ScheduledTask[] = [];
system.on({
plugLoaded: (name, plug) => {
@@ -56,7 +56,7 @@ export class NodeCronFeature implements Feature<CronHook> {
}
}
validateManifest(manifest: Manifest<CronHook>): string[] {
validateManifest(manifest: Manifest<CronHookT>): string[] {
let errors = [];
for (const [name, functionDef] of Object.entries(manifest.functions)) {
if (!functionDef.cron) {
+4 -4
View File
@@ -10,7 +10,7 @@
"watch": "rm -rf .parcel-cache && parcel watch",
"build": "parcel build",
"clean": "rm -rf dist",
"test": "jest dist"
"test": "jest dist/test"
},
"files": [
"dist"
@@ -28,9 +28,9 @@
"test": {
"source": [
"runtime.test.ts",
"feature/endpoint.test.ts",
"syscall/store.knex_node.test.ts",
"syscall/store.dexie_browser.test.ts"
"hooks/endpoint.test.ts",
"syscalls/store.knex_node.test.ts",
"syscalls/store.dexie_browser.test.ts"
],
"outputFormat": "commonjs",
"isLibrary": true,
+1 -1
View File
@@ -1,7 +1,7 @@
import fs from "fs/promises";
import watch from "node-watch";
import path from "path";
import { createSandbox } from "./environment/node_sandbox";
import { createSandbox } from "./environments/node_sandbox";
import { safeRun } from "../server/util";
import { System } from "./system";
+1 -1
View File
@@ -1,4 +1,4 @@
import { createSandbox } from "./environment/node_sandbox";
import { createSandbox } from "./environments/node_sandbox";
import { expect, test } from "@jest/globals";
import { System } from "./system";
+1 -1
View File
@@ -2,7 +2,7 @@ import {
ControllerMessage,
WorkerLike,
WorkerMessage,
} from "./environment/worker";
} from "./environments/worker";
import { Plug } from "./plug";
export type SandboxFactory<HookT> = (plug: Plug<HookT>) => Sandbox;
-10
View File
@@ -1,10 +0,0 @@
import { SysCallMapping } from "../system";
import { EventFeature } from "../feature/event";
export function eventSyscalls(eventFeature: EventFeature): SysCallMapping {
return {
async dispatch(ctx, eventName: string, data: any) {
return eventFeature.dispatchEvent(eventName, data);
},
};
}
+10
View File
@@ -0,0 +1,10 @@
import { SysCallMapping } from "../system";
import { EventHook } from "../hooks/event";
export function eventSyscalls(eventHook: EventHook): SysCallMapping {
return {
async dispatch(ctx, eventName: string, data: any) {
return eventHook.dispatchEvent(eventName, data);
},
};
}
@@ -1,4 +1,4 @@
import { createSandbox } from "../environment/node_sandbox";
import { createSandbox } from "../environments/node_sandbox";
import { expect, test } from "@jest/globals";
import { System } from "../system";
import { storeSyscalls } from "./store.dexie_browser";
@@ -1,4 +1,4 @@
import { createSandbox } from "../environment/node_sandbox";
import { createSandbox } from "../environments/node_sandbox";
import { expect, test } from "@jest/globals";
import { System } from "../system";
import {
+5 -5
View File
@@ -1,4 +1,4 @@
import { Feature, Manifest, RuntimeEnvironment } from "./types";
import { Hook, Manifest, RuntimeEnvironment } from "./types";
import { EventEmitter } from "../common/event";
import { SandboxFactory } from "./sandbox";
import { Plug } from "./plug";
@@ -31,7 +31,7 @@ type Syscall = {
export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
protected plugs = new Map<string, Plug<HookT>>();
protected registeredSyscalls = new Map<string, Syscall>();
protected enabledFeatures = new Set<Feature<HookT>>();
protected enabledHooks = new Set<Hook<HookT>>();
readonly runtimeEnv: RuntimeEnvironment;
@@ -40,8 +40,8 @@ export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
this.runtimeEnv = env;
}
addFeature(feature: Feature<HookT>) {
this.enabledFeatures.add(feature);
addHook(feature: Hook<HookT>) {
this.enabledHooks.add(feature);
feature.apply(this);
}
@@ -91,7 +91,7 @@ export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
}
// Validate
let errors: string[] = [];
for (const feature of this.enabledFeatures) {
for (const feature of this.enabledHooks) {
errors = [...errors, ...feature.validateManifest(manifest)];
}
if (errors.length > 0) {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"include": ["bin/*", "environment/*", "feature/**", "syscall/*", "*"],
"include": ["bin/*", "environments/*", "hooks/**", "syscalls/*", "*"],
"compilerOptions": {
"target": "esnext",
"strict": true,
+1 -1
View File
@@ -15,7 +15,7 @@ export type FunctionDef<HookT> = {
export type RuntimeEnvironment = "client" | "server";
export interface Feature<HookT> {
export interface Hook<HookT> {
validateManifest(manifest: Manifest<HookT>): string[];
apply(system: System<HookT>): void;