135 lines
No EOL
4.5 KiB
TypeScript
135 lines
No EOL
4.5 KiB
TypeScript
import GameflowHooks from "../hooks/app";
|
|
import { PluginDescriptionType, PluginLoadingContextType, PluginType } from "../../types/types.schema";
|
|
import { config } from "../app";
|
|
import Conf from "conf";
|
|
import projectPackage from '~/package.json';
|
|
import z from "zod";
|
|
import { PluginSourceType } from "@/shared/types";
|
|
|
|
export const pluginZodRegistry = z.registry<{
|
|
requiresRestart?: boolean;
|
|
readOnly?: boolean;
|
|
}>();
|
|
|
|
export class PluginManager
|
|
{
|
|
hooks = new GameflowHooks();
|
|
plugins: Record<string, {
|
|
enabled: boolean,
|
|
loaded: boolean,
|
|
plugin: PluginType;
|
|
description: PluginDescriptionType,
|
|
source: PluginSourceType;
|
|
config?: Conf;
|
|
|
|
}> = {};
|
|
|
|
register (plugin: PluginType, description: PluginDescriptionType, source: PluginSourceType)
|
|
{
|
|
try
|
|
{
|
|
if (this.plugins[description.name])
|
|
{
|
|
console.error("Plugin with name", description.name, "already registered");
|
|
}
|
|
else
|
|
{
|
|
let pluginConfig: Conf | undefined = undefined;
|
|
if (plugin.settingsSchema)
|
|
{
|
|
pluginConfig = new Conf({
|
|
projectName: projectPackage.name,
|
|
configName: description.name,
|
|
projectSuffix: 'bun',
|
|
cwd: process.env.CONFIG_CWD,
|
|
schema: Object.fromEntries(Object.entries(plugin.settingsSchema.shape).map(([key, schema]) => [key, (schema as z.ZodObject).toJSONSchema() as any])) as any,
|
|
defaults: plugin.settingsSchema.parse({}),
|
|
migrations: plugin.settingsMigrations as any,
|
|
projectVersion: description.version
|
|
});
|
|
}
|
|
|
|
this.plugins[description.name] = {
|
|
enabled: !config.get('disabledPlugins').includes(description.name),
|
|
loaded: false,
|
|
plugin: plugin,
|
|
source: source,
|
|
description: description,
|
|
config: pluginConfig
|
|
};
|
|
console.log("Plugin", description.name, "registered");
|
|
}
|
|
|
|
}
|
|
catch (error)
|
|
{
|
|
console.log("Error While Registering plugin");
|
|
console.error(error);
|
|
};
|
|
}
|
|
|
|
private async reload (name: string, reloadCtx: { setProgress: (progress: number, state: string) => void; })
|
|
{
|
|
const plugin = this.plugins[name];
|
|
if (plugin)
|
|
{
|
|
const ctx: PluginLoadingContextType = {
|
|
hooks: this.hooks,
|
|
setProgress: reloadCtx.setProgress.bind(reloadCtx),
|
|
config: plugin.config as any,
|
|
zodRegistry: pluginZodRegistry
|
|
};
|
|
|
|
if (plugin.loaded)
|
|
{
|
|
await plugin.plugin.cleanup?.();
|
|
plugin.loaded = false;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (plugin.enabled || plugin.description.canDisable === false)
|
|
{
|
|
console.log("Loading Plugin", plugin.description.name);
|
|
await plugin.plugin.load(ctx);
|
|
console.log("Loaded Plugin", plugin.description.name);
|
|
plugin.loaded = true;
|
|
}
|
|
} catch (error)
|
|
{
|
|
console.log("Error for plugin", plugin.description.name, "while loading");
|
|
console.error(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
async reloadAll (ctx: { setProgress: (progress: number, state: string) => void; })
|
|
{
|
|
this.hooks = new GameflowHooks();
|
|
for await (const id of Object.keys(this.plugins))
|
|
{
|
|
ctx.setProgress(0, `Loading ${id}`);
|
|
await this.reload(id, ctx);
|
|
}
|
|
}
|
|
|
|
async cleanup ()
|
|
{
|
|
await Promise.all(Object.values(this.plugins).filter(p => p.loaded && p.plugin.cleanup).map(async p =>
|
|
{
|
|
try
|
|
{
|
|
if (p.loaded)
|
|
{
|
|
console.log("Starting", p.description.name, "plugin cleanup");
|
|
await p.plugin.cleanup!();
|
|
console.log(p.description.name, "cleanup complete");
|
|
}
|
|
} catch (error)
|
|
{
|
|
console.error("Error for plugin", p.description.name, "while cleaning up");
|
|
console.error(error);
|
|
}
|
|
}));
|
|
}
|
|
} |