From 2c9b07b8d62b6183af20fbd31bd59b04011f06be Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sat, 18 Nov 2023 22:12:14 +0100 Subject: [PATCH 01/13] Add subscription handlers in constructor Move the calls to add subscrition handlers into the constructor of Controller to reduce the amount of code in the start logic. --- packages/controller/src/Controller.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index e355b836..68dba094 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -110,6 +110,14 @@ export default class Controller { this.wsServer = new WsServer(this); this.userManager = new UserManager(this.config); this.subscriptions = new lib.SubscriptionController(this); + + // Handle subscriptions for all internal properties + this.subscriptions.handle(lib.HostUpdateEvent); + this.subscriptions.handle(lib.InstanceDetailsUpdateEvent); + this.subscriptions.handle(lib.InstanceSaveListUpdateEvent); + this.subscriptions.handle(lib.ModPackUpdateEvent); + this.subscriptions.handle(lib.ModUpdateEvent); + this.subscriptions.handle(lib.UserUpdateEvent); } async start(args: ControllerArgs) { @@ -240,14 +248,6 @@ export default class Controller { this.app.locals.mainBundle = manifest["main.js"] || "no_web_build"; } - // Handle subscriptions for all internal properties - this.subscriptions.handle(lib.HostUpdateEvent); - this.subscriptions.handle(lib.InstanceDetailsUpdateEvent); - this.subscriptions.handle(lib.InstanceSaveListUpdateEvent); - this.subscriptions.handle(lib.ModPackUpdateEvent); - this.subscriptions.handle(lib.ModUpdateEvent); - this.subscriptions.handle(lib.UserUpdateEvent); - // Load plugins await this.loadPlugins(); From 97e05c0610da949681b60deccf1880d7c63ab699 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Wed, 11 Oct 2023 16:48:42 +0200 Subject: [PATCH 02/13] Update GitHub actions --- .github/workflows/node.js.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 5808be74..6098895e 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -16,12 +16,12 @@ jobs: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2.4.0 with: version: 8 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: pnpm i --no-optional --no-frozen-lockfile @@ -43,11 +43,11 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2.4.0 with: version: 8 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: 18.x - run: pnpm i --no-optional --no-frozen-lockfile From 7314dc99c82a5b695e674dac18c3de40695e4f8a Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Wed, 11 Oct 2023 17:59:32 +0200 Subject: [PATCH 03/13] Fix code style errors Remove extra whitespace, use more consistent spacing, add missing semicolons, using dangling commas, break up long lines, consistent multiline operator placement, add missing JSDoc strings and so on. --- packages/controller/controller.ts | 18 ++- packages/controller/src/ControlConnection.ts | 12 +- packages/controller/src/Controller.ts | 25 +++-- packages/controller/src/HostConnection.ts | 6 +- packages/controller/src/HttpCloser.ts | 3 +- packages/controller/src/InstanceInfo.ts | 2 +- packages/controller/src/UserManager.ts | 5 +- packages/controller/src/WsServer.ts | 4 +- packages/controller/src/metrics.ts | 2 +- packages/controller/src/routes.ts | 36 +++--- packages/ctl/src/commands.ts | 2 +- packages/host/src/Host.ts | 1 - packages/host/src/Instance.ts | 4 +- packages/host/src/export.ts | 1 - packages/host/src/patch.ts | 10 +- packages/host/src/server.ts | 106 +++++++++--------- packages/lib/index.ts | 2 +- packages/lib/src/config/classes.ts | 2 +- packages/lib/src/config/definitions.ts | 7 +- packages/lib/src/data/ModPack.ts | 1 - packages/lib/src/data/composites.ts | 2 +- packages/lib/src/data/message_validate.d.ts | 2 +- packages/lib/src/data/messages_controller.ts | 1 + packages/lib/src/data/messages_host.ts | 10 +- packages/lib/src/data/messages_user.ts | 2 +- packages/lib/src/database.ts | 3 +- packages/lib/src/factorio/exchange_string.ts | 9 +- packages/lib/src/is_deep_strict_equal.d.ts | 2 +- packages/lib/src/link/connectors.ts | 7 +- packages/lib/src/link/index.ts | 4 +- packages/lib/src/link/link.ts | 8 +- packages/lib/src/link/messages.ts | 3 +- packages/lib/src/logging.ts | 1 - packages/lib/src/logging_utils.ts | 1 - packages/lib/src/plugin.ts | 2 +- packages/lib/src/plugin_loader.ts | 2 +- packages/lib/src/prometheus.ts | 3 +- packages/lib/src/schema.ts | 6 +- packages/lib/src/shared_commands.ts | 1 - packages/lib/src/stream.ts | 1 - packages/lib/src/subscriptions.ts | 73 +++++++++--- packages/lib/src/users.ts | 2 +- packages/web_ui/global.d.ts | 4 +- .../web_ui/src/components/BaseConfigTree.tsx | 2 +- .../web_ui/src/components/HostViewPage.tsx | 16 +-- packages/web_ui/src/components/HostsPage.tsx | 18 +-- .../web_ui/src/components/InstanceList.tsx | 2 +- .../src/components/InstanceViewPage.tsx | 2 +- packages/web_ui/src/components/ModDetails.tsx | 2 +- .../web_ui/src/components/ModPackViewPage.tsx | 22 ++-- .../web_ui/src/components/RoleViewPage.tsx | 6 +- packages/web_ui/src/components/SavesList.tsx | 5 +- .../components/StartStopInstanceButton.tsx | 4 +- packages/web_ui/src/components/UsersPage.tsx | 4 +- packages/web_ui/src/model/host.ts | 12 +- packages/web_ui/src/model/item_metadata.ts | 16 +-- packages/web_ui/src/model/saves.ts | 2 +- packages/web_ui/src/model/user.tsx | 6 +- packages/web_ui/src/util/websocket.ts | 31 +++-- plugins/global_chat/info.ts | 2 +- plugins/inventory_sync/info.ts | 4 +- plugins/inventory_sync/instance.ts | 43 +++++-- plugins/inventory_sync/messages.ts | 14 +-- plugins/player_auth/controller.ts | 20 +++- plugins/player_auth/instance.ts | 13 ++- plugins/player_auth/messages.ts | 6 +- plugins/research_sync/messages.ts | 15 +-- plugins/subspace_storage/controller.ts | 4 +- plugins/subspace_storage/dole.ts | 3 +- plugins/subspace_storage/instance.ts | 5 +- plugins/subspace_storage/messages.ts | 16 +-- 71 files changed, 403 insertions(+), 290 deletions(-) diff --git a/packages/controller/controller.ts b/packages/controller/controller.ts index b7be8148..e0e72c0f 100644 --- a/packages/controller/controller.ts +++ b/packages/controller/controller.ts @@ -83,18 +83,16 @@ void new lib.Gauge( "clusterio_controller_websocket_active_connections", "How many WebSocket connections are currently open to the controller", { callback: function(gauge:lib.Gauge) { - gauge.set(controller.wsServer.activeConnectors.size); - } - } + gauge.set(controller.wsServer.activeConnectors.size); + }} ); void new lib.Gauge( "clusterio_controller_active_hosts", "How many hosts are currently connected to the controller", { callback: function(gauge:lib.Gauge) { - gauge.set(controller.wsServer.hostConnections.size); - } - } + gauge.set(controller.wsServer.hostConnections.size); + }} ); void new lib.Gauge( @@ -294,7 +292,7 @@ async function initialize(): Promise { logger.info(`Loading available plugins from ${args.pluginList}`); let pluginList = new Map(); try { - pluginList = new Map(JSON.parse(await fs.readFile(args.pluginList, { encoding: 'utf8' }))); + pluginList = new Map(JSON.parse(await fs.readFile(args.pluginList, { encoding: "utf8" }))); } catch (err: any) { if (err.code !== "ENOENT") { throw err; @@ -324,7 +322,7 @@ async function initialize(): Promise { logger.info(`Loading config from ${controllerConfigPath}`); const controllerConfig = new lib.ControllerConfig("controller"); try { - let fileData = await fs.readFile(controllerConfigPath, { encoding: 'utf8' }) + let fileData = await fs.readFile(controllerConfigPath, { encoding: "utf8" }); await controllerConfig.load(JSON.parse(fileData)); } catch (err: any) { @@ -363,7 +361,7 @@ async function initialize(): Promise { controllerConfigPath, controllerConfig, shouldRun, - } + }; } async function startup() { @@ -377,7 +375,7 @@ async function startup() { clusterLogger, pluginInfos, controllerConfigPath, - controllerConfig + controllerConfig, } = await initialize(); if (!shouldRun || !pluginInfos || !controllerConfigPath || !controllerConfig) { return; diff --git a/packages/controller/src/ControlConnection.ts b/packages/controller/src/ControlConnection.ts index 3ace64f8..58eb0fd1 100644 --- a/packages/controller/src/ControlConnection.ts +++ b/packages/controller/src/ControlConnection.ts @@ -254,7 +254,7 @@ export default class ControlConnection extends BaseConnection { assigned_host = undefined; } - let game_port: number|null|undefined = instance.game_port + let game_port: number|null|undefined = instance.game_port; if (game_port === null) { game_port = undefined; } @@ -275,8 +275,8 @@ export default class ControlConnection extends BaseConnection { if (assigned_host === null) { assigned_host = undefined; } - - let game_port: number|null|undefined = instance.game_port + + let game_port: number|null|undefined = instance.game_port; if (game_port === null) { game_port = undefined; } @@ -434,7 +434,7 @@ export default class ControlConnection extends BaseConnection { async handleModPackCreateRequest(request: lib.ModPackCreateRequest) { let modPack = request.modPack; if (modPack.id === undefined) { - throw new lib.RequestError(`Mod pack need an ID to be created`); + throw new lib.RequestError("Mod pack need an ID to be created"); } if (this._controller.modPacks!.has(modPack.id)) { throw new lib.RequestError(`Mod pack with ID ${modPack.id} already exist`); @@ -589,7 +589,7 @@ export default class ControlConnection extends BaseConnection { } async handleLogSetSubscriptionsRequest(request: lib.LogSetSubscriptionsRequest) { - this.logSubscriptions = { + this.logSubscriptions = { all: request.all || false, controller: request.controller || false, hostIds: request.hostIds || [], @@ -622,7 +622,7 @@ export default class ControlConnection extends BaseConnection { controller: request.controller, hostIds: request.hostIds, instanceIds: request.instanceIds, - } + }; let observeDuration = queryLogTime.startTimer(); let { all, controller, hostIds, instanceIds } = request; diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index 68dba094..900ebce5 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -77,7 +77,7 @@ export default class Controller { /** Event subscription controller */ subscriptions: lib.SubscriptionController; - + // Possible states are new, starting, running, stopping, stopped private _state: string = "new"; private _shouldStop: boolean = false; @@ -87,7 +87,7 @@ export default class Controller { _snoopedEvents = new Map(); devMiddleware: any | null = null; - + logDirectory: string = ""; clusterLogIndex: lib.LogIndex | null = null; clusterLogBuildInterval: ReturnType | null = null; @@ -157,7 +157,7 @@ export default class Controller { async _startInternal(args: ControllerArgs) { this.logDirectory = args.logDirectory; this.clusterLogIndex = await lib.LogIndex.load(path.join(this.logDirectory, "cluster")); - + this.clusterLogBuildInterval = setInterval(() => { if (this.clusterLogIndex) { this.clusterLogIndex.buildIndex().catch( @@ -239,7 +239,7 @@ export default class Controller { Controller.addAppRoutes(this.app, this.pluginInfos); if (!args.dev) { - let manifestPath = path.join(__dirname, "..", "..", "web", "manifest.json") + let manifestPath = path.join(__dirname, "..", "..", "web", "manifest.json"); let manifest = await Controller.loadJsonObject(manifestPath); if (!manifest["main.js"]) { @@ -365,7 +365,7 @@ export default class Controller { static async loadHosts(filePath: string): Promise> { let serialized: [number, HostInfo][]; try { - serialized = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); + serialized = JSON.parse(await fs.readFile(filePath, { encoding: "utf8" })); } catch (err: any) { if (err.code !== "ENOENT") { @@ -425,7 +425,7 @@ export default class Controller { static async loadModPacks(filePath: string): Promise> { let json; try { - json = JSON.parse(await fs.readFile(filePath, { encoding : "utf8" })); + json = JSON.parse(await fs.readFile(filePath, { encoding: "utf8" })); } catch (err: any) { if (err.code !== "ENOENT") { throw err; @@ -439,7 +439,7 @@ export default class Controller { await lib.safeOutputFile(filePath, JSON.stringify([...modPacks.values()], null, 4)); } - static async loadModInfos(modsDirectory: string): Promise> { + static async loadModInfos(modsDirectory: string): Promise> { let mods = new Map(); for (let entry of await fs.readdir(modsDirectory, { withFileTypes: true })) { if (entry.isDirectory()) { @@ -476,7 +476,7 @@ export default class Controller { static async loadJsonObject(filePath: string, throwOnMissing: boolean = false): Promise { let manifest = {}; try { - manifest = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); + manifest = JSON.parse(await fs.readFile(filePath, { encoding: "utf8" })); } catch (err: any) { if (!throwOnMissing && err.code !== "ENOENT") { throw err; @@ -543,7 +543,9 @@ export default class Controller { // Set folder to serve static content from (the website) const staticOptions = { immutable: true, maxAge: 1000 * 86400 * 365 }; - app.use("/static", express.static(path.join(__dirname, "..", "..", "..", "dist", "web", "static"), staticOptions)); + app.use("/static", + express.static(path.join(__dirname, "..", "..", "..", "dist", "web", "static"), staticOptions) + ); app.use("/static", express.static("static", staticOptions)); // Used for data export files // Add API routes @@ -595,9 +597,10 @@ export default class Controller { * Get instance by ID for a request * * @param instanceId - ID of instance to get. + * @returns Info for the given instance if it exists * @throws {module:lib.RequestError} if the instance does not exist. */ - getRequestInstance(instanceId:number):InstanceInfo { + getRequestInstance(instanceId:number): InstanceInfo { let instance = this.instances!.get(instanceId); if (!instance) { throw new lib.RequestError(`Instance with ID ${instanceId} does not exist`); @@ -773,7 +776,7 @@ export default class Controller { assigned_host = undefined; } - let game_port: number|null|undefined = instance.game_port + let game_port: number|null|undefined = instance.game_port; if (game_port === null) { game_port = undefined; } diff --git a/packages/controller/src/HostConnection.ts b/packages/controller/src/HostConnection.ts index be4c4413..61d2fb97 100644 --- a/packages/controller/src/HostConnection.ts +++ b/packages/controller/src/HostConnection.ts @@ -46,7 +46,7 @@ export default class HostConnection extends BaseConnection { this.plugins = new Map(Object.entries(registerData.plugins)); this._checkPluginVersions(); - let currentHostInfo = this._controller.hosts!.get(this._id) + let currentHostInfo = this._controller.hosts!.get(this._id); this._controller.hosts!.set(this._id, { agent: this._agent, @@ -223,7 +223,9 @@ export default class HostConnection extends BaseConnection { } instanceConfig.set("instance.assigned_host", this._id); - let newInstance = new InstanceInfo({ config: instanceConfig, status: instanceData.status as InstanceStatus }); + let newInstance = new InstanceInfo( + { config: instanceConfig, status: instanceData.status as InstanceStatus } + ); this._controller.instances!.set(instanceConfig.get("instance.id"), newInstance); this._controller.addInstanceHooks(newInstance); await this.send( diff --git a/packages/controller/src/HttpCloser.ts b/packages/controller/src/HttpCloser.ts index 4c52364e..2631930c 100644 --- a/packages/controller/src/HttpCloser.ts +++ b/packages/controller/src/HttpCloser.ts @@ -26,7 +26,8 @@ export default class HttpCloser { private _responses: Set; /** - * Server to attach this closer to. + * Create HttpCloser attached to a server. + * @param server - Node.js HTTP(S) server to attach to. */ constructor(server: http.Server | https.Server) { this._server = server; diff --git a/packages/controller/src/InstanceInfo.ts b/packages/controller/src/InstanceInfo.ts index 7af224cf..40c869cb 100644 --- a/packages/controller/src/InstanceInfo.ts +++ b/packages/controller/src/InstanceInfo.ts @@ -14,7 +14,7 @@ import type * as lib from "@clusterio/lib"; * - `exporting_data`: Instance is in the process of exporting game data. * - `deleted`: Instance has been deleted. */ -export type InstanceStatus = +export type InstanceStatus = "unknown" | "unassigned" | "stopped" | "starting" | "running" | "stopping" | "creating_save" | "exporting_data" | "deleted"; diff --git a/packages/controller/src/UserManager.ts b/packages/controller/src/UserManager.ts index bd2789c3..51254cb2 100644 --- a/packages/controller/src/UserManager.ts +++ b/packages/controller/src/UserManager.ts @@ -18,7 +18,7 @@ export default class UserManager { async load(filePath: string): Promise { try { - let content = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); + let content = JSON.parse(await fs.readFile(filePath, { encoding: "utf8" })); for (let serializedRole of content.roles) { let role = new lib.Role(serializedRole); this.roles.set(role.id, role); @@ -65,6 +65,7 @@ export default class UserManager { /** * Creates a new user and add it to the user database. * @param name - Name of the user to create. + * @returns The created user. */ createUser(name:string): lib.User { if (this.users.has(name)) { @@ -74,7 +75,7 @@ export default class UserManager { let roles = []; let defaultRoleId = this._config.get("controller.default_role_id"); if (defaultRoleId !== null) { - roles.push(defaultRoleId) + roles.push(defaultRoleId); } let user = new lib.User({ name, roles }, this.roles); diff --git a/packages/controller/src/WsServer.ts b/packages/controller/src/WsServer.ts index e52e267e..07886741 100644 --- a/packages/controller/src/WsServer.ts +++ b/packages/controller/src/WsServer.ts @@ -54,7 +54,9 @@ export default class WsServer { noServer: true, path: "/api/socket", }); - this.wss.on("connection", (socket: lib.WebSocketClusterio, req: IncomingMessage) => this.handleConnection(socket, req)); + this.wss.on("connection", + (socket: lib.WebSocketClusterio, req: IncomingMessage) => this.handleConnection(socket, req), + ); } async stop(): Promise { diff --git a/packages/controller/src/metrics.ts b/packages/controller/src/metrics.ts index d25d5690..ae0b7aca 100644 --- a/packages/controller/src/metrics.ts +++ b/packages/controller/src/metrics.ts @@ -12,4 +12,4 @@ endpointHitCounter.labels = util.deprecate( "incrementing endpointHitCounter is no longer needed and has no effect" ); -export default endpointHitCounter +export default endpointHitCounter; diff --git a/packages/controller/src/routes.ts b/packages/controller/src/routes.ts index 4e506313..4e5c14a1 100644 --- a/packages/controller/src/routes.ts +++ b/packages/controller/src/routes.ts @@ -34,7 +34,7 @@ function mergeSamples(destinationResult: any, sourceResult: any) { // Prometheus polling endpoint async function getMetrics(req: Request, res: Response, next: any) { - const controller: Controller = req.app.locals.controller + const controller: Controller = req.app.locals.controller; let results: any[] = []; let pluginResults: any[] = await lib.invokeHook(controller.plugins, "onMetrics"); @@ -93,7 +93,7 @@ async function getMetrics(req: Request, res: Response, next: any) { // lib.exposition expect AsyncIterable as parameter. // Should wrap results into a Generator functions ? - // @ts-ignore + // @ts-ignore let text = await lib.exposition(results); res.set("Content-Type", lib.exposition.contentType); res.send(text); @@ -426,28 +426,29 @@ async function uploadSave(req: Request, res: Response) { if (contentMime === "multipart/form-data") { await new Promise(resolve => { - let instanceId:number | undefined; - let parser = busboy({ headers: req.headers }); - parser.on("file", (name: string, stream: nodeStream.Readable, { filename, mimeType }: { filename: string, mimeType: string } ) => { + let instanceId: number | undefined; + function fileHandler( + name: string, + stream: nodeStream.Readable, + { filename, mimeType }: { filename: string, mimeType: string } + ) { if (instanceId === undefined) { requestErrors.push("instance_id must come before files uploaded"); } - if (!zipMimes.includes(mimeType)) { requestErrors.push("invalid file Content-Type"); } - if (!filename.endsWith(".zip")) { requestErrors.push("filename must end with .zip"); } - if (errors.length || requestErrors.length) { stream.resume(); return; } - tasks.push(handleFile(instanceId as number, stream, filename, mimeType)); - }); + } + let parser = busboy({ headers: req.headers }); + parser.on("file", fileHandler); parser.on("field", (name, value, info) => { if (name === "instance_id") { instanceId = Number.parseInt(value, 10); @@ -593,23 +594,26 @@ async function uploadMod(req: Request, res: Response) { if (contentMime === "multipart/form-data") { await new Promise(resolve => { - let parser = busboy({ headers: req.headers }); - parser.on("file", (name:string, stream: nodeStream.Readable, { filename, mimeType }: { filename: string, mimeType: string }) => { + function fileHandler( + name: string, + stream: nodeStream.Readable, + { filename, mimeType }: { filename: string, mimeType: string } + ) { if (!zipMimes.includes(mimeType)) { requestErrors.push("invalid file Content-Type"); } - if (!filename.endsWith(".zip")) { requestErrors.push("filename must end with .zip"); } - if (errors.length || requestErrors.length) { stream.resume(); return; } - tasks.push(handleFile(stream, filename)); - }); + } + + let parser = busboy({ headers: req.headers }); + parser.on("file", fileHandler); parser.on("close", resolve); parser.on("error", (err: any) => { logger.error(`Error parsing multipart request in upload-mod:\n${err.stack}`); diff --git a/packages/ctl/src/commands.ts b/packages/ctl/src/commands.ts index 1d8d5d9a..484490f1 100644 --- a/packages/ctl/src/commands.ts +++ b/packages/ctl/src/commands.ts @@ -466,7 +466,7 @@ instanceConfigCommands.add(new lib.Command({ }); await events.once(doneEmitter, "dot_on_done"); try { - await fs.unlink(tmpFile) + await fs.unlink(tmpFile); } catch (err) { print("err: temporary file", tmpFile, "could not be deleted."); print("This is not fatal, but they may build up over time if the issue persists."); diff --git a/packages/host/src/Host.ts b/packages/host/src/Host.ts index 835c39b7..7af872c0 100644 --- a/packages/host/src/Host.ts +++ b/packages/host/src/Host.ts @@ -1,4 +1,3 @@ -"use strict"; import fs from "fs-extra"; import path from "path"; import events from "events"; diff --git a/packages/host/src/Instance.ts b/packages/host/src/Instance.ts index 9c3e059f..0288ee1e 100644 --- a/packages/host/src/Instance.ts +++ b/packages/host/src/Instance.ts @@ -11,7 +11,7 @@ import * as lib from "@clusterio/lib"; import { FactorioServer } from "./server"; import { SaveModule, patch } from "./patch"; import { exportData } from "./export"; -import type Host from "./Host" +import type Host from "./Host"; const instanceRconCommandDuration = new lib.Histogram( @@ -99,7 +99,7 @@ export default class Instance extends lib.Link { /** * ID of this instance, equivalenet to `instance.config.get("instance.id")`. */ - readonly id: number + readonly id: number; plugins: Map; config: lib.InstanceConfig; logger: lib.Logger; diff --git a/packages/host/src/export.ts b/packages/host/src/export.ts index 76f13ebb..dcd2b01a 100644 --- a/packages/host/src/export.ts +++ b/packages/host/src/export.ts @@ -1,5 +1,4 @@ // Export of item icons and locale -"use strict"; import fs from "fs-extra"; import path from "path"; import Jimp from "jimp"; diff --git a/packages/host/src/patch.ts b/packages/host/src/patch.ts index 7e16bf92..035b824d 100644 --- a/packages/host/src/patch.ts +++ b/packages/host/src/patch.ts @@ -18,7 +18,7 @@ export class SaveModule { /** Module */ public info: lib.ModuleInfo, /** Files and their content that will be patched into the save */ - public files = new Map, + public files = new Map(), ) { } static moduleFilePath(filePath: string, moduleName: string) { @@ -47,7 +47,7 @@ export class SaveModule { if (entry.isFile()) { let savePath = SaveModule.moduleFilePath(relativePath, this.info.name); this.files.set(savePath, await fs.readFile(fsPath)); - if (relativePath == "module_exports.lua") { + if (relativePath === "module_exports.lua") { this.files.set( `modules/${this.info.name}.lua`, Buffer.from(`return require("modules/${this.info.name}/module_exports")`, "utf-8") @@ -96,7 +96,7 @@ export class SaveModule { version: plugin.info.version, dependencies: { "clusterio": "*" }, ...JSON.parse(await fs.readFile(moduleJsonPath, "utf8")), - } + }; } catch (err: any) { throw new Error(`Loading module/module.json in plugin ${plugin.info.name} failed: ${err.message}`); } @@ -173,7 +173,7 @@ export class PatchInfo { interface PatchInfoV0 { patch_number: number; scenario: ScenarioInfoV0; - modules: { name: string, files: { path: string, load: boolean, require: boolean }[], }[]; + modules: { name: string, files: { path: string, load: boolean, require: boolean }[], }[]; } const info = json as unknown as PatchInfoV0; @@ -394,7 +394,7 @@ export async function patch(savePath: string, modules: SaveModule[]) { } else { for (let module of patchInfo.modules) { for (let file of module.files.keys()) { - zip.remove(root.file(file)!.name) + zip.remove(root.file(file)!.name); } } patchInfo.modules = []; diff --git a/packages/host/src/server.ts b/packages/host/src/server.ts index 93a93364..a2404bb1 100644 --- a/packages/host/src/server.ts +++ b/packages/host/src/server.ts @@ -220,65 +220,61 @@ function parseOutput(line: string, source: "stdout" | "stderr"): lib.ParsedFacto level: secLogMatch[1], file: secLogMatch[2], message: secLogMatch[5], - } + }; + } // The other possibility is that the content is a generic message - } else { + return { + source, + format, + time, + type: "generic", + message: secContent, + }; + } + + // The second category of output starts with a date stamp of the format + // "yyyy-mm-dd hh:mm:ss message" + const dateRegex = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d) (.*)$/; + let dateMatch = dateRegex.exec(line); + if (dateMatch) { + const format = "date"; + const time = dateMatch[1]; + let dateContent = dateMatch[2]; + + // A date output has two general formats. The first is an action + // followed by a message and has a format of "[ACTION] message" + const dateActionRegex = /^\[(\w+)\] (.*)$/; + let dateActionMatch = dateActionRegex.exec(dateContent); + if (dateActionMatch) { return { source, format, time, - type: "generic", - message: secContent, - } + type: "action", + action: dateActionMatch[1], + message: dateActionMatch[2], + }; } - // The second category of output starts with a date stamp of the format - // "yyyy-mm-dd hh:mm:ss message" - } else { - const dateRegex = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d) (.*)$/; - let dateMatch = dateRegex.exec(line); - if (dateMatch) { - const format = "date"; - const time = dateMatch[1]; - let dateContent = dateMatch[2]; - - // A date output has two general formats. The first is an action - // followed by a message and has a format of "[ACTION] message" - const dateActionRegex = /^\[(\w+)\] (.*)$/; - let dateActionMatch = dateActionRegex.exec(dateContent); - if (dateActionMatch) { - return { - source, - format, - time, - type: "action", - action: dateActionMatch[1], - message: dateActionMatch[2], - } - - // The other format is a generic message - } else { - return { - source, - format, - time, - type: "generic", - message: dateContent, - } - } - - // The last category of output is simply a generic message with no - // formating. - } else { - return { - source, - format: "none", - type: "generic", - message: line, - } - } + // The other format is a generic message + return { + source, + format, + time, + type: "generic", + message: dateContent, + }; } + + // The last category of output is simply a generic message with no + // formating. + return { + source, + format: "none", + type: "generic", + message: line, + }; } // https://stackoverflow.com/a/49402091 @@ -465,7 +461,7 @@ export class FactorioServer extends events.EventEmitter { /** Enable Factorio.com based multiplayer bans **/ enableAuthserverBans: boolean; /** Enable verbose logging */ - verboseLogging: boolean + verboseLogging: boolean; /** Timeout in ms to wait for a response to a shutdown command */ hangTimeout = 5000; @@ -852,8 +848,8 @@ export class FactorioServer extends events.EventEmitter { "--config", this.writePath("config.ini"), "--create", this.writePath("saves", name), ...(seed !== undefined ? ["--map-gen-seed", String(seed)] : []), - ...(mapGenSettings !== undefined ? - ["--map-gen-settings", this.writePath("map-gen-settings.json")] : [] + ...(mapGenSettings !== undefined + ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : [] ), ...(mapSettings !== undefined ? ["--map-settings", this.writePath("map-settings.json")] : []), ...(this.verboseLogging ? ["--verbose"] : []), @@ -944,8 +940,8 @@ export class FactorioServer extends events.EventEmitter { "--config", this.writePath("config.ini"), "--start-server-load-scenario", scenario, ...(seed !== undefined ? ["--map-gen-seed", String(seed)] : []), - ...(mapGenSettings !== undefined ? - ["--map-gen-settings", this.writePath("map-gen-settings.json")] : [] + ...(mapGenSettings !== undefined + ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : [] ), ...(mapSettings !== undefined ? ["--map-settings", this.writePath("map-settings.json")] : []), "--port", String(this.gamePort), diff --git a/packages/lib/index.ts b/packages/lib/index.ts index 19583966..428086e3 100644 --- a/packages/lib/index.ts +++ b/packages/lib/index.ts @@ -25,7 +25,7 @@ export * from "./src/shared_commands"; export * from "./src/stream"; export * from "./src/users"; export * from "./src/zip_ops"; -export * from "./src/subscriptions" +export * from "./src/subscriptions"; export { default as ExponentialBackoff } from "./src/ExponentialBackoff"; export { default as PlayerStats } from "./src/PlayerStats"; diff --git a/packages/lib/src/config/classes.ts b/packages/lib/src/config/classes.ts index 88614815..4b40e4a9 100644 --- a/packages/lib/src/config/classes.ts +++ b/packages/lib/src/config/classes.ts @@ -3,7 +3,7 @@ import { Type, Static } from "@sinclair/typebox"; import events from "events"; import isDeepStrictEqual from "../is_deep_strict_equal"; -import { basicType } from"../helpers"; +import { basicType } from "../helpers"; export type ConfigLocation = "controller" | "host" | "instance" | "control"; diff --git a/packages/lib/src/config/definitions.ts b/packages/lib/src/config/definitions.ts index 72a5be05..9c878065 100644 --- a/packages/lib/src/config/definitions.ts +++ b/packages/lib/src/config/definitions.ts @@ -264,7 +264,7 @@ export class HostConfig extends classes.Config { get(name: "host.public_address"): string; get(name: "host.max_reconnect_delay"): number; get(name: string): unknown; - get(name: string) { + get(name: string) { return super.get(name); } } @@ -503,7 +503,10 @@ export class ControlConfig extends classes.Config { } ControlConfig.registerGroup(ControlGroup); -function validateGroup(pluginInfo: PluginNodeEnvInfo|PluginWebpackEnvInfo, groupName: "ControllerConfigGroup"|"InstanceConfigGroup") { +function validateGroup( + pluginInfo: PluginNodeEnvInfo | PluginWebpackEnvInfo, + groupName: "ControllerConfigGroup"|"InstanceConfigGroup", +) { if (!(pluginInfo[groupName]?.prototype instanceof classes.PluginConfigGroup)) { throw new Error( `Expected ${groupName} for ${pluginInfo.name} to be a subclass of PluginConfigGroup` diff --git a/packages/lib/src/data/ModPack.ts b/packages/lib/src/data/ModPack.ts index 95d1c31f..14fc7f29 100644 --- a/packages/lib/src/data/ModPack.ts +++ b/packages/lib/src/data/ModPack.ts @@ -1,4 +1,3 @@ -"use strict"; import zlib from "zlib"; import { Type, Static } from "@sinclair/typebox"; diff --git a/packages/lib/src/data/composites.ts b/packages/lib/src/data/composites.ts index 8566185f..c4f912ef 100644 --- a/packages/lib/src/data/composites.ts +++ b/packages/lib/src/data/composites.ts @@ -1,7 +1,7 @@ import { Type } from "@sinclair/typebox"; export function StringEnum(values: [...T]) { - return Type.Unsafe({ type: 'string', enum: values }) + return Type.Unsafe({ type: "string", enum: values }); } export interface JSONDeserialisable { diff --git a/packages/lib/src/data/message_validate.d.ts b/packages/lib/src/data/message_validate.d.ts index fdd40377..d9ec5838 100644 --- a/packages/lib/src/data/message_validate.d.ts +++ b/packages/lib/src/data/message_validate.d.ts @@ -1,4 +1,4 @@ import type { ValidateFunction } from "ajv"; import type { Message } from "./messages_core"; -var message_validate: ValidateFunction; +const message_validate: ValidateFunction; export default message_validate; diff --git a/packages/lib/src/data/messages_controller.ts b/packages/lib/src/data/messages_controller.ts index e39de057..5a0aefc8 100644 --- a/packages/lib/src/data/messages_controller.ts +++ b/packages/lib/src/data/messages_controller.ts @@ -166,6 +166,7 @@ export class LogQueryRequest { json.all, json.controller, json.hostIds, json.instanceIds, json.maxLevel, json.limit, json.order ); } + static Response = class Response { constructor( public log: object[], diff --git a/packages/lib/src/data/messages_host.ts b/packages/lib/src/data/messages_host.ts index 5389a7c2..4343e14b 100644 --- a/packages/lib/src/data/messages_host.ts +++ b/packages/lib/src/data/messages_host.ts @@ -23,7 +23,15 @@ export class HostDetails { }); static fromJSON(json: Static) { - return new this(json.agent, json.version, json.name, json.id, json.connected, json.publicAddress, json.tokenValidAfter); + return new this( + json.agent, + json.version, + json.name, + json.id, + json.connected, + json.publicAddress, + json.tokenValidAfter, + ); } } diff --git a/packages/lib/src/data/messages_user.ts b/packages/lib/src/data/messages_user.ts index be7c1c9d..c50a9339 100644 --- a/packages/lib/src/data/messages_user.ts +++ b/packages/lib/src/data/messages_user.ts @@ -211,7 +211,7 @@ export class RawUser { // TODO refactor into lib/user.User isDeleted: this.isDeleted, }; if (this.playerStats) { - json.playerStats = this.playerStats.toJSON() + json.playerStats = this.playerStats.toJSON(); } if (this.instanceStats) { json.instanceStats = [...this.instanceStats].map(([k, v]) => [k, v.toJSON()]); diff --git a/packages/lib/src/database.ts b/packages/lib/src/database.ts index 3f54c301..aaedd478 100644 --- a/packages/lib/src/database.ts +++ b/packages/lib/src/database.ts @@ -277,8 +277,9 @@ export class ItemDatabase { /** * Allow to iterate through the items. + * @returns array of items. */ getEntries(): IterableIterator<[string, number]> { - return this._items.entries() + return this._items.entries(); } } diff --git a/packages/lib/src/factorio/exchange_string.ts b/packages/lib/src/factorio/exchange_string.ts index 13a4ef6a..3ca83522 100644 --- a/packages/lib/src/factorio/exchange_string.ts +++ b/packages/lib/src/factorio/exchange_string.ts @@ -1,4 +1,3 @@ -"use strict"; import zlib from "zlib"; class MapReaderState { @@ -72,7 +71,7 @@ function readString(state: MapReaderState) { return data; } -function readOptional(state: MapReaderState, readValue: (state: MapReaderState) => T) { +function readOptional(state: MapReaderState, readValue: (s: MapReaderState) => T) { let load = readUInt8(state) !== 0; if (!load) { return null; @@ -80,7 +79,7 @@ function readOptional(state: MapReaderState, readValue: (state: MapReaderStat return readValue(state); } -function readArray(state: MapReaderState, readItem: (state: MapReaderState) => T) { +function readArray(state: MapReaderState, readItem: (s: MapReaderState) => T) { let size = readUInt32so(state); let array: T[] = []; @@ -94,8 +93,8 @@ function readArray(state: MapReaderState, readItem: (state: MapReaderState) = function readDict( state: MapReaderState, - readKey: (state: MapReaderState) => K, - readValue: (state: MapReaderState) => V + readKey: (s: MapReaderState) => K, + readValue: (s: MapReaderState) => V ) { let size = readUInt32so(state); diff --git a/packages/lib/src/is_deep_strict_equal.d.ts b/packages/lib/src/is_deep_strict_equal.d.ts index ec5e4c72..3ec0532c 100644 --- a/packages/lib/src/is_deep_strict_equal.d.ts +++ b/packages/lib/src/is_deep_strict_equal.d.ts @@ -1 +1 @@ -export default function isDeepStrictEqual(a: any, b: any): boolean +export default function isDeepStrictEqual(a: any, b: any): boolean; diff --git a/packages/lib/src/link/connectors.ts b/packages/lib/src/link/connectors.ts index 8345d975..2f22236d 100644 --- a/packages/lib/src/link/connectors.ts +++ b/packages/lib/src/link/connectors.ts @@ -1,13 +1,12 @@ // Connection adapters for Links -"use strict"; import { strict as assert } from "assert"; import events from "events"; import WebSocket from "./WebSocket"; import * as libData from "../data"; -import * as libErrors from "../errors"; -import { logger } from "../logging"; -import ExponentialBackoff from "../ExponentialBackoff"; +import * as libErrors from "../errors"; +import { logger } from "../logging"; +import ExponentialBackoff from "../ExponentialBackoff"; import type { Request, Event } from "./link"; diff --git a/packages/lib/src/link/index.ts b/packages/lib/src/link/index.ts index e13d1d8b..d48297e3 100644 --- a/packages/lib/src/link/index.ts +++ b/packages/lib/src/link/index.ts @@ -3,5 +3,5 @@ * @module lib/link * @author Hornwitser */ -export * from "./link" -export * from "./connectors" +export * from "./link"; +export * from "./connectors"; diff --git a/packages/lib/src/link/link.ts b/packages/lib/src/link/link.ts index 73bb633e..998e3a63 100644 --- a/packages/lib/src/link/link.ts +++ b/packages/lib/src/link/link.ts @@ -316,7 +316,7 @@ export class Link { if (!this.router) { let err = new libErrors.InvalidMessage( `Received message addressed to ${(message as libData.MessageRequest).dst} but this link `+ - `does not route messages` + "does not route messages" ); if (message.type === "request") { this.connector.sendResponseError( @@ -401,8 +401,8 @@ export class Link { this.connector.sendResponseError( new libData.ResponseError(err.message, err.code, err.stack), message.src, spoofedSrc ); - } catch (err: any) { - logger.error(`Unexpected error sending error response for ${message.name}:\n${err.stack}`); + } catch (subErr: any) { + logger.error(`Unexpected error sending error response for ${message.name}:\n${subErr.stack}`); } } ); @@ -527,7 +527,7 @@ export class Link { let requestId = this._nextRequestId; this._nextRequestId += 1; this._pendingRequests.set( - requestId, { request: entry, promise, resolve: resolve!, reject: reject!, dst, } + requestId, { request: entry, promise, resolve: resolve!, reject: reject!, dst } ); this.connector.sendRequest(request, requestId, dst); return promise; diff --git a/packages/lib/src/link/messages.ts b/packages/lib/src/link/messages.ts index 0f21bbd0..73868284 100644 --- a/packages/lib/src/link/messages.ts +++ b/packages/lib/src/link/messages.ts @@ -1,11 +1,10 @@ -"use strict"; import * as core from "../data/messages_core"; import * as controller from "../data/messages_controller"; import * as host from "../data/messages_host"; import * as instance from "../data/messages_instance"; import * as mod from "../data/messages_mod"; import * as user from "../data/messages_user"; -import * as subscriptions from "../subscriptions" +import * as subscriptions from "../subscriptions"; import type { RequestClass, EventClass } from "./link"; /** diff --git a/packages/lib/src/logging.ts b/packages/lib/src/logging.ts index 03b08870..0e6e6e97 100644 --- a/packages/lib/src/logging.ts +++ b/packages/lib/src/logging.ts @@ -1,4 +1,3 @@ -"use strict"; import winston from "winston"; import Transport from "winston-transport"; import { LEVEL, MESSAGE } from "triple-beam"; diff --git a/packages/lib/src/logging_utils.ts b/packages/lib/src/logging_utils.ts index 42f50045..592bae5e 100644 --- a/packages/lib/src/logging_utils.ts +++ b/packages/lib/src/logging_utils.ts @@ -4,7 +4,6 @@ * @author Hornwitser * @module lib/logging_utils */ -"use strict"; import fs from "fs-extra"; import path from "path"; import stream from "stream"; diff --git a/packages/lib/src/plugin.ts b/packages/lib/src/plugin.ts index 67623f35..de5c55c7 100644 --- a/packages/lib/src/plugin.ts +++ b/packages/lib/src/plugin.ts @@ -120,6 +120,7 @@ export class BaseInstancePlugin { message: string, expectEmpty: boolean, }[] = []; + private _sendingRconMessages = false; constructor( @@ -655,7 +656,6 @@ export class BaseControlPlugin { } - /** * Plugin supplied login form */ diff --git a/packages/lib/src/plugin_loader.ts b/packages/lib/src/plugin_loader.ts index 6a1a72bf..651a7b51 100644 --- a/packages/lib/src/plugin_loader.ts +++ b/packages/lib/src/plugin_loader.ts @@ -89,7 +89,7 @@ export async function loadControllerPluginClass( /** * Load instance plugin class of a plugin - + * * @param pluginInfo - * Plugin info object returned from {@link * loadPluginInfos} to load class from. diff --git a/packages/lib/src/prometheus.ts b/packages/lib/src/prometheus.ts index fd1ab626..5ef900e7 100644 --- a/packages/lib/src/prometheus.ts +++ b/packages/lib/src/prometheus.ts @@ -1188,7 +1188,7 @@ class HistogramChild { protected _bucketValues: Map; protected _sumValues: Map; protected _countValues: Map; - protected _key: string + protected _key: string; protected _bucketKeys: Map; constructor(collector: Histogram, key: string) { @@ -1438,6 +1438,7 @@ export class Histogram extends LabeledCollector { * Observe a given value and increment matching buckets * * Note: Only works if this is an unlabeled collector. + * @param value - number to count into histogram buckets. */ observe(value: number) { this._defaultChild!.observe(value); diff --git a/packages/lib/src/schema.ts b/packages/lib/src/schema.ts index d39416e9..de8032f4 100644 --- a/packages/lib/src/schema.ts +++ b/packages/lib/src/schema.ts @@ -22,13 +22,13 @@ export function compile(schema: JSONSchemaType) { } let doValidate: ValidateFunction; - const validate = >function (data) { + const validate = > function (data) { if (!doValidate) { doValidate = ajv.compile(schema); } let result = doValidate(data); validate.errors = doValidate.errors; return result; - } - return validate + }; + return validate; } diff --git a/packages/lib/src/shared_commands.ts b/packages/lib/src/shared_commands.ts index 7c959b93..cec55d47 100644 --- a/packages/lib/src/shared_commands.ts +++ b/packages/lib/src/shared_commands.ts @@ -2,7 +2,6 @@ * Implementation of commands shared between controller/host/ctl. * @module lib/shared_commands */ -"use strict"; import path from "path"; import * as libConfig from "./config"; diff --git a/packages/lib/src/stream.ts b/packages/lib/src/stream.ts index 5e2ab36c..315e6a13 100644 --- a/packages/lib/src/stream.ts +++ b/packages/lib/src/stream.ts @@ -1,4 +1,3 @@ -"use strict"; import assert from "assert"; import fs from "fs-extra"; import stream from "stream"; diff --git a/packages/lib/src/subscriptions.ts b/packages/lib/src/subscriptions.ts index ae346b65..1f6c149e 100644 --- a/packages/lib/src/subscriptions.ts +++ b/packages/lib/src/subscriptions.ts @@ -33,16 +33,15 @@ export class SubscriptionResponse { Type.String(), Type.Unknown(), ]), - Type.Null() - ]) + Type.Null(), + ]); toJSON() { if (this.eventReplay) { const entry = Link._eventsByClass.get(this.eventReplay.constructor)!; return [entry.name, this.eventReplay]; - } else { - return null; } + return null; } static fromJSON(json: Static): SubscriptionResponse { @@ -67,7 +66,7 @@ export class SubscriptionResponse { export class SubscriptionRequest { declare ["constructor"]: typeof SubscriptionRequest; static type = "request" as const; - static src = ["control", "instance"] as const; + static src = ["control", "instance"] as const; static dst = "controller" as const; static Response = SubscriptionResponse; static permission(user: User, message: MessageRequest) { @@ -100,7 +99,7 @@ export class SubscriptionRequest { Type.Boolean(), Type.Array(Type.Union([Type.String(), Type.Number()])), Type.Number(), - ]) + ]); toJSON() { return [this.eventName, this.allChannels, this.channels, this.lastRequestTime]; @@ -130,6 +129,9 @@ export class SubscriptionController { /** * Allow clients to subscribe to an event by telling the subscription controller to accept them * Has an optional subscription update handler which is called when any client updates their subscription + * @param Event - Event class which is sent out as updates. + * @param subscriptionUpdate - + * Optional handler called when a client updates its subscriptions. */ handle(Event: EventClass, subscriptionUpdate?: SubscriptionRequestHandler) { const entry = Link._eventsByClass.get(Event); @@ -147,6 +149,7 @@ export class SubscriptionController { /** * Broadcast an event to all subscribers of that event, will be filtered by channel if a ChannelEvent is provided + * @param event - Event to broadcast. */ broadcast(event: Event | ChannelEvent) { const entry = Link._eventsByClass.get(event.constructor); @@ -169,6 +172,11 @@ export class SubscriptionController { /** * Handle incoming event subscription requests + * @param event - incomming event. + * @param src - Source address of incomming request. + * @param dst - destination address of incomming request. + * @returns Response to subscription request. + * @internal */ async _handleRequest(event: SubscriptionRequest, src: Address, dst: Address) { if (!Link._eventsByName.has(event.eventName)) { @@ -192,7 +200,9 @@ export class SubscriptionController { onceClose = () => eventData.subscriptions.delete(link); link.connector.once("close", onceClose); } - eventData.subscriptions.set(link, { all: event.allChannels, channels: event.channels, onceClose: onceClose }); + eventData.subscriptions.set( + link, { all: event.allChannels, channels: event.channels, onceClose: onceClose }, + ); } return new SubscriptionResponse(eventReplay); } @@ -204,15 +214,15 @@ export class SubscriptionController { * Multiple handlers can be subscribed at the same time, on the same or different channels */ export class EventSubscriber { - _callbacks = new Array>() - _channelCallbacks = new Map>>() + _callbacks = new Array>(); + _channelCallbacks = new Map>>(); lastResponse: Event | null = null; lastResponseTime = 0; - control?: Link + control?: Link; constructor( private event: EventClass | ChannelEventClass, - private prehandler?: (event: T) => V, + private prehandler?: (e: T) => V, control?: Link ) { const entry = Link._eventsByClass.get(this.event); @@ -226,6 +236,8 @@ export class EventSubscriber { /** * Handle incoming events and distribute it to the correct callbacks + * @param response - event from subscribed resource + * @internal */ async _handle(response: Event | ChannelEvent) { this.lastResponse = response; @@ -246,10 +258,14 @@ export class EventSubscriber { } /** - * If a control link was not connected at creation, it can be connected here (normally during onControllerConnectionEvent) + * If a control link was not connected at creation, it can be connected + * here (normally during onControllerConnectionEvent) + * @param control - Control link to associate with. */ async connectControl(control: Link) { - if (this.control === control) return; + if (this.control === control) { + return; + } this.control = control; this.control.handle(this.event, this._handle.bind(this)); await this._updateSubscription(); @@ -257,6 +273,8 @@ export class EventSubscriber { /** * Subscribe to receive all event notifications + * @param handler - + * callback invoked whenever the subscribed resource changes. */ async subscribe(handler: EventSubscriberCallback) { this._callbacks.push(handler); @@ -265,6 +283,10 @@ export class EventSubscriber { /** * Subscribe to receive event notifications for the given channel + * @param channel - Channel to subscribe to. + * @param handler - + * callback invoked whenever the subscribed resource changes on the + * given channel. */ async subscribeToChannel(channel: string | number, handler: EventSubscriberCallback) { if (!this._channelCallbacks.get(channel)) { @@ -275,8 +297,14 @@ export class EventSubscriber { } /** - * Unsubscribe from receiving all event notifications, does not effect the subscriptions of other handlers - * Will throw an error if your handler is not subscribed to all channels, does not accept anonymous functions + * Unsubscribe from receiving all event notifications, does not effect + * the subscriptions of other handlers. + * + * @param handler - A callback previously passed to {@link subscribe} + * + * @throws {Error} + * If your handler is not subscribed to all channels, does not + * accept anonymous functions */ async unsubscribe(handler: EventSubscriberCallback) { let index = this._callbacks.lastIndexOf(handler); @@ -289,8 +317,15 @@ export class EventSubscriber { } /** - * Unsubscribe from receiving event notifications for a given channel, does not effect the subscriptions of other handlers - * Will throw an error if your handler is not subscribed to the channel, does not accept anonymous functions + * Unsubscribe from receiving event notifications for a given channel, + * does not effect the subscriptions of other handlers. + * + * @param channel - A channel previously passed to {@link subscribeToChannel} + * @param handler - A callback previously passed to {@link subscribeToChannel} + * + * @throws {Error} + * If your handler is not subscribed to the channel or does not + * accept anonymous functions */ async unsubscribeFromChannel(channel: string | number, handler: EventSubscriberCallback) { const channelCallbacks = this._channelCallbacks.get(channel); @@ -315,7 +350,9 @@ export class EventSubscriber { * Update the subscription with the controller based on current handler counts */ async _updateSubscription() { - if (!this.control || !(this.control.connector as WebSocketClientConnector).connected) return; + if (!this.control || !(this.control.connector as WebSocketClientConnector).connected) { + return; + } const entry = Link._eventsByClass.get(this.event)!; const response = await this.control.send(new SubscriptionRequest( diff --git a/packages/lib/src/users.ts b/packages/lib/src/users.ts index 5990db08..53bc91f7 100644 --- a/packages/lib/src/users.ts +++ b/packages/lib/src/users.ts @@ -6,7 +6,6 @@ * @author Hornwitser * @module lib/users */ -"use strict"; import * as libErrors from "./errors"; import PlayerStats from "./PlayerStats"; @@ -328,6 +327,7 @@ export class User { } return playerStats; } + /** * Set of users currently online in the cluster. */ diff --git a/packages/web_ui/global.d.ts b/packages/web_ui/global.d.ts index e1a04c39..2bb8472e 100644 --- a/packages/web_ui/global.d.ts +++ b/packages/web_ui/global.d.ts @@ -1,5 +1,5 @@ -declare module '*.png' { - const value: import('react-native').ImageSourcePropType; +declare module "*.png" { + const value: import("react-native").ImageSourcePropType; export default value; } diff --git a/packages/web_ui/src/components/BaseConfigTree.tsx b/packages/web_ui/src/components/BaseConfigTree.tsx index 99c8c69d..93aab9ea 100644 --- a/packages/web_ui/src/components/BaseConfigTree.tsx +++ b/packages/web_ui/src/components/BaseConfigTree.tsx @@ -103,7 +103,7 @@ export default function BaseConfigTree(props: BaseConfigTreeProps) { title="A restart is required for this setting to take effect" >; - + type ChildNode = { key: string; children: any[]; diff --git a/packages/web_ui/src/components/HostViewPage.tsx b/packages/web_ui/src/components/HostViewPage.tsx index 1d2524db..a620a9df 100644 --- a/packages/web_ui/src/components/HostViewPage.tsx +++ b/packages/web_ui/src/components/HostViewPage.tsx @@ -41,8 +41,8 @@ export default function HostViewPage() { } let hostButtons = { - account.hasPermission("core.host.revoke_access") && - { control.send(new lib.HostRevokeTokensRequest(host.id!)) .then(() => notify("Host tokens revoked")) - .catch(notifyErrorHandler(`Error revoking tokens for host id:${host.id}`)) + .catch(notifyErrorHandler(`Error revoking tokens for host id:${host.id}`)); }} > - } - + } + ; return {host["agent"]} {host["version"]} { - host.tokenValidAfter && - - {formatTimestamp(host.tokenValidAfter*1000)} + host.tokenValidAfter + && + {formatTimestamp(host.tokenValidAfter*1000)} } diff --git a/packages/web_ui/src/components/HostsPage.tsx b/packages/web_ui/src/components/HostsPage.tsx index c6123351..4816301b 100644 --- a/packages/web_ui/src/components/HostsPage.tsx +++ b/packages/web_ui/src/components/HostsPage.tsx @@ -37,7 +37,7 @@ function GenerateHostTokenButton() { }, []); async function generateToken() { - let id = undefined; + let id; let values = form.getFieldsValue(); if (values.hostId) { id = Number.parseInt(values.hostId, 10); @@ -114,12 +114,12 @@ function GenerateHostTokenButton() {

> mkdir clusterio

> cd clusterio

@@ -166,7 +166,7 @@ function CopyButton({ text, message }: { text:string, message:string }) { return result.state === "granted"; } catch (err: any) { - //If it fail because "clipboard-write" is not supported. + // If it fail because "clipboard-write" is not supported. return err.name === "TypeError"; } } @@ -229,7 +229,7 @@ export default function HostsPage() { {host.connected ? "Connected" : "Disconnected"} , sorter: (a, b) => Number(a.connected) - Number(b.connected), - } + }, ]} dataSource={hostList} rowKey={host => host.id} diff --git a/packages/web_ui/src/components/InstanceList.tsx b/packages/web_ui/src/components/InstanceList.tsx index 23e0af24..feec3335 100644 --- a/packages/web_ui/src/components/InstanceList.tsx +++ b/packages/web_ui/src/components/InstanceList.tsx @@ -99,7 +99,7 @@ export default function InstanceList(props: InstanceListProps) { responsive: ["sm"], align: "right", width: 100, - }) + }); } if (props.hideAssignedHost) { diff --git a/packages/web_ui/src/components/InstanceViewPage.tsx b/packages/web_ui/src/components/InstanceViewPage.tsx index c1ffad6c..e00fd6d4 100644 --- a/packages/web_ui/src/components/InstanceViewPage.tsx +++ b/packages/web_ui/src/components/InstanceViewPage.tsx @@ -1,7 +1,7 @@ import React, { useContext, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { Alert, Button, Descriptions, Dropdown, Menu, MenuProps, Modal, Space, Spin, Typography } from "antd"; -import type { ItemType } from 'antd/es/menu/hooks/useItems'; +import type { ItemType } from "antd/es/menu/hooks/useItems"; import DeleteOutlined from "@ant-design/icons/DeleteOutlined"; import DownOutlined from "@ant-design/icons/DownOutlined"; diff --git a/packages/web_ui/src/components/ModDetails.tsx b/packages/web_ui/src/components/ModDetails.tsx index 1506f15e..bb80b8e8 100644 --- a/packages/web_ui/src/components/ModDetails.tsx +++ b/packages/web_ui/src/components/ModDetails.tsx @@ -38,7 +38,7 @@ export default function ModDetails(props: ModDetailsProps) { {`https://mods.factorio.com/mod/${mod.name}`} - + { (mod instanceof lib.ModInfo) && <> {mod.contact && {mod.contact}} {mod.homepage && {mod.homepage}} diff --git a/packages/web_ui/src/components/ModPackViewPage.tsx b/packages/web_ui/src/components/ModPackViewPage.tsx index 25e8d57f..39ad5c06 100644 --- a/packages/web_ui/src/components/ModPackViewPage.tsx +++ b/packages/web_ui/src/components/ModPackViewPage.tsx @@ -70,7 +70,7 @@ function SearchModsTable(props: SearchModsTableProps) { const [modResultPage, setModResultPage] = useState(1); const [modResultPageSize, setModResultPageSize] = useState(10); const [modResultCount, setModResultCount] = useState(2); - const [modResultSelectedVersion, setModResultSelectedVersion] = useState>(new Map()); + const [modResultSelectedVersion, setModResultSelectedVersion] = useState>(new Map()); const factorioVersion = props.modPack.factorioVersion.split(".").slice(0, 2).join("."); @@ -216,7 +216,9 @@ function SearchModsTable(props: SearchModsTableProps) { title: "Action", key: "action", responsive: ["lg"], - render: (result:ModResult) => actions(result.versions[modResultSelectedVersion.get(result.name) || 0]), + render: (result:ModResult) => ( + actions(result.versions[modResultSelectedVersion.get(result.name) || 0]) + ), }, ]} expandable={{ @@ -294,11 +296,13 @@ function ModsTable(props: ModsTableProps) { >remove} {(deletedMods.has(mod.name) || changedMods.has(mod.name)) && { - props.onRevert && props.onRevert({ - type: deletedMods.has(mod.name) ? "mods.delete" : "mods.set", - name: mod.name, - value: mod, - }); + if (props.onRevert) { + props.onRevert({ + type: deletedMods.has(mod.name) ? "mods.delete" : "mods.set", + name: mod.name, + value: mod, + }); + } }} >revert} ; @@ -337,7 +341,9 @@ function ModsTable(props: ModsTableProps) { }); } } - const added = selectedRowKeys.filter(key => !props.modPack.mods.get(key as string)?.enabled) as string[]; + const added = selectedRowKeys.filter( + key => !props.modPack.mods.get(key as string)?.enabled + ) as string[]; const removed = [...props.modPack.mods.values()].filter( mod => mod.enabled && selectedRowKeys.indexOf(mod.name) === -1 ).map(mod => mod.name); diff --git a/packages/web_ui/src/components/RoleViewPage.tsx b/packages/web_ui/src/components/RoleViewPage.tsx index 3d4ae548..19137389 100644 --- a/packages/web_ui/src/components/RoleViewPage.tsx +++ b/packages/web_ui/src/components/RoleViewPage.tsx @@ -14,9 +14,9 @@ import { notifyErrorHandler } from "../util/notify"; export type RawRoleState = Partial & { - loading?: Boolean; - missing?: Boolean; - present?: Boolean; + loading?: boolean; + missing?: boolean; + present?: boolean; }; function useRole(id: number): [RawRoleState, () => void] { let control = useContext(ControlContext); diff --git a/packages/web_ui/src/components/SavesList.tsx b/packages/web_ui/src/components/SavesList.tsx index d69d1cb9..bc707dd3 100644 --- a/packages/web_ui/src/components/SavesList.tsx +++ b/packages/web_ui/src/components/SavesList.tsx @@ -17,7 +17,6 @@ import { useSaves } from "../model/saves"; import { notifyErrorHandler } from "../util/notify"; - type ModalProps = { disabled: boolean; save: lib.SaveDetails; @@ -150,7 +149,9 @@ function TransferModal(props: ModalProps) {