silverbullet/web/hooks/syscall.ts

68 lines
2.0 KiB
TypeScript

import type { Hook, Manifest } from "$lib/plugos/types.ts";
import type { System } from "$lib/plugos/system.ts";
import type { SyscallHookT } from "$lib/manifest.ts";
import type { SysCallMapping } from "$lib/plugos/system.ts";
export class SyscallHook implements Hook<SyscallHookT> {
apply(system: System<SyscallHookT>): void {
this.registerSyscalls(system);
system.on({
plugLoaded: () => {
this.registerSyscalls(system);
},
});
}
registerSyscalls(system: System<SyscallHookT>) {
// Register syscalls from all loaded plugs
for (const plug of system.loadedPlugs.values()) {
const syscalls: SysCallMapping = {};
for (
const [name, functionDef] of Object.entries(plug.manifest!.functions)
) {
if (!functionDef.syscall) {
continue;
}
const syscallName = functionDef.syscall;
// Add the syscall to our mapping
syscalls[syscallName] = (ctx, ...args) => {
// Delegate to the system to invoke the function
return system.syscall(ctx, "system.invokeFunction", [
`${plug.manifest!.name}.${name}`,
...args,
]);
};
// Register the syscalls with no required permissions
system.registerSyscalls([], syscalls);
}
}
}
validateManifest(manifest: Manifest<SyscallHookT>): string[] {
const errors: string[] = [];
for (const [name, functionDef] of Object.entries(manifest.functions)) {
if (!functionDef.syscall) {
continue;
}
// Validate syscall name is provided
if (!functionDef.syscall) {
errors.push(`Function ${name} has a syscall but no name`);
continue;
}
// Validate syscall name format (should be namespaced)
if (!functionDef.syscall.includes(".")) {
errors.push(
`Function ${name} has invalid syscall name "${functionDef.syscall}" - must be in format "namespace.name"`,
);
}
}
return errors;
}
}