Tons of refactoring, moving commands and slash commands into hooks
This commit is contained in:
+22
-22
@@ -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
@@ -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,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,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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -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
-1
@@ -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
@@ -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,5 +1,5 @@
|
||||
{
|
||||
"include": ["bin/*", "environment/*", "feature/**", "syscall/*", "*"],
|
||||
"include": ["bin/*", "environments/*", "hooks/**", "syscalls/*", "*"],
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"strict": true,
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user