mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
122 lines
3.2 KiB
TypeScript
122 lines
3.2 KiB
TypeScript
/**
|
|
* Plugin interfaces and utilities.
|
|
* @module lib/plugin
|
|
*/
|
|
import * as libHelpers from "./helpers";
|
|
import type { Logger } from "./logging";
|
|
import type { FieldDefinition } from "./config";
|
|
import type { PlayerStats } from "./data";
|
|
|
|
|
|
export const PluginFeatureFlags = [
|
|
/** The plugin requires module code to be patched into the save */
|
|
"SavePatching",
|
|
/** The plugin requires access to script commands over rcon */
|
|
"ScriptCommands",
|
|
] as const;
|
|
|
|
/** Used to define the plugin export in plugins */
|
|
export type PluginDeclaration = {
|
|
name: string;
|
|
title: string;
|
|
description?: string;
|
|
|
|
controllerEntrypoint?: string;
|
|
controllerConfigFields?: Record<string, FieldDefinition>;
|
|
|
|
hostEntrypoint?: string;
|
|
hostConfigFields?: Record<string, FieldDefinition>;
|
|
|
|
instanceEntrypoint?: string;
|
|
instanceConfigFields?: Record<string, FieldDefinition>;
|
|
|
|
ctlEntrypoint?: string;
|
|
webEntrypoint?: string;
|
|
controlConfigFields?: Record<string, FieldDefinition>;
|
|
|
|
features?: (typeof PluginFeatureFlags)[number][];
|
|
|
|
messages?: any[];
|
|
routes?: string[];
|
|
}
|
|
|
|
export type PluginNodeEnvInfo = PluginDeclaration & {
|
|
requirePath: string;
|
|
version: string;
|
|
manifest: any;
|
|
/**
|
|
* NPM package this plugin is published as. Not present if the package
|
|
* is private or the path used to load it does not match the name of the
|
|
* package.
|
|
*/
|
|
npmPackage?: string;
|
|
};
|
|
|
|
export type PluginWebpackEnvInfo = PluginDeclaration & {
|
|
container?: any;
|
|
package?: any;
|
|
enabled?: boolean;
|
|
error?: string;
|
|
};
|
|
|
|
/**
|
|
* Information about the event.
|
|
*/
|
|
export interface PlayerEvent {
|
|
type: "join" | "leave" | "import" | "promote" | "demote" | "ban" | "unban" | "whitelisted" | "unwhitelisted";
|
|
/** Name of the player that caused the event */
|
|
name: string,
|
|
/**
|
|
* Only present for type "leave" and "ban". Reason for player leaving the
|
|
* game, one of the possible reasons in defines.disconnect_reason
|
|
* or "server_quit" if the server exits while the player is online.
|
|
* When type is "ban" this is the reason given for the ban.
|
|
*/
|
|
reason?: string;
|
|
/**
|
|
* Statistics recorded for this player on the instance this event
|
|
* originated from.
|
|
*/
|
|
stats: PlayerStats,
|
|
}
|
|
|
|
/**
|
|
* Invokes the given hook on all plugins
|
|
*
|
|
* @param plugins -
|
|
* Mapping of plugin names to plugins to invoke the hook on.
|
|
* @param hook - Name of hook to invoke.
|
|
* @param args - Arguments to pass on to the hook.
|
|
* @returns Non-undefined return values from the hooks.
|
|
*/
|
|
export async function invokeHook<
|
|
Hook extends string,
|
|
R,
|
|
Args extends [...any],
|
|
Plugin extends { logger: Logger } & Record<Hook, (...hookArgs: Args) => R | Promise<R>>
|
|
>(
|
|
plugins: Map<string, Plugin>,
|
|
hook: Hook,
|
|
...args: Args
|
|
): Promise<Exclude<Awaited<ReturnType<Plugin[Hook]>>, void>[]> {
|
|
let results: any[] = [];
|
|
for (let [name, plugin] of plugins) {
|
|
try {
|
|
const timeout = Symbol("timeout-token");
|
|
let result = await libHelpers.timeout<R | typeof timeout>(
|
|
plugin[hook](...args) as Promise<R>,
|
|
15000,
|
|
timeout
|
|
);
|
|
if (result === timeout) {
|
|
throw new Error(`Invoking hook ${hook} timed out for plugin ${name}`);
|
|
} else if (result !== undefined) {
|
|
results.push(result);
|
|
}
|
|
} catch (err: any) {
|
|
plugin.logger.error(`Ignoring error from plugin ${name} in ${hook}:\n${err.stack}`);
|
|
}
|
|
}
|
|
return results;
|
|
}
|