diff --git a/clean.js b/clean.js index 51bc9f47..48c8c5b1 100644 --- a/clean.js +++ b/clean.js @@ -74,7 +74,7 @@ async function removeTestArtifacts() { async function removeExecutionArtifacts() { const artifacts = [ "database", "instances", "logs", "mods", - "config-control.json", "config-controller.json", "config-host.json", + "config-ctl.json", "config-controller.json", "config-host.json", "FactorioAdminToken.txt", "plugin-list.json", ]; diff --git a/docs/configuration.md b/docs/configuration.md index 8863454b..818f0e48 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -706,16 +706,16 @@ Loading a plugin that requires save patching or script commands is rejected whil Defaults to true. -## Control Configuration +## Ctl Configuration -### control.controller_url +### ctl.controller_url URL to connect to the controller to. Defaults to null meaning complain about it not being set and exit. -### control.controller_token +### ctl.controller_token Access token used for authenticating with the controller. You can generate an access token with `clusteriocontroller bootstrap generate-user-token `, or use the `clusteriocontroller bootstrap create-ctl-config ` to create a new ctl config with the correct url and token in it. @@ -723,7 +723,7 @@ You can generate an access token with `clusteriocontroller bootstrap generate-us Defaults to null meaning complain about it not being set and exit. -### control.max_reconnect_delay +### ctl.max_reconnect_delay Max duration in seconds to wait before attempting to reconnect with the controller after the connection is dropped. The actual delay on each reconnect will be a random number between 0 and this configured value to avoid all clients trying to reconnect at the same time. diff --git a/docs/contributing.md b/docs/contributing.md index 62dc3c71..a2067658 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -77,7 +77,7 @@ The documentation uses the binaries provided by the packages, but for the develo By default node does not enable source maps, to get stack traces pointing to the `.ts` files you will need to pass `--enable-source-maps` to `node` or set the environment variable `NODE_OPTIONS=--enable-source-maps`. -Note that to use `clusterioctl` you will have to create a control config first: +Note that to use `clusterioctl` you will have to create a ctl config first: node packages/controller bootstrap create-ctl-config [admin-user] diff --git a/docs/devs/protocol.md b/docs/devs/protocol.md index ae072857..08efe8b8 100644 --- a/docs/devs/protocol.md +++ b/docs/devs/protocol.md @@ -14,7 +14,7 @@ All messages sent and received are validated with JSON schemas to catch potentia Messages are sent by calling the `.send()` method of the message instance and passing a `Link` instance to send it over and the data to send. For the controller there's a `Link` instance for each host and control connection stored in the `WsServer` class. For hosts the `Host` instance is a link to the controller, and each `Instance` instance is an in-memory link to the `Host` instance and has a corresponding `InstanceConnection` link stored on the `Host` instance. -For ctl and web_ui there's a `Control` instance that acts as the link to the controller. +For ctl there's a `Ctl` instance and web_ui there's a `Control` instance that acts as the link to the controller. Messages received invokes message handlers that were registered when the link was brought up. These handlers are named after the name of the property the message is stored under with `EventHandler` appended for events and `RequestHandler` appended for requests. diff --git a/docs/writing-plugins.md b/docs/writing-plugins.md index b6205037..5b9c02f8 100644 --- a/docs/writing-plugins.md +++ b/docs/writing-plugins.md @@ -28,7 +28,7 @@ The basic file structure of a plugin is the following. +- package.json +- controller.js +- instance.js - +- control.js + +- ctl.js +- test/ | +- plugin.js +- module/ @@ -643,7 +643,7 @@ controller.hooks.metrics.attach(plugin.name, async () => fooRegistry.collect()); ## Adding Custom Commands to clusterioctl -The control entrypoint for plugins allows you to extend clustectl with your own commands. +The ctl entrypoint for plugins allows you to extend clustectl with your own commands. The creation of custom commands typically starts with defining a command tree for the plugin: ```js @@ -664,8 +664,8 @@ fooFrobberCommands.add(new Command({ describe: "type of frobnication", type: "string" }); }], - handler: async function(args, control) { - await info.messages.frobnicate.send(control, { + handler: async function(args, ctl) { + await info.messages.frobnicate.send(ctl, { instance_name: "Console", content: args.message, }); @@ -674,7 +674,7 @@ fooFrobberCommands.add(new Command({ ``` For a command the `definition` is the arguments to pass to [yargs.command](http://yargs.js.org/docs/#api-reference-commandcmd-desc-builder-handler) (see also [yargs.positional](http://yargs.js.org/docs/#api-reference-positionalkey-opt) and [yargs.options](http://yargs.js.org/docs/#api-reference-optionskey-opt) for setting up positional and optional arguments to commands). -The `handler` is an async function that's invoked when the command is executed and it's passed the parsed command line arguments and a reference to the `Control` class of clusterioctl. +The `handler` is an async function that's invoked when the command is executed and it's passed the parsed command line arguments and a reference to the `Ctl` class of clusterioctl. Note that messages sent from clusterioctl needs to have `"control-controller"` as a part of the links array for it to be accepted by the controller, see [Defining Link Messages](#defining-link-messages) for how to define the messages that can be sent to the controller. To have the command tree become part of clusterioctl it needs to be added to the rootCommand tree in the `addCommands` hook of the ctl entrypoint: diff --git a/packages/controller/controller.ts b/packages/controller/controller.ts index 7e38e29f..b8cc26ed 100644 --- a/packages/controller/controller.ts +++ b/packages/controller/controller.ts @@ -201,15 +201,15 @@ async function handleBootstrapCommand( process.exitCode = 1; return; } - let controlConfig = new lib.ControlConfig("control"); + let ctlConfig = new lib.CtlConfig("control"); - controlConfig.set("control.controller_url", Controller.calculateControllerUrl(controllerConfig)); - controlConfig.set( - "control.controller_token", + ctlConfig.set("ctl.controller_url", Controller.calculateControllerUrl(controllerConfig)); + ctlConfig.set( + "ctl.controller_token", userManager.signUserToken(admin), ); - let content = JSON.stringify(controlConfig, null, "\t"); + let content = JSON.stringify(ctlConfig, null, "\t"); if (args.output === "-") { // eslint-disable-next-line no-console console.log(content); @@ -322,7 +322,7 @@ async function initialize(): Promise { .command("create-ctl-config ", "Create clusterioctl config for the given user", yargs => { yargs.option("output", { describe: "Path to output config (- for stdout)", type: "string", - nargs: 1, default: "config-control.json", + nargs: 1, default: "config-ctl.json", }); }) .demandCommand(1, "You need to specify a command to run"); diff --git a/packages/create/create.js b/packages/create/create.js index 5980f9d2..930f9570 100755 --- a/packages/create/create.js +++ b/packages/create/create.js @@ -887,8 +887,8 @@ async function main() { } if (answers.mode === "ctl") { - await execCtl(["control-config", "set", "control.controller_url", answers.controllerUrl]); - await execCtl(["control-config", "set", "control.controller_token", answers.controllerToken]); + await execCtl(["config", "set", "ctl.controller_url", answers.controllerUrl]); + await execCtl(["config", "set", "ctl.controller_token", answers.controllerToken]); } /* eslint-disable no-console */ diff --git a/packages/create/templates/plugin-js/ctl.js b/packages/create/templates/plugin-js/ctl.js index b3f16594..59a1546b 100644 --- a/packages/create/templates/plugin-js/ctl.js +++ b/packages/create/templates/plugin-js/ctl.js @@ -11,8 +11,8 @@ pluginCommands.add(new Command({ definition: ["my-command ", "My command description that I really should change", (yargs) => { yargs.positional("foo", { describe: "foo is foo!", type: "string" }); }], - handler: async function(args, control) { - const response = await control.sendTo("controller", new PluginExampleRequest(args.foo, [1, 2, 3])); + handler: async function(args, ctl) { + const response = await ctl.sendTo("controller", new PluginExampleRequest(args.foo, [1, 2, 3])); console.log(response); console.log(args); }, diff --git a/packages/create/templates/plugin-js/index.js b/packages/create/templates/plugin-js/index.js index 171341cb..98cc8c75 100644 --- a/packages/create/templates/plugin-js/index.js +++ b/packages/create/templates/plugin-js/index.js @@ -62,9 +62,9 @@ export const plugin = { ctlEntrypoint: "./dist/node/ctl.js", //%endif //%if ctl & config - controlConfigFields: { - "__plugin_name__.myControlField": { - title: "My Control Field", + ctlConfigFields: { + "__plugin_name__.myCtlField": { + title: "My Ctl Field", description: "This should be removed from index.js", type: "string", initialValue: "Remove Me", diff --git a/packages/create/templates/plugin-ts/ctl.ts b/packages/create/templates/plugin-ts/ctl.ts index 6211d37c..e468029b 100644 --- a/packages/create/templates/plugin-ts/ctl.ts +++ b/packages/create/templates/plugin-ts/ctl.ts @@ -1,4 +1,4 @@ -import type { Control, CtlPluginContext } from "@clusterio/ctl"; +import type { Ctl, CtlPluginContext } from "@clusterio/ctl"; import { CommandTree, Command } from "@clusterio/lib"; //%// We do not check for multi context here because it doesn't make sense to have a ctl without messages import { PluginExampleEvent, PluginExampleRequest } from "./messages.js"; @@ -12,8 +12,8 @@ pluginCommands.add(new Command({ definition: ["my-command ", "My command description that I really should change", (yargs) => { yargs.positional("foo", { describe: "foo is foo!", type: "string" }); }], - handler: async function(args: { foo: string }, control: Control) { - const response = await control.sendTo("controller", new PluginExampleRequest(args.foo, [1, 2, 3])); + handler: async function(args: { foo: string }, ctl: Ctl) { + const response = await ctl.sendTo("controller", new PluginExampleRequest(args.foo, [1, 2, 3])); console.log(response); console.log(args); }, diff --git a/packages/create/templates/plugin-ts/index.ts b/packages/create/templates/plugin-ts/index.ts index f35b29e4..4a46060b 100644 --- a/packages/create/templates/plugin-ts/index.ts +++ b/packages/create/templates/plugin-ts/index.ts @@ -22,8 +22,8 @@ declare module "@clusterio/lib" { } //%endif //%if ctl & config - export interface ControlConfigFields { - "__plugin_name__.myControlField": string; + export interface CtlConfigFields { + "__plugin_name__.myCtlField": string; } //%endif //%if multi_context | web @@ -106,9 +106,9 @@ export const plugin: lib.PluginDeclaration = { ctlEntrypoint: "./dist/node/ctl.js", //%endif //%if ctl & config - controlConfigFields: { - "__plugin_name__.myControlField": { - title: "My Control Field", + ctlConfigFields: { + "__plugin_name__.myCtlField": { + title: "My Ctl Field", description: "This should be removed from index.js", type: "string", initialValue: "Remove Me", diff --git a/packages/ctl/README.md b/packages/ctl/README.md index c116dd3b..71aa1d9d 100644 --- a/packages/ctl/README.md +++ b/packages/ctl/README.md @@ -17,7 +17,7 @@ Common options: See the `plugin` command for managing this list. * `--config ` JSON file to use for storing configuration for ctl. - Defaults to `config-control.json` and will be created if it does not exist. + Defaults to `config-ctl.json` and will be created if it does not exist. See the `config` command for inspecting and modifying the configuration. @@ -70,13 +70,13 @@ Since the `plugin-list.json` is shared between controller, host and ctl you usua Lists the plugins set up to be available by name followed by path. -### `config-control` +### `config` Manage the ctl configuration. This allows setting the url and token to the controller to manage. -#### `config-control set [value]` +#### `config set [value]` Set a config entry to the given value. If value is not provided the entry is set to null. @@ -85,12 +85,12 @@ If the config entry is of type object the value must be a valid JSON serializati See docs/configuration.md in the main repositiory for the available configuration. -#### `config-control show ` +#### `config show ` Shows the value for a single config entry. -#### `config-control list` +#### `config list` Lists up all configuration entries with their currently configured values. diff --git a/packages/ctl/ctl.ts b/packages/ctl/ctl.ts index b81562f4..573a0b6d 100755 --- a/packages/ctl/ctl.ts +++ b/packages/ctl/ctl.ts @@ -23,7 +23,7 @@ import { BaseCtlPlugin, CtlHooks } from "./src/BaseCtlPlugin.js"; * Connector for control connection to controller * @private */ -class ControlConnector extends lib.WebSocketClientConnector { +class CtlConnector extends lib.WebSocketClientConnector { private _token: string; constructor(url: string, maxReconnectDelay: number, token: string) { @@ -45,23 +45,23 @@ class ControlConnector extends lib.WebSocketClientConnector { } /** - * Handles running the control + * Handles running ctl * * Connects to the controller over WebSocket and sends commands to it. * @static */ -export class Control extends lib.Link { - /** Control config used for connecting to the controller. */ - config: lib.ControlConfig; +export class Ctl extends lib.Link { + /** Ctl config used for connecting to the controller. */ + config: lib.CtlConfig; /** Keep the control connection alive after the command completes. */ keepOpen = false; constructor( - connector: ControlConnector, - controlConfig: lib.ControlConfig, + connector: CtlConnector, + ctlConfig: lib.CtlConfig, ) { super(connector); - this.config = controlConfig; + this.config = ctlConfig; this.handle(lib.LogMessageEvent, this.handleLogMessageEvent.bind(this)); this.handle(lib.DebugWsMessageEvent, this.handleDebugWsMessageEvent.bind(this)); @@ -92,7 +92,7 @@ export class Control extends lib.Link { async shutdown() { try { - await (this.connector as ControlConnector).disconnect(); + await (this.connector as CtlConnector).disconnect(); } catch (err) { if (!(err instanceof lib.SessionLost)) { throw err; @@ -135,7 +135,7 @@ interface InitializeParameters { shouldRun: boolean; ctlHooks: CtlHooks; rootCommands?: lib.CommandTree; - controlConfig?: lib.ControlConfig; + ctlConfig?: lib.CtlConfig; } export async function initialize( @@ -166,7 +166,7 @@ export async function initialize( .option("config", { nargs: 1, describe: "config file to get credentails from", - default: "config-control.json", + default: "config-ctl.json", defaultDescription: "auto", type: "string", }) @@ -178,7 +178,7 @@ export async function initialize( }) .option("bypass-lock-file", { hidden: true, type: "boolean", nargs: 0, default: false }) .command("plugin", "Manage available plugins", lib.pluginCommand) - .command("control-config", "Manage Control config", lib.configCommand) + .command("config", "Manage ctl config", lib.configCommand) .wrap(parser.terminalWidth()) .help(false) // Disable help to avoid triggering it on the first parse. ; @@ -222,22 +222,22 @@ export async function initialize( .parse(argv) as CtlArguments ; - const controlConfigPath = args.config; - const controlConfigLockPath = `${controlConfigPath}.lock`; + const ctlConfigPath = args.config; + const ctlConfigLockPath = `${ctlConfigPath}.lock`; if (args.bypassLockFile) { - await fs.unlink(controlConfigLockPath).catch(() => {}); // ignore error, file might not exist + await fs.unlink(ctlConfigLockPath).catch(() => {}); // ignore error, file might not exist } - let controlConfig; - const controlConfigLock = new lib.LockFile(controlConfigLockPath); - logger.verbose(`Loading config from ${controlConfigPath}`); + let ctlConfig; + const ctlConfigLock = new lib.LockFile(ctlConfigLockPath); + logger.verbose(`Loading config from ${ctlConfigPath}`); try { - controlConfig = await lib.ControlConfig.fromFile("control", controlConfigPath); + ctlConfig = await lib.CtlConfig.fromFile("control", ctlConfigPath); } catch (err: any) { if (err.code === "ENOENT") { logger.verbose("Config not found, initializing new config"); - controlConfig = new lib.ControlConfig("control", undefined, controlConfigPath); + ctlConfig = new lib.CtlConfig("control", undefined, ctlConfigPath); } else { throw new lib.StartupError(`Failed to load ${args.config}: ${err.stack ?? err.message ?? err}`); @@ -249,13 +249,13 @@ export async function initialize( parser.exit(1, undefined as unknown as Error); // Type definition file is wrong. } - // Handle the control-config command before trying to connect. - if (args._[0] === "control-config") { - await lib.handleConfigCommand(args, controlConfig, controlConfigLock); - return { args, controlConfig, ctlHooks, rootCommands, shouldRun: false }; + // Handle the config command before trying to connect. + if (args._[0] === "config") { + await lib.handleConfigCommand(args, ctlConfig, ctlConfigLock); + return { args, ctlConfig, ctlHooks, rootCommands, shouldRun: false }; } - return { args, controlConfig, ctlHooks, rootCommands, shouldRun: true }; + return { args, ctlConfig, ctlHooks, rootCommands, shouldRun: true }; } export function selectTargetCommand(args: CtlArguments, rootCommands: lib.CommandTree): lib.Command { @@ -268,30 +268,30 @@ export function selectTargetCommand(args: CtlArguments, rootCommands: lib.Comman return targetCommand; } -async function startControl() { +async function startCtl() { const { args, shouldRun, rootCommands, - controlConfig, + ctlConfig, } = await initialize(process.argv.slice(2)); - if (!shouldRun || !rootCommands || !controlConfig) { + if (!shouldRun || !rootCommands || !ctlConfig) { return; } - if (!controlConfig.get("control.controller_url") || !controlConfig.get("control.controller_token")) { + if (!ctlConfig.get("ctl.controller_url") || !ctlConfig.get("ctl.controller_token")) { logger.error("Missing URL and/or token to connect with. See README.md for setting up access."); process.exitCode = 1; return; } - let controlConnector = new ControlConnector( - controlConfig.get("control.controller_url")!, - controlConfig.get("control.max_reconnect_delay"), - controlConfig.get("control.controller_token")!, + let controlConnector = new CtlConnector( + ctlConfig.get("ctl.controller_url")!, + ctlConfig.get("ctl.max_reconnect_delay"), + ctlConfig.get("ctl.controller_token")!, ); - let control = new Control(controlConnector, controlConfig); + let ctl = new Ctl(controlConnector, ctlConfig); try { await controlConnector.connect(); } catch (err) { @@ -302,15 +302,15 @@ async function startControl() { } // Handle interrupts - process.on("SIGINT", lib.createShutdownGuard(logger, "interrupt", control.shutdown.bind(control))); - process.on("SIGTERM", lib.createShutdownGuard(logger, "termination", control.shutdown.bind(control))); + process.on("SIGINT", lib.createShutdownGuard(logger, "interrupt", ctl.shutdown.bind(ctl))); + process.on("SIGTERM", lib.createShutdownGuard(logger, "termination", ctl.shutdown.bind(ctl))); try { const targetCommand = selectTargetCommand(args, rootCommands); - await targetCommand.run(args, control); + await targetCommand.run(args, ctl); } catch (err) { - control.keepOpen = false; + ctl.keepOpen = false; if (err instanceof lib.CommandError) { logger.error(`Error running command: ${err.message}`); process.exitCode = 1; @@ -328,8 +328,8 @@ async function startControl() { } } finally { - if (!control.keepOpen) { - await control.shutdown(); + if (!ctl.keepOpen) { + await ctl.shutdown(); } } } @@ -343,16 +343,16 @@ I version of clusterio. Expect things to break. I +==========================================================+ ` ); - startControl().catch(err => { + startCtl().catch(err => { if (err.errors) { logger.fatal(JSON.stringify(err.errors, null, "\t")); } if (!(err instanceof lib.StartupError)) { logger.fatal(` -+------------------------------------------------------------+ -| Unexpected error occured while starting control, please | -| report it to https://github.com/clusterio/clusterio/issues | -+------------------------------------------------------------+ ++---------------------------------------------------------------+ +| Unexpected error occured while starting clussterioctl, please | +| report it to https://github.com/clusterio/clusterio/issues | ++---------------------------------------------------------------+ ${err.stack}` ); } else { diff --git a/packages/ctl/src/commands_controller.ts b/packages/ctl/src/commands_controller.ts index a6684abd..266fadb9 100644 --- a/packages/ctl/src/commands_controller.ts +++ b/packages/ctl/src/commands_controller.ts @@ -5,7 +5,7 @@ import os from "os"; import child_process from "child_process"; import * as lib from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; import { serializedConfigToString, getEditor, configToKeyVal } from "./config_ops.js"; @@ -14,15 +14,15 @@ const asTable = asTableModule.configure({ delimiter: " | " }); export const controllerCommands = new lib.CommandTree({ name: "controller", description: "Controller management" }); controllerCommands.add(new lib.Command({ definition: ["stop", "Stop controller"], - handler: async function(_args: object, control: Control) { - await control.send(new lib.ControllerStopRequest()); + handler: async function(_args: object, ctl: Ctl) { + await ctl.send(new lib.ControllerStopRequest()); }, })); controllerCommands.add(new lib.Command({ definition: ["restart", "Restart controller"], - handler: async function(_args: object, control: Control) { - await control.send(new lib.ControllerRestartRequest()); + handler: async function(_args: object, ctl: Ctl) { + await ctl.send(new lib.ControllerRestartRequest()); }, })); controllerCommands.add(new lib.Command({ @@ -30,14 +30,14 @@ controllerCommands.add(new lib.Command({ yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); yargs.option("all", { alias: "a", type: "boolean", description: "Also update all plugins" }); }], - handler: async function(args: { restart: boolean, all: boolean }, control: Control) { + handler: async function(args: { restart: boolean, all: boolean }, ctl: Ctl) { if (args.all) { - await control.send(new lib.UpdateAllRequest()); + await ctl.send(new lib.UpdateAllRequest()); } else { - await control.send(new lib.ControllerUpdateRequest()); + await ctl.send(new lib.ControllerUpdateRequest()); } if (args.restart) { - await control.send(new lib.ControllerRestartRequest()); + await ctl.send(new lib.ControllerRestartRequest()); } else { print("Controller updated; a restart is required to apply the changes."); } @@ -50,8 +50,8 @@ const controllerConfigCommands = new lib.CommandTree({ controllerConfigCommands.add(new lib.Command({ definition: ["list", "List controller configuration"], - handler: async function(args: object, control: Control) { - let config = await control.send(new lib.ControllerConfigGetRequest()); + handler: async function(args: object, ctl: Ctl) { + let config = await ctl.send(new lib.ControllerConfigGetRequest()); for (let [name, value] of Object.entries(config)) { print(`${name} ${JSON.stringify(value)}`); @@ -67,13 +67,13 @@ controllerConfigCommands.add(new lib.Command({ "stdin": { describe: "read value from stdin", nargs: 0, type: "boolean" }, }); }], - handler: async function(args: { field: string, value?: string, stdin?: boolean }, control: Control) { + handler: async function(args: { field: string, value?: string, stdin?: boolean }, ctl: Ctl) { if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } else if (args.value === undefined) { args.value = ""; } - await control.send(new lib.ControllerConfigSetFieldRequest(args.field, args.value)); + await ctl.send(new lib.ControllerConfigSetFieldRequest(args.field, args.value)); }, })); @@ -86,7 +86,7 @@ controllerConfigCommands.add(new lib.Command({ "stdin": { describe: "read value from stdin", nargs: 0, type: "boolean" }, }); }], - handler: async function(args: { field: string, prop: string, value?: string, stdin?: boolean }, control: Control) { + handler: async function(args: { field: string, prop: string, value?: string, stdin?: boolean }, ctl: Ctl) { if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } @@ -102,7 +102,7 @@ controllerConfigCommands.add(new lib.Command({ } value = args.value; } - await control.send(new lib.ControllerConfigSetPropRequest(args.field, args.prop, value)); + await ctl.send(new lib.ControllerConfigSetPropRequest(args.field, args.prop, value)); }, })); controllerConfigCommands.add(new lib.Command({ @@ -113,8 +113,8 @@ controllerConfigCommands.add(new lib.Command({ default: "", }); }], - handler: async function(args: { editor: string }, control: Control) { - let config = await control.send(new lib.ControllerConfigGetRequest()); + handler: async function(args: { editor: string }, ctl: Ctl) { + let config = await ctl.send(new lib.ControllerConfigGetRequest()); let tmpFile = await lib.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = await getEditor(args.editor); if (editor === undefined) { @@ -138,7 +138,7 @@ controllerConfigCommands.add(new lib.Command({ for (let index in final) { if (index in final) { try { - await control.send(new lib.ControllerConfigSetFieldRequest( + await ctl.send(new lib.ControllerConfigSetFieldRequest( index, final[index], )); @@ -167,8 +167,8 @@ const controllerPluginCommands = new lib.CommandTree({ }); controllerPluginCommands.add(new lib.Command({ definition: ["list", "List plugins on controller"], - handler: async function(args: object, control: Control) { - let url = new URL(control.config.get("control.controller_url")!); + handler: async function(args: object, ctl: Ctl) { + let url = new URL(ctl.config.get("ctl.controller_url")!); url.pathname += "api/plugins"; let response = await fetch(url); print(asTable(await response.json() as [])); @@ -179,10 +179,10 @@ controllerPluginCommands.add(new lib.Command({ yargs.positional("plugin", { describe: "Plugin to update", type: "string" }); yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); }], - handler: async function(args: { plugin: string, restart: boolean }, control: Control) { - await control.sendTo("controller", new lib.PluginUpdateRequest(args.plugin)); + handler: async function(args: { plugin: string, restart: boolean }, ctl: Ctl) { + await ctl.sendTo("controller", new lib.PluginUpdateRequest(args.plugin)); if (args.restart) { - await control.send(new lib.ControllerRestartRequest()); + await ctl.send(new lib.ControllerRestartRequest()); } else { print("Plugin updated; a restart is required to apply the changes."); } @@ -193,10 +193,10 @@ controllerPluginCommands.add(new lib.Command({ yargs.positional("plugin", { describe: "Plugin to install", type: "string" }); yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); }], - handler: async function(args: { plugin: string, restart: boolean }, control: Control) { - await control.sendTo("controller", new lib.PluginInstallRequest(args.plugin)); + handler: async function(args: { plugin: string, restart: boolean }, ctl: Ctl) { + await ctl.sendTo("controller", new lib.PluginInstallRequest(args.plugin)); if (args.restart) { - await control.send(new lib.ControllerRestartRequest()); + await ctl.send(new lib.ControllerRestartRequest()); } else { print("Plugin installed; a restart is required to apply the changes."); } diff --git a/packages/ctl/src/commands_debug.ts b/packages/ctl/src/commands_debug.ts index c69e9298..c3dce44e 100644 --- a/packages/ctl/src/commands_debug.ts +++ b/packages/ctl/src/commands_debug.ts @@ -1,12 +1,12 @@ import * as lib from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; export const debugCommands = new lib.CommandTree({ name: "debug", description: "Debugging utilities" }); debugCommands.add(new lib.Command({ definition: ["dump-ws", "Dump WebSocket messages sent and received by controller"], - handler: async function(args: object, control: Control) { - await control.send(new lib.DebugDumpWsRequest()); - control.keepOpen = true; + handler: async function(args: object, ctl: Ctl) { + await ctl.send(new lib.DebugDumpWsRequest()); + ctl.keepOpen = true; }, })); @@ -18,7 +18,7 @@ debugCommands.add(new lib.Command({ yargs.positional("exchange-string", { describe: "String to parse", type: "string" }); yargs.option("pretty", { alias: "p", type: "boolean", description: "Pretty output" }); }], - handler: async function(args: { exchangeString: string, pretty: boolean }, control: Control) { + handler: async function(args: { exchangeString: string, pretty: boolean }, ctl: Ctl) { const result = lib.readMapExchangeString(args.exchangeString); if (args.pretty) { // eslint-disable-next-line no-console diff --git a/packages/ctl/src/commands_host.ts b/packages/ctl/src/commands_host.ts index fe408679..8661dbe2 100644 --- a/packages/ctl/src/commands_host.ts +++ b/packages/ctl/src/commands_host.ts @@ -6,7 +6,7 @@ import child_process from "child_process"; import * as lib from "@clusterio/lib"; import { logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; import { serializedConfigToString, getEditor, configToKeyVal } from "./config_ops.js"; @@ -17,9 +17,9 @@ hostCommands.add(new lib.Command({ definition: ["stop ", "Stop the given host", (yargs) => { yargs.positional("host", { describe: "Host to stop", type: "string" }); }], - handler: async function(args: { host: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - await control.sendTo({ hostId }, new lib.HostStopRequest()); + handler: async function(args: { host: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + await ctl.sendTo({ hostId }, new lib.HostStopRequest()); }, })); @@ -27,16 +27,16 @@ hostCommands.add(new lib.Command({ definition: ["restart ", "Restart the given host", (yargs) => { yargs.positional("host", { describe: "Host to restart", type: "string" }); }], - handler: async function(args: { host: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - await control.sendTo({ hostId }, new lib.HostRestartRequest()); + handler: async function(args: { host: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + await ctl.sendTo({ hostId }, new lib.HostRestartRequest()); }, })); hostCommands.add(new lib.Command({ definition: [["list", "l"], "List hosts connected to the controller"], - handler: async function(args: object, control: Control) { - let hosts = await control.send(new lib.HostListRequest()); + handler: async function(args: object, ctl: Ctl) { + let hosts = await ctl.send(new lib.HostListRequest()); print(asTable(hosts)); }, })); @@ -45,9 +45,9 @@ hostCommands.add(new lib.Command({ definition: ["generate-token", "Generate token for a host", (yargs) => { yargs.option("id", { type: "number", nargs: 1, describe: "Host id" }); }], - handler: async function(args: { id?: number }, control: Control) { + handler: async function(args: { id?: number }, ctl: Ctl) { let hostId = typeof args.id === "number" ? args.id : undefined; - let response = await control.send(new lib.HostGenerateTokenRequest(hostId)); + let response = await ctl.send(new lib.HostGenerateTokenRequest(hostId)); print(response); }, })); @@ -56,9 +56,9 @@ hostCommands.add(new lib.Command({ definition: ["revoke-token ", "Revoke all tokens for a host", (yargs) => { yargs.positional("host", { describe: "Host to revoke tokens for", type: "string" }); }], - handler: async function(args: { host: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - await control.send(new lib.HostRevokeTokensRequest(hostId)); + handler: async function(args: { host: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + await ctl.send(new lib.HostRevokeTokensRequest(hostId)); }, })); @@ -75,9 +75,9 @@ hostCommands.add(new lib.Command({ }], handler: async function( args: { id?: number, name?: string, generateToken: boolean, output: string }, - control: Control + ctl: Ctl ) { - let config = await control.send( + let config = await ctl.send( new lib.HostConfigCreateRequest(args.id, args.name, args.generateToken) ); @@ -103,15 +103,15 @@ hostCommands.add(new lib.Command({ yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); yargs.option("all", { alias: "a", type: "boolean", description: "Also update all plugins" }); }], - handler: async function(args: { host: string, restart: boolean, all: boolean }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); + handler: async function(args: { host: string, restart: boolean, all: boolean }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); if (args.all) { - await control.sendTo({ hostId }, new lib.UpdateAllRequest()); + await ctl.sendTo({ hostId }, new lib.UpdateAllRequest()); } else { - await control.sendTo({ hostId }, new lib.HostUpdateRequest()); + await ctl.sendTo({ hostId }, new lib.HostUpdateRequest()); } if (args.restart) { - await control.sendTo({ hostId }, new lib.HostRestartRequest()); + await ctl.sendTo({ hostId }, new lib.HostRestartRequest()); } else { print("Host updated; a restart is required to apply the changes."); } @@ -126,9 +126,9 @@ hostConfigCommands.add(new lib.Command({ definition: ["list ", "List configuration for a host", (yargs) => { yargs.positional("host", { describe: "Host to list config for", type: "string" }); }], - handler: async function(args: { host: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - let config = await control.sendTo({ hostId }, new lib.HostConfigGetRequest()); + handler: async function(args: { host: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + let config = await ctl.sendTo({ hostId }, new lib.HostConfigGetRequest()); for (let [name, value] of Object.entries(config)) { print(`${name} ${JSON.stringify(value)}`); @@ -147,15 +147,15 @@ hostConfigCommands.add(new lib.Command({ }], handler: async function( args: { host: string, field: string, value?: string, stdin?: boolean }, - control: Control, + ctl: Ctl, ) { - let hostId = await lib.resolveHost(control, args.host); + let hostId = await lib.resolveHost(ctl, args.host); if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } else if (args.value === undefined) { args.value = ""; } - await control.sendTo({ hostId }, new lib.HostConfigSetFieldRequest(args.field, args.value)); + await ctl.sendTo({ hostId }, new lib.HostConfigSetFieldRequest(args.field, args.value)); }, })); @@ -171,9 +171,9 @@ hostConfigCommands.add(new lib.Command({ }], handler: async function( args: { host: string, field: string, prop: string, value?: string, stdin?: boolean }, - control: Control + ctl: Ctl ) { - let hostId = await lib.resolveHost(control, args.host); + let hostId = await lib.resolveHost(ctl, args.host); if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } @@ -189,7 +189,7 @@ hostConfigCommands.add(new lib.Command({ } value = args.value; } - await control.sendTo({ hostId }, new lib.HostConfigSetPropRequest(args.field, args.prop, value)); + await ctl.sendTo({ hostId }, new lib.HostConfigSetPropRequest(args.field, args.prop, value)); }, })); @@ -202,9 +202,9 @@ hostConfigCommands.add(new lib.Command({ default: "", }); }], - handler: async function(args: { host: string, editor: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - let config = await control.sendTo({ hostId }, new lib.HostConfigGetRequest()); + handler: async function(args: { host: string, editor: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + let config = await ctl.sendTo({ hostId }, new lib.HostConfigGetRequest()); let tmpFile = await lib.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = await getEditor(args.editor); if (editor === undefined) { @@ -231,7 +231,7 @@ hostConfigCommands.add(new lib.Command({ for (let index in final) { if (index in final) { try { - await control.sendTo({ hostId }, new lib.HostConfigSetFieldRequest( + await ctl.sendTo({ hostId }, new lib.HostConfigSetFieldRequest( index, final[index], )); @@ -267,9 +267,9 @@ hostPluginCommands.add(new lib.Command({ definition: ["list ", "List plugins on a host", (yargs) => { yargs.positional("host", { describe: "Host to list for", type: "string" }); }], - handler: async function(args: { host: string }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - const plugins = await control.sendTo({ hostId }, new lib.PluginListRequest()); + handler: async function(args: { host: string }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + const plugins = await ctl.sendTo({ hostId }, new lib.PluginListRequest()); print(asTable(plugins.map(p => ({ title: p.title, version: p.version, loaded: p.loaded, enabled: p.enabled, npmPackage: p.npmPackage, })))); @@ -281,11 +281,11 @@ hostPluginCommands.add(new lib.Command({ yargs.positional("plugin", { describe: "Plugin to update", type: "string" }); yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); }], - handler: async function(args: { host: string, plugin: string, restart: boolean }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - await control.sendTo({ hostId }, new lib.PluginUpdateRequest(args.plugin)); + handler: async function(args: { host: string, plugin: string, restart: boolean }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + await ctl.sendTo({ hostId }, new lib.PluginUpdateRequest(args.plugin)); if (args.restart) { - await control.sendTo({ hostId }, new lib.HostRestartRequest()); + await ctl.sendTo({ hostId }, new lib.HostRestartRequest()); } else { print("Plugin updated; a restart is required to apply the changes."); } @@ -297,11 +297,11 @@ hostPluginCommands.add(new lib.Command({ yargs.positional("plugin", { describe: "Plugin to install", type: "string" }); yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" }); }], - handler: async function(args: { host: string, plugin: string, restart: boolean }, control: Control) { - let hostId = await lib.resolveHost(control, args.host); - await control.sendTo({ hostId }, new lib.PluginInstallRequest(args.plugin)); + handler: async function(args: { host: string, plugin: string, restart: boolean }, ctl: Ctl) { + let hostId = await lib.resolveHost(ctl, args.host); + await ctl.sendTo({ hostId }, new lib.PluginInstallRequest(args.plugin)); if (args.restart) { - await control.sendTo({ hostId }, new lib.HostRestartRequest()); + await ctl.sendTo({ hostId }, new lib.HostRestartRequest()); } else { print("Plugin installed; a restart is required to apply the changes."); } diff --git a/packages/ctl/src/commands_instance.ts b/packages/ctl/src/commands_instance.ts index 8451d56c..6a1f79ad 100644 --- a/packages/ctl/src/commands_instance.ts +++ b/packages/ctl/src/commands_instance.ts @@ -9,7 +9,7 @@ import util from "util"; import * as lib from "@clusterio/lib"; import { logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; import { serializedConfigToString, getEditor, configToKeyVal } from "./config_ops.js"; @@ -21,8 +21,8 @@ export const instanceCommands = new lib.CommandTree({ }); instanceCommands.add(new lib.Command({ definition: [["list", "l"], "List instances known to the controller"], - handler: async function(args: object, control: Control) { - let list = await control.send(new lib.InstanceDetailsListRequest()); + handler: async function(args: object, ctl: Ctl) { + let list = await ctl.send(new lib.InstanceDetailsListRequest()); print(asTable(list)); }, })); @@ -36,13 +36,13 @@ instanceCommands.add(new lib.Command({ "from": { type: "number", nargs: 1, describe: "Clone config from instance id" }, }); }], - handler: async function(args: { name: string, id?: number, from?: number, }, control: Control) { + handler: async function(args: { name: string, id?: number, from?: number, }, ctl: Ctl) { let instanceConfig = new lib.InstanceConfig("control"); if (args.id !== undefined) { instanceConfig.set("instance.id", args.id); } instanceConfig.set("instance.name", args.name); - await control.send(new lib.InstanceCreateRequest( + await ctl.send(new lib.InstanceCreateRequest( instanceConfig.toRemote("controller", [ "instance.id", "instance.name", ]), @@ -58,9 +58,9 @@ instanceConfigCommands.add(new lib.Command({ definition: ["list ", "List configuration for an instance", (yargs) => { yargs.positional("instance", { describe: "Instance to list config for", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - let config = await control.send(new lib.InstanceConfigGetRequest(instanceId)); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + let config = await ctl.send(new lib.InstanceConfigGetRequest(instanceId)); for (let [name, value] of Object.entries(config)) { print(`${name} ${JSON.stringify(value)}`); @@ -79,15 +79,15 @@ instanceConfigCommands.add(new lib.Command({ }], handler: async function( args: { instance: string, field: string, value?: string, stdin?: boolean }, - control: Control, + ctl: Ctl, ) { - let instanceId = await lib.resolveInstance(control, args.instance); + let instanceId = await lib.resolveInstance(ctl, args.instance); if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } else if (args.value === undefined) { args.value = ""; } - await control.send(new lib.InstanceConfigSetFieldRequest(instanceId, args.field, args.value)); + await ctl.send(new lib.InstanceConfigSetFieldRequest(instanceId, args.field, args.value)); }, })); @@ -103,9 +103,9 @@ instanceConfigCommands.add(new lib.Command({ }], handler: async function( args: { instance: string, field: string, prop: string, value?: string, stdin?: boolean }, - control: Control + ctl: Ctl ) { - let instanceId = await lib.resolveInstance(control, args.instance); + let instanceId = await lib.resolveInstance(ctl, args.instance); if (args.stdin) { args.value = (await lib.readStream(process.stdin)).toString().replace(/\r?\n$/, ""); } @@ -136,7 +136,7 @@ instanceConfigCommands.add(new lib.Command({ } value = args.value; } - await control.send(new lib.InstanceConfigSetPropRequest(instanceId, args.field, args.prop, value)); + await ctl.send(new lib.InstanceConfigSetPropRequest(instanceId, args.field, args.prop, value)); }, })); @@ -149,9 +149,9 @@ instanceConfigCommands.add(new lib.Command({ default: "", }); }], - handler: async function(args: { instance: string, editor: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - let config = await control.send(new lib.InstanceConfigGetRequest(instanceId)); + handler: async function(args: { instance: string, editor: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + let config = await ctl.send(new lib.InstanceConfigGetRequest(instanceId)); let tmpFile = await lib.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = await getEditor(args.editor); if (editor === undefined) { @@ -178,7 +178,7 @@ instanceConfigCommands.add(new lib.Command({ for (let index in final) { if (index in final) { try { - await control.send(new lib.InstanceConfigSetFieldRequest( + await ctl.send(new lib.InstanceConfigSetFieldRequest( instanceId, index, final[index], @@ -211,10 +211,10 @@ instanceCommands.add(new lib.Command({ yargs.positional("instance", { describe: "Instance to assign", type: "string" }); yargs.positional("host", { describe: "Host to assign to or unassign if none", type: "string" }); }], - handler: async function(args: { instance: string, host?: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - let hostId = args.host ? await lib.resolveHost(control, args.host) : undefined; - await control.send(new lib.InstanceAssignRequest(instanceId, hostId)); + handler: async function(args: { instance: string, host?: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + let hostId = args.host ? await lib.resolveHost(ctl, args.host) : undefined; + await ctl.send(new lib.InstanceAssignRequest(instanceId, hostId)); }, })); @@ -250,9 +250,9 @@ instanceSaveCommands.add(new lib.Command({ definition: ["list ", "list saves on an instance", (yargs) => { yargs.positional("instance", { describe: "Instance to list saves on", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - let saves = await control.sendTo("controller", new lib.InstanceSaveDetailsListRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + let saves = await ctl.sendTo("controller", new lib.InstanceSaveDetailsListRequest()); saves = saves.filter(save => save.instanceId === instanceId); print(asTable(saves.map( ({ mtimeMs, ...rest }) => ({ ...rest, mtime: new Date(mtimeMs).toLocaleString() }) @@ -280,12 +280,12 @@ instanceSaveCommands.add(new lib.Command({ mapGenSettings?: string, mapSettings?: string, }, - control: Control + ctl: Ctl ) { - let instanceId = await lib.resolveInstance(control, args.instance); + let instanceId = await lib.resolveInstance(ctl, args.instance); let { seed, mapGenSettings, mapSettings } = await loadMapSettings(args); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo( + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo( { instanceId }, new lib.InstanceCreateSaveRequest(args.name, seed, mapGenSettings, mapSettings), ); @@ -298,9 +298,9 @@ instanceSaveCommands.add(new lib.Command({ yargs.positional("old-name", { describe: "Old name of save.", type: "string" }); yargs.positional("new-name", { describe: "New name of save.", type: "string" }); }], - handler: async function(args: { instance: string, oldName: string, newName: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.send(new lib.InstanceRenameSaveRequest(instanceId, args.oldName, args.newName)); + handler: async function(args: { instance: string, oldName: string, newName: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.send(new lib.InstanceRenameSaveRequest(instanceId, args.oldName, args.newName)); }, })); @@ -310,9 +310,9 @@ instanceSaveCommands.add(new lib.Command({ yargs.positional("source", { describe: "Save to copy.", type: "string" }); yargs.positional("destination", { describe: "Name of copy.", type: "string" }); }], - handler: async function(args: { instance: string, source: string, destination: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.send(new lib.InstanceCopySaveRequest(instanceId, args.source, args.destination)); + handler: async function(args: { instance: string, source: string, destination: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.send(new lib.InstanceCopySaveRequest(instanceId, args.source, args.destination)); }, })); @@ -324,14 +324,14 @@ instanceSaveCommands.add(new lib.Command({ "name": { describe: "Name to give save on server", nargs: 1, type: "string" }, }); }], - handler: async function(args: { instance: string, filepath: string, name?: string }, control: Control) { + handler: async function(args: { instance: string, filepath: string, name?: string }, ctl: Ctl) { let filename = args.name || path.basename(args.filepath); if (!filename.endsWith(".zip")) { throw new lib.CommandError("Save name must end with .zip"); } - let instanceId = await lib.resolveInstance(control, args.instance); - let url = new URL(control.config.get("control.controller_url")!); + let instanceId = await lib.resolveInstance(ctl, args.instance); + let url = new URL(ctl.config.get("ctl.controller_url")!); url.pathname += "api/upload-save"; url.searchParams.append("instance_id", String(instanceId)); url.searchParams.append("filename", filename); @@ -341,7 +341,7 @@ instanceSaveCommands.add(new lib.Command({ body: (await fs.open(args.filepath)).createReadStream(), duplex: "half", headers: { - "X-Access-Token": control.config.get("control.controller_token")!, + "X-Access-Token": ctl.config.get("ctl.controller_token")!, "Content-Type": "application/zip", }, }); @@ -389,11 +389,11 @@ instanceSaveCommands.add(new lib.Command({ targetSave: string, copy: boolean, }, - control: Control + ctl: Ctl ) { - let sourceInstanceId = await lib.resolveInstance(control, args.sourceInstance); - let targetInstanceId = await lib.resolveInstance(control, args.targetInstance); - let storedName = await control.send( + let sourceInstanceId = await lib.resolveInstance(ctl, args.sourceInstance); + let targetInstanceId = await lib.resolveInstance(ctl, args.targetInstance); + let storedName = await ctl.send( new lib.InstanceTransferSaveRequest( sourceInstanceId, args.sourceSave, @@ -411,11 +411,11 @@ instanceSaveCommands.add(new lib.Command({ yargs.positional("instance", { describe: "Instance to download save from", type: "string" }); yargs.positional("save", { describe: "Save to download", type: "string" }); }], - handler: async function(args: { instance: string, save: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - let streamId = await control.send(new lib.InstanceDownloadSaveRequest(instanceId, args.save)); + handler: async function(args: { instance: string, save: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + let streamId = await ctl.send(new lib.InstanceDownloadSaveRequest(instanceId, args.save)); - let url = new URL(control.config.get("control.controller_url")!); + let url = new URL(ctl.config.get("ctl.controller_url")!); url.pathname += `api/stream/${streamId}`; const filename = await lib.downloadFile(url, args.save, "rename"); @@ -428,9 +428,9 @@ instanceSaveCommands.add(new lib.Command({ yargs.positional("instance", { describe: "Instance to delete save from", type: "string" }); yargs.positional("save", { describe: "Save to delete", type: "string" }); }], - handler: async function(args: { instance: string, save: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.send(new lib.InstanceDeleteSaveRequest(instanceId, args.save)); + handler: async function(args: { instance: string, save: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.send(new lib.InstanceDeleteSaveRequest(instanceId, args.save)); }, })); instanceCommands.add(instanceSaveCommands); @@ -439,10 +439,10 @@ instanceCommands.add(new lib.Command({ definition: ["export-data ", "Export item icons and locale from instance", (yargs) => { yargs.positional("instance", { describe: "Instance to export from", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceExportDataRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceExportDataRequest()); }, })); @@ -450,9 +450,9 @@ instanceCommands.add(new lib.Command({ definition: ["save-game ", "Save the running game of an instance", (yargs) => { yargs.positional("instance", { describe: "Instance to save the game on", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.sendTo({ instanceId }, new lib.InstanceSaveGameRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.sendTo({ instanceId }, new lib.InstanceSaveGameRequest()); }, })); @@ -460,10 +460,10 @@ instanceCommands.add(new lib.Command({ definition: ["extract-players ", "Extract players from running save into the cluster.", (yargs) => { yargs.positional("instance", { describe: "Instance to extract players and online time from", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceExtractPlayersRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceExtractPlayersRequest()); }, })); @@ -475,11 +475,11 @@ instanceCommands.add(new lib.Command({ "keep-open": { describe: "Keep console open", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { instance: string, save?: string, keepOpen: boolean }, control: Control) { - const instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceStartRequest(args.save)); - control.keepOpen = args.keepOpen; + handler: async function(args: { instance: string, save?: string, keepOpen: boolean }, ctl: Ctl) { + const instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceStartRequest(args.save)); + ctl.keepOpen = args.keepOpen; }, })); instanceCommands.add(new lib.Command({ @@ -490,11 +490,11 @@ instanceCommands.add(new lib.Command({ "keep-open": { describe: "Keep console open", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { instance: string, save?: string, keepOpen: boolean }, control: Control) { - const instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceRestartRequest(args.save)); - control.keepOpen = args.keepOpen; + handler: async function(args: { instance: string, save?: string, keepOpen: boolean }, ctl: Ctl) { + const instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceRestartRequest(args.save)); + ctl.keepOpen = args.keepOpen; }, })); @@ -509,9 +509,9 @@ instanceCommands.add(new lib.Command({ }, }); }], - handler: async function(args: { force: boolean }, control: Control) { + handler: async function(args: { force: boolean }, ctl: Ctl) { // Get all instances - const instances = await control.send(new lib.InstanceDetailsListRequest()); + const instances = await ctl.send(new lib.InstanceDetailsListRequest()); // Filter instances that should be started const instancesToStart = instances.filter((instance: lib.InstanceDetails) => { @@ -541,7 +541,7 @@ instanceCommands.add(new lib.Command({ // Start all filtered instances const startPromises = instancesToStart.map(async (instance: lib.InstanceDetails) => { try { - await control.sendTo({ instanceId: instance.id }, new lib.InstanceStartRequest()); + await ctl.sendTo({ instanceId: instance.id }, new lib.InstanceStartRequest()); print(`✓ Started ${instance.name}`); } catch (error) { print(`✗ Failed to start ${instance.name}: ${error}`); @@ -575,15 +575,15 @@ instanceCommands.add(new lib.Command({ mapSettings?: string, keepOpen: boolean, }, - control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); + ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); let { seed, mapGenSettings, mapSettings } = await loadMapSettings(args); - await control.sendTo( + await ctl.sendTo( { instanceId }, new lib.InstanceLoadScenarioRequest(args.scenario, seed, mapGenSettings, mapSettings), ); - control.keepOpen = args.keepOpen; + ctl.keepOpen = args.keepOpen; }, })); @@ -591,18 +591,18 @@ instanceCommands.add(new lib.Command({ definition: ["stop ", "Stop instance", (yargs) => { yargs.positional("instance", { describe: "Instance to stop", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceStopRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceStopRequest()); }, })); instanceCommands.add(new lib.Command({ definition: ["stop-all", "Stop all running instances", () => {}], - handler: async function(_args, control: Control) { + handler: async function(_args, ctl: Ctl) { // Get all instances - const instances = await control.send(new lib.InstanceDetailsListRequest()); + const instances = await ctl.send(new lib.InstanceDetailsListRequest()); // Filter instances that should be stopped const instancesToStop = instances @@ -621,7 +621,7 @@ instanceCommands.add(new lib.Command({ // Stop all filtered instances const stopPromises = instancesToStop.map(async (instance: lib.InstanceDetails) => { try { - await control.sendTo({ instanceId: instance.id }, new lib.InstanceStopRequest()); + await ctl.sendTo({ instanceId: instance.id }, new lib.InstanceStopRequest()); print(`✓ Stopped ${instance.name}`); } catch (error) { print(`✗ Failed to stop ${instance.name}: ${error}`); @@ -637,10 +637,10 @@ instanceCommands.add(new lib.Command({ definition: ["kill ", "Kill instance", (yargs) => { yargs.positional("instance", { describe: "Instance to kill", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.setLogSubscriptions({ instanceIds: [instanceId] }); - await control.sendTo({ instanceId }, new lib.InstanceKillRequest()); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.setLogSubscriptions({ instanceIds: [instanceId] }); + await ctl.sendTo({ instanceId }, new lib.InstanceKillRequest()); }, })); @@ -648,9 +648,9 @@ instanceCommands.add(new lib.Command({ definition: ["delete ", "Delete instance", (yargs) => { yargs.positional("instance", { describe: "Instance to delete", type: "string" }); }], - handler: async function(args: { instance: string }, control: Control) { - let instanceId = await lib.resolveInstance(control, args.instance); - await control.send(new lib.InstanceDeleteRequest(instanceId)); + handler: async function(args: { instance: string }, ctl: Ctl) { + let instanceId = await lib.resolveInstance(ctl, args.instance); + await ctl.send(new lib.InstanceDeleteRequest(instanceId)); }, })); @@ -659,9 +659,9 @@ instanceCommands.add(new lib.Command({ yargs.positional("instance", { describe: "Instance to send to", type: "string" }); yargs.positional("command", { describe: "command to send", type: "string" }); }], - handler: async function(args: { instance: string, command: string }, control: Control) { - let result = await control.sendTo( - { instanceId: await lib.resolveInstance(control, args.instance) }, + handler: async function(args: { instance: string, command: string }, ctl: Ctl) { + let result = await ctl.sendTo( + { instanceId: await lib.resolveInstance(ctl, args.instance) }, new lib.InstanceSendRconRequest(args.command), ); diff --git a/packages/ctl/src/commands_log.ts b/packages/ctl/src/commands_log.ts index 4cce13a3..967f2393 100644 --- a/packages/ctl/src/commands_log.ts +++ b/packages/ctl/src/commands_log.ts @@ -2,7 +2,7 @@ import winston from "winston"; import * as lib from "@clusterio/lib"; import { ConsoleTransport, levels, logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; export const logCommands = new lib.CommandTree({ name: "log", description: "Log inspection" }); logCommands.add(new lib.Command({ @@ -16,17 +16,17 @@ logCommands.add(new lib.Command({ }], handler: async function( args: { all: boolean, controller: boolean, host: string | null, instance: string | null }, - control: Control + ctl: Ctl ) { if (!args.all && !args.controller && !args.host && !args.instance) { logger.error("At least one of --all, --controller, --host and --instance must be passed"); process.exitCode = 1; return; } - let instanceIds = args.instance ? [await lib.resolveInstance(control, args.instance)] : []; - let hostIds = args.host ? [await lib.resolveHost(control, args.host)] : []; - await control.setLogSubscriptions({ all: args.all, controller: args.controller, hostIds, instanceIds }); - control.keepOpen = true; + let instanceIds = args.instance ? [await lib.resolveInstance(ctl, args.instance)] : []; + let hostIds = args.host ? [await lib.resolveHost(ctl, args.host)] : []; + await ctl.setLogSubscriptions({ all: args.all, controller: args.controller, hostIds, instanceIds }); + ctl.keepOpen = true; }, })); @@ -52,16 +52,16 @@ logCommands.add(new lib.Command({ limit: number, start: boolean, }, - control: Control + ctl: Ctl ) { if (!args.all && !args.controller && !args.host && !args.instance) { logger.error("At least one of --all, --controller, --host and --instance must be passed"); process.exitCode = 1; return; } - let instanceIds = args.instance ? [await lib.resolveInstance(control, args.instance)] : []; - let hostIds = args.host ? [await lib.resolveHost(control, args.host)] : []; - let result = await control.send(new lib.LogQueryRequest( + let instanceIds = args.instance ? [await lib.resolveInstance(ctl, args.instance)] : []; + let hostIds = args.host ? [await lib.resolveHost(ctl, args.host)] : []; + let result = await ctl.send(new lib.LogQueryRequest( args.all, args.controller, hostIds, diff --git a/packages/ctl/src/commands_mod.ts b/packages/ctl/src/commands_mod.ts index 778ead86..3eda61d0 100644 --- a/packages/ctl/src/commands_mod.ts +++ b/packages/ctl/src/commands_mod.ts @@ -7,7 +7,7 @@ import util from "util"; import * as lib from "@clusterio/lib"; import { logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; const asTable = asTableModule.configure({ delimiter: " | " }); @@ -19,11 +19,11 @@ modCommands.add(new lib.Command({ yargs.positional("name", { describe: "Mod name to show details for", type: "string" }); yargs.positional("mod-version", { describe: "Version of the mod", type: "string" }); }], - handler: async function(args: { name: string, modVersion: string }, control: Control) { + handler: async function(args: { name: string, modVersion: string }, ctl: Ctl) { if (!lib.isSourceVersion(args.modVersion)) { throw new lib.CommandError("mod-version must match format digit.digit.digit"); } - let modInfo = await control.send(new lib.ModGetRequest(args.name, args.modVersion)); + let modInfo = await ctl.send(new lib.ModGetRequest(args.name, args.modVersion)); for (let [field, value] of Object.entries(modInfo)) { if (value instanceof Array) { print(`${field}:`); @@ -48,8 +48,8 @@ modCommands.add(new lib.Command({ }, }); }], - handler: async function(args: { fields: string[] }, control: Control) { - let mods = await control.send(new lib.ModListRequest()); + handler: async function(args: { fields: string[] }, ctl: Ctl) { + let mods = await ctl.send(new lib.ModListRequest()); if (!args.fields.includes("all")) { for (let entry of mods) { for (let field of Object.keys(entry)) { @@ -106,13 +106,13 @@ modCommands.add(new lib.Command({ sortOrder: "asc" | "desc", fields: string[], }, - control: Control + ctl: Ctl ) { const searchVersion = lib.normaliseSourceVersion(String(args.factorioVersion)); if (searchVersion === undefined) { throw new Error(`Invalid factorio version "${args.factorioVersion}"`); } - let response = await control.send(new lib.ModSearchRequest( + let response = await ctl.send(new lib.ModSearchRequest( args.query, lib.normaliseMajorMinorVersion(searchVersion), args.page, @@ -143,13 +143,13 @@ modCommands.add(new lib.Command({ definition: ["upload ", "Upload mod to the cluster", (yargs) => { yargs.positional("file", { describe: "File to upload", type: "string" }); }], - handler: async function(args: { file: string }, control: Control) { + handler: async function(args: { file: string }, ctl: Ctl) { let filename = path.basename(args.file); if (!filename.endsWith(".zip")) { throw new lib.CommandError("Mod filename must end with .zip"); } - let url = new URL(control.config.get("control.controller_url")!); + let url = new URL(ctl.config.get("ctl.controller_url")!); url.pathname += "api/upload-mod"; url.searchParams.append("filename", filename); @@ -158,7 +158,7 @@ modCommands.add(new lib.Command({ body: (await fs.open(args.file)).createReadStream(), duplex: "half", headers: { - "X-Access-Token": control.config.get("control.controller_token")!, + "X-Access-Token": ctl.config.get("ctl.controller_token")!, "Content-Type": "application/zip", }, }); @@ -190,13 +190,13 @@ modCommands.add(new lib.Command({ yargs.positional("name", { describe: "Internal name of mod to download", type: "string" }); yargs.positional("mod-version", { describe: "Version of mod to download", type: "string" }); }], - handler: async function(args: { name: string, modVersion: string }, control: Control) { + handler: async function(args: { name: string, modVersion: string }, ctl: Ctl) { if (!lib.isSourceVersion(args.modVersion)) { throw new lib.CommandError("mod-version must match format digit.digit.digit"); } - let streamId = await control.send(new lib.ModDownloadRequest(args.name, args.modVersion)); + let streamId = await ctl.send(new lib.ModDownloadRequest(args.name, args.modVersion)); - let url = new URL(control.config.get("control.controller_url")!); + let url = new URL(ctl.config.get("ctl.controller_url")!); url.pathname += `api/stream/${streamId}`; let filename = `${args.name}_${args.modVersion}.zip`; await lib.downloadFile(url, filename, "overwrite"); @@ -210,10 +210,10 @@ modCommands.add(new lib.Command({ yargs.positional("name", { describe: "Name of mod to delete", type: "string" }); yargs.positional("mod-version", { describe: "Version of mod to delete", type: "string" }); }], - handler: async function(args: { name: string, modVersion: string }, control: Control) { + handler: async function(args: { name: string, modVersion: string }, ctl: Ctl) { if (!lib.isSourceVersion(args.modVersion)) { throw new lib.CommandError("mod-version must match format digit.digit.digit"); } - await control.send(new lib.ModDeleteRequest(args.name, args.modVersion)); + await ctl.send(new lib.ModDeleteRequest(args.name, args.modVersion)); }, })); diff --git a/packages/ctl/src/commands_mod_pack.ts b/packages/ctl/src/commands_mod_pack.ts index 6c88679f..690b6e9e 100644 --- a/packages/ctl/src/commands_mod_pack.ts +++ b/packages/ctl/src/commands_mod_pack.ts @@ -2,7 +2,7 @@ import asTableModule from "as-table"; import * as lib from "@clusterio/lib"; import { logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; const asTable = asTableModule.configure({ delimiter: " | " }); @@ -12,12 +12,12 @@ modPackCommands.add(new lib.Command({ definition: ["show ", "Show details of mod pack", (yargs) => { yargs.positional("mod-pack", { describe: "Mod pack to show", type: "string" }); }], - handler: async function(args: { modPack: string }, control: Control) { + handler: async function(args: { modPack: string }, ctl: Ctl) { let mods = new Map( - (await control.send(new lib.ModListRequest())).map(m => [m.id, m]) + (await ctl.send(new lib.ModListRequest())).map(m => [m.id, m]) ); - let modPack = await control.send( - new lib.ModPackGetRequest(await lib.resolveModPack(control, args.modPack)) + let modPack = await ctl.send( + new lib.ModPackGetRequest(await lib.resolveModPack(ctl, args.modPack)) ); for (let [field, value] of Object.entries(modPack)) { @@ -57,8 +57,8 @@ modPackCommands.add(new lib.Command({ modPackCommands.add(new lib.Command({ definition: [["list", "l"], "List mod packs in the cluster"], - handler: async function(args: object, control: Control) { - let modPacks = await control.send(new lib.ModPackListRequest()); + handler: async function(args: object, ctl: Ctl) { + let modPacks = await ctl.send(new lib.ModPackListRequest()); let fields = ["id", "name", "factorioVersion"]; for (let entry of modPacks) { for (let field of Object.keys(entry)) { @@ -179,7 +179,7 @@ modPackCommands.add(new lib.Command({ stringSetting?: string[], colorSetting?: string[], }, - control: Control, + ctl: Ctl, ) { const modPack = new lib.ModPack(); modPack.name = args.name; @@ -193,7 +193,7 @@ modPackCommands.add(new lib.Command({ setModPackMods(modPack, args.mods); setModPackModsEnabled(modPack, args.disabledMods, false); setModPackSettings(modPack, args); - await control.send(new lib.ModPackCreateRequest(modPack)); + await ctl.send(new lib.ModPackCreateRequest(modPack)); print(`Created mod pack ${modPack.name} (${modPack.id})`); }, })); @@ -202,9 +202,9 @@ modPackCommands.add(new lib.Command({ definition: ["import ", "Import mod pack string", (yargs) => { yargs.positional("string", { describe: "Mod pack string to import", type: "string" }); }], - handler: async function(args: { string: string }, control: Control) { + handler: async function(args: { string: string }, ctl: Ctl) { const modPack = lib.ModPack.fromModPackString(args.string); - await control.send(new lib.ModPackCreateRequest(modPack)); + await ctl.send(new lib.ModPackCreateRequest(modPack)); print(`Created mod pack ${modPack.name} (${modPack.id})`); }, })); @@ -213,9 +213,9 @@ modPackCommands.add(new lib.Command({ definition: ["export ", "Export mod pack string", (yargs) => { yargs.positional("string", { describe: "Mod pack to export", type: "string" }); }], - handler: async function(args: { modPack: string }, control: Control) { - const modPack = await control.send( - new lib.ModPackGetRequest(await lib.resolveModPack(control, args.modPack)) + handler: async function(args: { modPack: string }, ctl: Ctl) { + const modPack = await ctl.send( + new lib.ModPackGetRequest(await lib.resolveModPack(ctl, args.modPack)) ); print(modPack.toModPackString()); }, @@ -257,10 +257,10 @@ modPackCommands.add(new lib.Command({ colorSetting?: string[], removeSetting?: string[], }, - control: Control, + ctl: Ctl, ) { - const modPack = await control.send( - new lib.ModPackGetRequest(await lib.resolveModPack(control, args.modPack)) + const modPack = await ctl.send( + new lib.ModPackGetRequest(await lib.resolveModPack(ctl, args.modPack)) ); if (args.name) { modPack.name = args.name; } @@ -300,7 +300,7 @@ modPackCommands.add(new lib.Command({ } } } - await control.send(new lib.ModPackUpdateRequest(modPack)); + await ctl.send(new lib.ModPackUpdateRequest(modPack)); }, })); @@ -308,8 +308,8 @@ modPackCommands.add(new lib.Command({ definition: ["delete ", "Delete mod pack", (yargs) => { yargs.positional("mod-pack", { describe: "Mod pack to delete", type: "string" }); }], - handler: async function(args: { modPack: string }, control: Control) { - const id = await lib.resolveModPack(control, args.modPack); - await control.send(new lib.ModPackDeleteRequest(id)); + handler: async function(args: { modPack: string }, ctl: Ctl) { + const id = await lib.resolveModPack(ctl, args.modPack); + await ctl.send(new lib.ModPackDeleteRequest(id)); }, })); diff --git a/packages/ctl/src/commands_permission.ts b/packages/ctl/src/commands_permission.ts index 0094314b..6e6dc691 100644 --- a/packages/ctl/src/commands_permission.ts +++ b/packages/ctl/src/commands_permission.ts @@ -1,7 +1,7 @@ import asTableModule from "as-table"; import * as lib from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; const asTable = asTableModule.configure({ delimiter: " | " }); @@ -9,8 +9,8 @@ const asTable = asTableModule.configure({ delimiter: " | " }); export const permissionCommands = new lib.CommandTree({ name: "permission", description: "Permission inspection" }); permissionCommands.add(new lib.Command({ definition: [["list", "l"], "List permissions in the cluster"], - handler: async function(args: object, control: Control) { - let permissions = await control.send(new lib.PermissionListRequest()); + handler: async function(args: object, ctl: Ctl) { + let permissions = await ctl.send(new lib.PermissionListRequest()); print(asTable(permissions)); }, })); diff --git a/packages/ctl/src/commands_role.ts b/packages/ctl/src/commands_role.ts index e1707255..2b6a42cd 100644 --- a/packages/ctl/src/commands_role.ts +++ b/packages/ctl/src/commands_role.ts @@ -2,7 +2,7 @@ import asTableModule from "as-table"; import * as lib from "@clusterio/lib"; import { logger } from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; const asTable = asTableModule.configure({ delimiter: " | " }); @@ -10,8 +10,8 @@ const asTable = asTableModule.configure({ delimiter: " | " }); export const roleCommands = new lib.CommandTree({ name: "role", description: "Role management" }); roleCommands.add(new lib.Command({ definition: [["list", "l"], "List roles in the cluster"], - handler: async function(args: object, control: Control) { - let roles = await control.send(new lib.RoleListRequest()); + handler: async function(args: object, ctl: Ctl) { + let roles = await ctl.send(new lib.RoleListRequest()); print(asTable(roles)); }, })); @@ -24,8 +24,8 @@ roleCommands.add(new lib.Command({ "permissions": { describe: "Permissions role grants", nargs: 1, array: true, type: "string", default: [] }, }); }], - handler: async function(args: { name: string, description: string, permissions: string[] }, control: Control) { - let id = await control.send(new lib.RoleCreateRequest( + handler: async function(args: { name: string, description: string, permissions: string[] }, ctl: Ctl) { + let id = await ctl.send(new lib.RoleCreateRequest( args.name, args.description, args.permissions, @@ -58,9 +58,9 @@ roleCommands.add(new lib.Command({ removePerms?: string[], grantDefault?: boolean, }, - control: Control + ctl: Ctl ) { - let role = await lib.retrieveRole(control, args.role); + let role = await lib.retrieveRole(ctl, args.role); if (args.name !== undefined) { role.name = args.name; @@ -81,10 +81,10 @@ roleCommands.add(new lib.Command({ if (args.setPerms !== undefined) { role.permissions = new Set(args.setPerms); } - await control.send(new lib.RoleUpdateRequest(role.id, role.name, role.description, [...role.permissions])); + await ctl.send(new lib.RoleUpdateRequest(role.id, role.name, role.description, [...role.permissions])); if (args.grantDefault) { - await control.send(new lib.RoleGrantDefaultPermissionsRequest(role.id)); + await ctl.send(new lib.RoleGrantDefaultPermissionsRequest(role.id)); } }, })); @@ -93,8 +93,8 @@ roleCommands.add(new lib.Command({ definition: ["delete ", "Delete role", (yargs) => { yargs.positional("role", { describe: "Role to delete", type: "string" }); }], - handler: async function(args: { role: string }, control: Control) { - let role = await lib.retrieveRole(control, args.role); - await control.send(new lib.RoleDeleteRequest(role.id)); + handler: async function(args: { role: string }, ctl: Ctl) { + let role = await lib.retrieveRole(ctl, args.role); + await ctl.send(new lib.RoleDeleteRequest(role.id)); }, })); diff --git a/packages/ctl/src/commands_user.ts b/packages/ctl/src/commands_user.ts index 1f8817f6..6df05c22 100644 --- a/packages/ctl/src/commands_user.ts +++ b/packages/ctl/src/commands_user.ts @@ -3,7 +3,7 @@ import asTableModule from "as-table"; import path from "path"; import * as lib from "@clusterio/lib"; -import type { Control } from "../ctl.js"; +import type { Ctl } from "../ctl.js"; import { print } from "./command_ops.js"; const asTable = asTableModule.configure({ delimiter: " | " }); @@ -16,8 +16,8 @@ userCommands.add(new lib.Command({ "instance-stats": { describe: "include per-instance stats", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { name: string, instanceStats: boolean }, control: Control) { - let user = await control.send(new lib.UserGetRequest(args.name)); + handler: async function(args: { name: string, instanceStats: boolean }, ctl: Ctl) { + let user = await ctl.send(new lib.UserGetRequest(args.name)); Object.assign(user, user.playerStats); // @ts-expect-error Terrible hack delete user.playerStats; @@ -27,7 +27,7 @@ userCommands.add(new lib.Command({ print(asTable(Object.entries(user).map(([property, value]) => ({ property, value })))); if (args.instanceStats) { - let instances = await control.send(new lib.InstanceDetailsListRequest()); + let instances = await ctl.send(new lib.InstanceDetailsListRequest()); function instanceName(id: number) { let instance = instances.find(i => i.id === id); if (instance) { @@ -51,8 +51,8 @@ userCommands.add(new lib.Command({ "attributes": { describe: "include admin/whitelisted/banned", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { stats: boolean, attributes: boolean }, control: Control) { - let users = await control.send(new lib.UserListRequest()); + handler: async function(args: { stats: boolean, attributes: boolean }, ctl: Ctl) { + let users = await ctl.send(new lib.UserListRequest()); for (let user of users) { if (args.stats) { Object.assign(user, user.playerStats); @@ -82,8 +82,8 @@ userCommands.add(new lib.Command({ definition: ["create ", "Create a user", (yargs) => { yargs.positional("name", { describe: "Name of user to create", type: "string" }); }], - handler: async function(args: { name: string }, control: Control) { - await control.send(new lib.UserCreateRequest(args.name)); + handler: async function(args: { name: string }, ctl: Ctl) { + await ctl.send(new lib.UserCreateRequest(args.name)); }, })); @@ -91,8 +91,8 @@ userCommands.add(new lib.Command({ definition: ["revoke-token ", "Revoke token for user", (yargs) => { yargs.positional("name", { describe: "Name of user to revoke token for", type: "string" }); }], - handler: async function(args: { name: string }, control: Control) { - await control.send(new lib.UserRevokeTokenRequest(args.name)); + handler: async function(args: { name: string }, ctl: Ctl) { + await ctl.send(new lib.UserRevokeTokenRequest(args.name)); }, })); @@ -104,8 +104,8 @@ userCommands.add(new lib.Command({ "create": { describe: "Create user if it does not exist", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { user: string, revoke: boolean, create: boolean }, control: Control) { - await control.send(new lib.UserSetAdminRequest(args.user, args.create, !args.revoke)); + handler: async function(args: { user: string, revoke: boolean, create: boolean }, ctl: Ctl) { + await ctl.send(new lib.UserSetAdminRequest(args.user, args.create, !args.revoke)); }, })); @@ -117,8 +117,8 @@ userCommands.add(new lib.Command({ "create": { describe: "Create user if it does not exist", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: { user: string, remove: boolean, create: boolean }, control: Control) { - await control.send(new lib.UserSetWhitelistedRequest(args.user, args.create, !args.remove)); + handler: async function(args: { user: string, remove: boolean, create: boolean }, ctl: Ctl) { + await ctl.send(new lib.UserSetWhitelistedRequest(args.user, args.create, !args.remove)); }, })); @@ -138,9 +138,9 @@ userCommands.add(new lib.Command({ reason: string, create: boolean }, - control: Control + ctl: Ctl ) { - await control.send(new lib.UserSetBannedRequest(args.user, args.create, !args.pardon, args.reason)); + await ctl.send(new lib.UserSetBannedRequest(args.user, args.create, !args.pardon, args.reason)); }, })); @@ -149,8 +149,8 @@ userCommands.add(new lib.Command({ yargs.positional("user", { describe: "Name of user to change roles for", type: "string" }); yargs.positional("roles", { describe: "roles to assign", type: "string" }); }], - handler: async function(args: { user: string, roles: string[] }, control: Control) { - let roles = await control.send(new lib.RoleListRequest()); + handler: async function(args: { user: string, roles: string[] }, ctl: Ctl) { + let roles = await ctl.send(new lib.RoleListRequest()); let resolvedRoles = []; for (let roleName of args.roles) { @@ -174,7 +174,7 @@ userCommands.add(new lib.Command({ } } - await control.send(new lib.UserUpdateRolesRequest(args.user, resolvedRoles)); + await ctl.send(new lib.UserUpdateRolesRequest(args.user, resolvedRoles)); }, })); @@ -182,8 +182,8 @@ userCommands.add(new lib.Command({ definition: ["delete ", "Delete user", (yargs) => { yargs.positional("user", { describe: "Name of user to delete", type: "string" }); }], - handler: async function(args: { user: string }, control: Control) { - await control.send(new lib.UserDeleteRequest(args.user)); + handler: async function(args: { user: string }, ctl: Ctl) { + await ctl.send(new lib.UserDeleteRequest(args.user)); }, })); @@ -194,7 +194,7 @@ async function handleImportOrRestore(args: { admins: boolean, whitelist: boolean, noBackup?: boolean, -}, control: Control, restore: boolean) { +}, ctl: Ctl, restore: boolean) { let importType: ConstructorParameters[0]; const data = JSON.parse((await fs.readFile(args.filepath)).toString()); const optionCount = [args.users, args.bans, args.admins, args.whitelist] @@ -218,7 +218,7 @@ async function handleImportOrRestore(args: { throw new lib.CommandError("Unknown json file, please specify an option"); } - const backup = await control.send( + const backup = await ctl.send( new lib.UserBulkImportRequest(importType, importType === "users" ? data.users : data, restore) ); @@ -239,8 +239,8 @@ userCommands.add(new lib.Command({ "whitelist": { describe: "Import whitelist json", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: any, control: any) { - await handleImportOrRestore(args, control, false); + handler: async function(args: any, ctl: any) { + await handleImportOrRestore(args, ctl, false); }, })); @@ -255,8 +255,8 @@ userCommands.add(new lib.Command({ "no-backup": { describe: "Don't save a backup to the cwd", nargs: 0, type: "boolean", default: false }, }); }], - handler: async function(args: any, control: any) { - await handleImportOrRestore(args, control, true); + handler: async function(args: any, ctl: any) { + await handleImportOrRestore(args, ctl, true); }, })); @@ -276,7 +276,7 @@ userCommands.add(new lib.Command({ bans: boolean, admins: boolean, whitelist: boolean, - }, control: Control) { + }, ctl: Ctl) { let exportType = "users" as ConstructorParameters[0]; const optionCount = [args.bans, args.admins, args.whitelist] .reduce((acc, bool) => (bool ? acc + 1 : acc), 0); @@ -296,7 +296,7 @@ userCommands.add(new lib.Command({ exportType = "whitelist"; } - await fs.writeFile(args.filepath, JSON.stringify(await control.send( + await fs.writeFile(args.filepath, JSON.stringify(await ctl.send( new lib.UserBulkExportRequest(exportType) ), undefined, "\t")); print(`Exported ${exportType} to ${args.filepath}`); diff --git a/packages/lib/src/command.ts b/packages/lib/src/command.ts index 556a104e..c4e6ce1d 100644 --- a/packages/lib/src/command.ts +++ b/packages/lib/src/command.ts @@ -11,7 +11,7 @@ import * as libErrors from "./errors.js"; import type { Link } from "./link/index.js"; import type { Argv } from "yargs"; -export type CommandHandler = (args: any, control: any) => Promise; +export type CommandHandler = (args: any, ctl: any) => Promise; export type CommandDefinition = [string | string[], string?, ((yargs: Argv) => void)?]; /** @@ -34,7 +34,7 @@ export class Command { * @param cmd.handler - * Async function invoked when the command is executed. Is given * the parsed args and a reference to the {@link - * module:ctl/ctl.Control} instance. + * module:ctl/ctl.Ctl} instance. */ constructor({ definition, handler }: { definition: CommandDefinition, handler: CommandHandler }) { if (definition[0] instanceof Array) { @@ -52,8 +52,8 @@ export class Command { yargs.command(...this._definition); } - async run(args: Record, control: Link) { - await this._handler(args, control); + async run(args: Record, ctl: Link) { + await this._handler(args, ctl); } } @@ -62,7 +62,7 @@ export class Command { * * Container which can contain {@link module:lib.Command}s and other * CommandTrees. This is used by clusterioctl to hold the full tree of - * available commands, you may extend this tree by using a control plugin, + * available commands, you may extend this tree by using a ctl plugin, * see {@link module:lib.BaseControlPlugin#addCommands} */ export class CommandTree { diff --git a/packages/lib/src/config/definitions.ts b/packages/lib/src/config/definitions.ts index 0f109141..27042c44 100644 --- a/packages/lib/src/config/definitions.ts +++ b/packages/lib/src/config/definitions.ts @@ -691,32 +691,32 @@ export class InstanceConfig extends classes.Config { }; } -export interface ControlConfigFields { - "control.controller_url": string | null; - "control.controller_token": string | null; - "control.max_reconnect_delay": number; +export interface CtlConfigFields { + "ctl.controller_url": string | null; + "ctl.controller_token": string | null; + "ctl.max_reconnect_delay": number; } /** - * Control config class + * Ctl config class * @extends classes.Config */ -export class ControlConfig extends classes.Config { - declare static fromJSON: configFromJSON; - declare static fromFile: configFromFile; - static fieldDefinitions: classes.ConfigDefs = { - "control.controller_url": { +export class CtlConfig extends classes.Config { + declare static fromJSON: configFromJSON; + declare static fromFile: configFromFile; + static fieldDefinitions: classes.ConfigDefs = { + "ctl.controller_url": { description: "URL to connect to the controller at", type: "string", optional: true, }, - "control.controller_token": { + "ctl.controller_token": { access: ["control"], description: "Token to authenticate to controller with.", type: "string", optional: true, }, - "control.max_reconnect_delay": { + "ctl.max_reconnect_delay": { title: "Max Reconnect Delay", description: "Maximum delay to wait before attempting to reconnect WebSocket", type: "number", diff --git a/packages/lib/src/plugin.ts b/packages/lib/src/plugin.ts index d1cfd359..1a00eb2f 100644 --- a/packages/lib/src/plugin.ts +++ b/packages/lib/src/plugin.ts @@ -31,7 +31,7 @@ export type PluginDeclaration = { ctlEntrypoint?: string; webEntrypoint?: string; - controlConfigFields?: Record; + ctlConfigFields?: Record; features?: (typeof PluginFeatureFlags)[number][]; @@ -53,7 +53,7 @@ export function pluginNeedsWebBuild(info: PluginDeclaration) { || info.controllerConfigFields || info.hostConfigFields || info.instanceConfigFields - || info.controlConfigFields + || info.ctlConfigFields ); } diff --git a/packages/web_ui/src/components/SiteLayout.tsx b/packages/web_ui/src/components/SiteLayout.tsx index 0cbfa7c2..03e183e3 100644 --- a/packages/web_ui/src/components/SiteLayout.tsx +++ b/packages/web_ui/src/components/SiteLayout.tsx @@ -16,7 +16,7 @@ import { DraggingContext } from "../model/is_dragging"; import webUiPackage from "../../package.json"; import logo from "../images/logo.png"; -import { ControlConfig } from "@clusterio/lib"; +import { CtlConfig } from "@clusterio/lib"; type MenuItem = Required["items"][number]; @@ -77,11 +77,11 @@ export default function SiteLayout() { if (key === "user") { navigate(`/users/${account.name}/view`); } else if (key === "ctlConfig") { - const config = new ControlConfig("control", { - "control.controller_token": control.connector.token, - "control.controller_url": (new URL(webRoot, document.location.href)).href, + const config = new CtlConfig("control", { + "ctl.controller_token": control.connector.token, + "ctl.controller_url": (new URL(webRoot, document.location.href)).href, }); - saveJson("config-control.json", config.toJSON()); + saveJson("config-ctl.json", config.toJSON()); } else if (key === "about") { setAboutOpen(true); } else if (key === "logOut") { diff --git a/plugins/global_chat/control.ts b/plugins/global_chat/ctl.ts similarity index 83% rename from plugins/global_chat/control.ts rename to plugins/global_chat/ctl.ts index ff4f5068..cbb0bbca 100644 --- a/plugins/global_chat/control.ts +++ b/plugins/global_chat/ctl.ts @@ -9,8 +9,8 @@ globalChatCommands.add(new Command({ definition: ["shout ", "Send message to all instances", (yargs) => { yargs.positional("message", { describe: "message to send", type: "string" }); }], - handler: async function(args, control) { - await control.sendTo("allInstances", new ChatEvent("Console", args.message)); + handler: async function(args, ctl) { + await ctl.sendTo("allInstances", new ChatEvent("Console", args.message)); }, })); diff --git a/plugins/global_chat/index.ts b/plugins/global_chat/index.ts index dee12820..43dff7bf 100644 --- a/plugins/global_chat/index.ts +++ b/plugins/global_chat/index.ts @@ -7,7 +7,7 @@ export const plugin: lib.PluginDeclaration = { title: "Global Chat", description: "Forwards chat between instances.", instanceEntrypoint: "dist/node/instance.js", - ctlEntrypoint: "dist/node/control.js", + ctlEntrypoint: "dist/node/ctl.js", features: [ "ScriptCommands", diff --git a/test/file/test_plugin/control.js b/test/file/test_plugin/ctl.js similarity index 93% rename from test/file/test_plugin/control.js rename to test/file/test_plugin/ctl.js index 6f903c05..caa09025 100644 --- a/test/file/test_plugin/control.js +++ b/test/file/test_plugin/ctl.js @@ -8,7 +8,7 @@ testPluginCommands.add(new Command({ definition: ["echo ", "Print the message given to it", (yargs) => { yargs.positional("message", { describe: "message to print", type: "string" }); }], - handler: async function(args, control) { + handler: async function(args, ctl) { // eslint-disable-next-line no-console console.log(args.message); }, diff --git a/test/file/test_plugin/index.js b/test/file/test_plugin/index.js index de9f64e2..437d6172 100644 --- a/test/file/test_plugin/index.js +++ b/test/file/test_plugin/index.js @@ -11,7 +11,7 @@ export const plugin = { controllerEntrypoint: "controller.js", hostEntrypoint: "host.js", instanceEntrypoint: "instance.js", - ctlEntrypoint: "control.js", + ctlEntrypoint: "ctl.js", messages: [ ControllerEcho, diff --git a/test/integration/index.js b/test/integration/index.js index a1730c22..9f3345e0 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -200,7 +200,7 @@ export let factorioDir = getFactorioDir(baseHostConfig); let pluginListPath = path.join("temp", "test", "plugin-list.json"); export let controllerConfigPath = path.join("temp", "test", "config-controller.json"); export let hostConfigPath = path.join("temp", "test", "config-host.json"); -export let controlConfigPath = path.join("temp", "test", "config-control.json"); +export let ctlConfigPath = path.join("temp", "test", "config-ctl.json"); function childOptions(options) { return { @@ -241,7 +241,7 @@ export async function execCtl(command) { return; } - control.config = initArgs.controlConfig; + control.config = initArgs.ctlConfig; const targetCommand = selectTargetCommand(initArgs.args, initArgs.rootCommands); await targetCommand.run(initArgs.args, control); } finally { @@ -340,7 +340,7 @@ before(async function() { await fs.rm(pluginListPath, { force: true }); await fs.rm(controllerConfigPath, { force: true }); await fs.rm(hostConfigPath, { force: true }); - await fs.rm(controlConfigPath, { force: true }); + await fs.rm(ctlConfigPath, { force: true }); await fs.mkdir(path.join("temp", "test"), { recursive: true }); @@ -394,8 +394,8 @@ before(async function() { control = new TestControl(controlConnector); await controlConnector.connect(); - const initArgs = await initializeCtl(`--plugin-list ${pluginListPath} control-config list`, undefined, true); - control.config = initArgs.controlConfig; + const initArgs = await initializeCtl(`--plugin-list ${pluginListPath} config list`, undefined, true); + control.config = initArgs.ctlConfig; control.hooks = initArgs.ctlHooks; const testPack = lib.ModPack.fromJSON({}); diff --git a/test/lib/config/migrations.js b/test/lib/config/migrations.js index 26dc6b03..f93a10fd 100644 --- a/test/lib/config/migrations.js +++ b/test/lib/config/migrations.js @@ -42,7 +42,7 @@ describe("lib/config/definitions/migrations", function() { assert.equal(configFalse.get("factorio.sync_banlist"), "disabled", "sync_adminlist contains wrong value"); }); }); - describe("Control Config", function() { + describe("Ctl Config", function() { }); }); diff --git a/test/lib/config/validators.test.js b/test/lib/config/validators.test.js index be8b867d..1ae9de05 100644 --- a/test/lib/config/validators.test.js +++ b/test/lib/config/validators.test.js @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import * as lib from "@clusterio/lib"; const validators = lib.Config.validators; -import { ControllerConfig, HostConfig, InstanceConfig, ControlConfig } from "@clusterio/lib"; +import { ControllerConfig, HostConfig, InstanceConfig, CtlConfig } from "@clusterio/lib"; describe("lib/config/validators", function() { describe("all", function() { @@ -366,7 +366,7 @@ describe("lib/config/definitions/validators", function() { }); }); - describe("Control Config", function() { + describe("Ctl Config", function() { }); }); diff --git a/test/lib/plugin.js b/test/lib/plugin.js index 176a3bf6..dd5ef087 100644 --- a/test/lib/plugin.js +++ b/test/lib/plugin.js @@ -18,7 +18,7 @@ describe("lib/plugin", function() { name: "foo", title: "Foo", controllerEntrypoint: "controller.js", }), true); for (const field of [ - "controllerConfigFields", "hostConfigFields", "instanceConfigFields", "controlConfigFields", + "controllerConfigFields", "hostConfigFields", "instanceConfigFields", "ctlConfigFields", ]) { assert.equal(lib.pluginNeedsWebBuild({ name: "foo", title: "Foo", [field]: {} }), true, field); }