mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Strongly type invokeHook
Add strong typing of the invokeHook function to prevent incorrect paramaters being passed to plugin hooks. This detected a few places where the parameters passed were incorrect.
This commit is contained in:
1 parent
e3e5867d60
commit
654df76065
7 files changed
+24
-18
No files matched your search
@@ -661,7 +661,7 @@ export default class Controller {
|
||||
|
||||
let instance = new InstanceInfo({ config: instanceConfig, status: "unassigned" });
|
||||
this.instances!.set(instanceId, instance);
|
||||
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance, null);
|
||||
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance);
|
||||
this.addInstanceHooks(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ export default class HostConnection extends BaseConnection {
|
||||
instanceConfig.get("instance.id"), instanceConfig.serialize("host")
|
||||
)
|
||||
);
|
||||
await lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", newInstance, null);
|
||||
await lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", newInstance);
|
||||
}
|
||||
|
||||
// Push lists to make sure they are in sync.
|
||||
|
||||
@@ -37,8 +37,7 @@ async function getMetrics(req: Request, res: Response, next: any) {
|
||||
const controller: Controller = req.app.locals.controller;
|
||||
|
||||
let results: lib.CollectorResult[] = [];
|
||||
type ResultIterator = AsyncIterable<lib.CollectorResult> | Iterable<lib.CollectorResult>
|
||||
let pluginResults = await lib.invokeHook(controller.plugins, "onMetrics") as ResultIterator[];
|
||||
let pluginResults = await lib.invokeHook(controller.plugins, "onMetrics");
|
||||
for (let metricIterator of pluginResults) {
|
||||
for await (let metric of metricIterator) {
|
||||
results.push(metric);
|
||||
|
||||
@@ -594,8 +594,7 @@ export default class Host extends lib.Link {
|
||||
}
|
||||
|
||||
let results = [];
|
||||
type ResultIterator = AsyncIterable<lib.CollectorResult> | Iterable<lib.CollectorResult>
|
||||
let pluginResults = await lib.invokeHook(this.plugins, "onMetrics") as ResultIterator[];
|
||||
let pluginResults = await lib.invokeHook(this.plugins, "onMetrics");
|
||||
for (let metricIterator of pluginResults) {
|
||||
for await (let metric of metricIterator) {
|
||||
results.push(metric);
|
||||
@@ -859,7 +858,7 @@ export default class Host extends lib.Link {
|
||||
}
|
||||
|
||||
async prepareDisconnect() {
|
||||
await lib.invokeHook(this.plugins, "onPrepareControllerDisconnect");
|
||||
await lib.invokeHook(this.plugins, "onPrepareControllerDisconnect", this);
|
||||
for (let instanceConnection of this.instanceConnections.values()) {
|
||||
await instanceConnection.send(new lib.PrepareControllerDisconnectRequest());
|
||||
}
|
||||
|
||||
@@ -965,14 +965,13 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
|
||||
}
|
||||
|
||||
async handlePrepareControllerDisconnectRequest() {
|
||||
await lib.invokeHook(this.plugins, "onPrepareControllerDisconnect");
|
||||
await lib.invokeHook(this.plugins, "onPrepareControllerDisconnect", this);
|
||||
}
|
||||
|
||||
async handleInstanceMetricsRequest() {
|
||||
let results: ReturnType<typeof lib.serializeResult>[] = [];
|
||||
if (!["stopped", "stopping"].includes(this._status)) {
|
||||
type ResultIterator = AsyncIterable<lib.CollectorResult> | Iterable<lib.CollectorResult>
|
||||
let pluginResults = await lib.invokeHook(this.plugins, "onMetrics") as ResultIterator[];
|
||||
let pluginResults = await lib.invokeHook(this.plugins, "onMetrics");
|
||||
for (let metricIterator of pluginResults) {
|
||||
for await (let metric of metricIterator) {
|
||||
results.push(lib.serializeResult(metric));
|
||||
|
||||
@@ -96,11 +96,11 @@ export class ControllerConnectionEvent {
|
||||
static dst = "instance" as const;
|
||||
|
||||
constructor(
|
||||
public event: string,
|
||||
public event: "connect" | "drop" | "resume" | "close",
|
||||
) { }
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
"event": Type.String(),
|
||||
"event": StringEnum(["connect", "drop", "resume", "close"]),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* @module lib/plugin
|
||||
*/
|
||||
import * as libHelpers from "./helpers";
|
||||
import type { Logger } from "./logging";
|
||||
import type { PluginConfigGroup } from "./config";
|
||||
import type PlayerStats from "./PlayerStats";
|
||||
|
||||
@@ -71,14 +72,22 @@ export interface PlayerEvent {
|
||||
* @param args - Arguments to pass on to the hook.
|
||||
* @returns Non-undefined return values from the hooks.
|
||||
*/
|
||||
export async function invokeHook(plugins: Map<string, any>, hook: string, ...args: any[]) {
|
||||
let results: unknown[] = [];
|
||||
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 {
|
||||
// Use an object to detect if the hook failed on timeout or tried to return a value looking like an error
|
||||
const timeout = {};
|
||||
let result = await libHelpers.timeout(
|
||||
(plugin as any)[hook](...args),
|
||||
const timeout = Symbol("timeout-token");
|
||||
let result = await libHelpers.timeout<R | typeof timeout>(
|
||||
plugin[hook](...args) as Promise<R>,
|
||||
15000,
|
||||
timeout
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user