From 25e65910dd4f0ef458032a7d6729699d48e92862 Mon Sep 17 00:00:00 2001 From: Luciole <31817566+Luciole0x@users.noreply.github.com> Date: Mon, 14 Aug 2023 11:26:48 +0200 Subject: [PATCH] Controller: back to hosts, instances, modPacks, mods init to null --- packages/controller/src/BaseConnection.ts | 4 +- packages/controller/src/ControlConnection.ts | 26 +++--- packages/controller/src/Controller.ts | 86 ++++++++++---------- packages/controller/src/ControllerRouter.ts | 2 +- packages/controller/src/HostConnection.ts | 16 ++-- packages/controller/src/WsServer.ts | 4 +- 6 files changed, 67 insertions(+), 71 deletions(-) diff --git a/packages/controller/src/BaseConnection.ts b/packages/controller/src/BaseConnection.ts index b12c7e3c..4c55eb9a 100644 --- a/packages/controller/src/BaseConnection.ts +++ b/packages/controller/src/BaseConnection.ts @@ -50,7 +50,7 @@ export default class BaseConnection extends lib.Link { async handleModPackGetRequest(request: lib.ModPackGetRequest): Promise { let { id } = request; - let modPack = this._controller.modPacks.get(id); + let modPack = this._controller.modPacks!.get(id); if (!modPack) { throw new lib.RequestError(`Mod pack with ID ${id} does not exist`); } @@ -62,7 +62,7 @@ export default class BaseConnection extends lib.Link { if (id === null) { throw new lib.RequestError("Default mod pack not set on controller"); } - let modPack = this._controller.modPacks.get(id); + let modPack = this._controller.modPacks!.get(id); if (!modPack) { throw new lib.RequestError(`Default mod pack configured (${id}) does not exist`); } diff --git a/packages/controller/src/ControlConnection.ts b/packages/controller/src/ControlConnection.ts index a0a8eae5..557cd092 100644 --- a/packages/controller/src/ControlConnection.ts +++ b/packages/controller/src/ControlConnection.ts @@ -206,7 +206,7 @@ export default class ControlConnection extends BaseConnection { async handleHostListRequest(): Promise { let list = []; - for (let host of this._controller.hosts.values()) { + for (let host of this._controller.hosts!.values()) { list.push(new lib.HostDetails( host.agent, host.version, @@ -275,7 +275,7 @@ export default class ControlConnection extends BaseConnection { async handleInstanceDetailsListRequest() { let list = []; - for (let instance of this._controller.instances.values()) { + for (let instance of this._controller.instances!.values()) { list.push(new lib.InstanceDetails( instance.config.get("instance.name"), instance.id, @@ -457,7 +457,7 @@ export default class ControlConnection extends BaseConnection { } async handleModPackListRequest() { - return [...this._controller.modPacks.values()]; + return [...this._controller.modPacks!.values()]; } async handleModPackSetSubscriptionsRequest(request: lib.ModPackSetSubscriptionsRequest) { @@ -469,30 +469,30 @@ export default class ControlConnection extends BaseConnection { if (modPack.id === undefined) { throw new lib.RequestError(`Mod pack need an ID to be created`); } - if (this._controller.modPacks.has(modPack.id)) { + if (this._controller.modPacks!.has(modPack.id)) { throw new lib.RequestError(`Mod pack with ID ${modPack.id} already exist`); } - this._controller.modPacks.set(modPack.id, modPack); + this._controller.modPacks!.set(modPack.id, modPack); this._controller.modPackUpdated(modPack); } async handleModPackUpdateRequest(request: lib.ModPackUpdateRequest) { let modPack = request.modPack; - if (modPack.id === undefined || !this._controller.modPacks.has(modPack.id)) { + if (modPack.id === undefined || !this._controller.modPacks!.has(modPack.id)) { throw new lib.RequestError(`Mod pack with ID ${modPack.id} does not exist`); } - this._controller.modPacks.set(modPack.id, modPack); + this._controller.modPacks!.set(modPack.id, modPack); this._controller.modPackUpdated(modPack); } async handleModPackDeleteRequest(request: lib.ModPackDeleteRequest) { let { id } = request; - let modPack = this._controller.modPacks.get(id); + let modPack = this._controller.modPacks!.get(id); if (!modPack) { throw new lib.RequestError(`Mod pack with ID ${id} does not exist`); } modPack.isDeleted = true; - this._controller.modPacks.delete(id); + this._controller.modPacks!.delete(id); this._controller.modPackUpdated(modPack); } @@ -508,7 +508,7 @@ export default class ControlConnection extends BaseConnection { async handleModGetRequest(request: lib.ModGetRequest) { let { name, version } = request; let filename = `${name}_${version}.zip`; - let mod = this._controller.mods.get(filename); + let mod = this._controller.mods!.get(filename); if (!mod) { throw new lib.RequestError(`Mod ${filename} does not exist`); } @@ -516,7 +516,7 @@ export default class ControlConnection extends BaseConnection { } async handleModListRequest() { - return [...this._controller.mods.values()]; + return [...this._controller.mods!.values()]; } static termsMatchesMod(terms: lib.ParsedTerm[], mod: lib.ModInfo) { @@ -556,7 +556,7 @@ export default class ControlConnection extends BaseConnection { type ModVersions = { name: string, versions: lib.ModInfo[] }; let results: Map = new Map(); - for (let mod of this._controller.mods.values()) { + for (let mod of this._controller.mods!.values()) { if ( mod.factorioVersion !== factorioVersion || !ControlConnection.termsMatchesMod(query.terms, mod) @@ -615,7 +615,7 @@ export default class ControlConnection extends BaseConnection { async handleModDownloadRequest(request: lib.ModDownloadRequest) { let { name, version } = request; let filename = `${name}_${version}.zip`; - let mod = this._controller.mods.get(filename); + let mod = this._controller.mods!.get(filename); if (!mod) { throw new lib.RequestError(`Mod ${filename} does not exist`); } diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index 6e35efab..09f79563 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -52,13 +52,13 @@ export default class Controller { app: Application; /** Mapping of host id to host info */ - hosts: Map = new Map(); + hosts: Map | null = null; /** Mapping of instance id to instance info */ - instances: Map = new Map(); + instances: Map | null = null; /** Mapping of mod pack id to mod pack */ - modPacks: Map = new Map(); + modPacks: Map | null = null; /** Mapping of mod names to mod infos */ - mods: Map = new Map(); + mods: Map | null = null; /** User and roles manager for the cluster */ userManager: UserManager; @@ -189,9 +189,9 @@ export default class Controller { let databaseDirectory = this.config.get("controller.database_directory"); await fs.ensureDir(databaseDirectory); - await Controller.loadHosts(path.join(databaseDirectory, "hosts.json"), this.hosts); - await Controller.loadInstances(path.join(databaseDirectory, "instances.json"), this.instances); - await Controller.loadModPacks(path.join(databaseDirectory, "mod-packs.json"), this.modPacks); + this.hosts = await Controller.loadHosts(path.join(databaseDirectory, "hosts.json")); + this.instances = await Controller.loadInstances(path.join(databaseDirectory, "instances.json")); + this.modPacks = await Controller.loadModPacks(path.join(databaseDirectory, "mod-packs.json")); await this.userManager.load(path.join(databaseDirectory, "users.json")); let modsDirectory = this.config.get("controller.mods_directory"); @@ -201,7 +201,7 @@ export default class Controller { this.config.on("fieldChanged", (group, field, prev) => { lib.invokeHook(this.plugins, "onControllerConfigFieldChanged", group, field, prev); }); - for (let instance of this.instances.values()) { + for (let instance of this.instances!.values()) { this.addInstanceHooks(instance); } @@ -315,15 +315,15 @@ export default class Controller { } let databaseDirectory = this.config.get("controller.database_directory"); - if (this.hosts.size > 0) { + if (this.hosts) { await Controller.saveHosts(path.join(databaseDirectory, "hosts.json"), this.hosts); } - if (this.instances.size > 0) { + if (this.instances) { await Controller.saveInstances(path.join(databaseDirectory, "instances.json"), this.instances); } - if (this.modPacks.size > 0) { + if (this.modPacks) { await Controller.saveModPacks(path.join(databaseDirectory, "mod-packs.json"), this.modPacks); } @@ -350,36 +350,36 @@ export default class Controller { logger.info("Goodbye"); } - static async loadHosts(filePath: string, hosts:Map) { - hosts.clear(); - + static async loadHosts(filePath: string): Promise> { + let serialized: [number, HostInfo][]; try { - const serialized = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); - // TODO: Remove after release. - if (serialized.length && !(serialized[0] instanceof Array)) { - for (let [id, host] of serialized) { - hosts.set(id ,host) - } - } + serialized = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); } catch (err: any) { if (err.code !== "ENOENT") { throw err; } - hosts.clear(); + return new Map(); } + + // TODO: Remove after release. + if (serialized.length && !(serialized[0] instanceof Array)) { + return new Map(); // Discard old format. + } + + return new Map(serialized); } static async saveHosts(filePath: string, hosts: Map) { await lib.safeOutputFile(filePath, JSON.stringify([...hosts.entries()], null, 4)); } - static async loadInstances(filePath: string, instances: Map) { + static async loadInstances(filePath: string): Promise> { logger.info(`Loading ${filePath}`); - instances.clear(); + let instances = new Map(); try { - const serialized = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); + let serialized = JSON.parse(await fs.readFile(filePath, { encoding: "utf8" })); for (let serializedConfig of serialized) { let instanceConfig = new lib.InstanceConfig("controller"); await instanceConfig.load(serializedConfig); @@ -395,7 +395,10 @@ export default class Controller { if (err.code !== "ENOENT") { throw err; } + return new Map(); } + + return instances; } static async saveInstances(filePath: string, instances: Map) { @@ -407,31 +410,24 @@ export default class Controller { await lib.safeOutputFile(filePath, JSON.stringify(serialized, null, 4)); } - static async loadModPacks(filePath: string, modPacks: Map) { - modPacks.clear(); - + static async loadModPacks(filePath: string): Promise> { + let json; try { - const json = JSON.parse(await fs.readFile(filePath, { encoding: 'utf8' })); - - for (const modPackJson of json) { - modPacks.set( - modPackJson.id, - lib.ModPack.fromJSON(modPackJson) - ) - } - + json = JSON.parse(await fs.readFile(filePath, { encoding : "utf8" })); } catch (err: any) { if (err.code !== "ENOENT") { throw err; } + return new Map(); } + return new Map(json.map((e: any) => [e.id, lib.ModPack.fromJSON(e)])); } static async saveModPacks(filePath: string, modPacks: Map) { await lib.safeOutputFile(filePath, JSON.stringify([...modPacks.values()], null, 4)); } - static async loadModInfos(modsDirectory: string) { + static async loadModInfos(modsDirectory: string): Promise> { let mods = new Map(); for (let entry of await fs.readdir(modsDirectory, { withFileTypes: true })) { if (entry.isDirectory()) { @@ -479,14 +475,14 @@ export default class Controller { async deleteMod(name: string, version: string): Promise { let filename = `${name}_${version}.zip`; - let mod = this.mods.get(filename); + let mod = this.mods!.get(filename); if (!mod) { throw new Error(`Mod ${filename} does not exist`); } let modsDirectory = this.config.get("controller.mods_directory"); await fs.unlink(path.join(modsDirectory, filename)); - this.mods.delete(filename); + this.mods!.delete(filename); mod.isDeleted = true; this.modUpdated(mod); } @@ -595,7 +591,7 @@ export default class Controller { * @throws {module:lib.RequestError} if the instance does not exist. */ getRequestInstance(instanceId:number):InstanceInfo { - let instance = this.instances.get(instanceId); + let instance = this.instances!.get(instanceId); if (!instance) { throw new lib.RequestError(`Instance with ID ${instanceId} does not exist`); } @@ -621,7 +617,7 @@ export default class Controller { */ async instanceCreate(instanceConfig: lib.InstanceConfig): Promise { let instanceId = instanceConfig.get("instance.id"); - if (this.instances.has(instanceId)) { + if (this.instances!.has(instanceId)) { throw new lib.RequestError(`Instance with ID ${instanceId} already exists`); } @@ -652,7 +648,7 @@ export default class Controller { instanceConfig.set("factorio.settings", settings); let instance = new InstanceInfo({ config: instanceConfig, status: "unassigned" }); - this.instances.set(instanceId, instance); + this.instances!.set(instanceId, instance); await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance, null); this.addInstanceHooks(instance); return instance; @@ -723,7 +719,7 @@ export default class Controller { if (hostId !== null) { await this.sendTo({ hostId }, new lib.InstanceDeleteInternalRequest(instanceId)); } - this.instances.delete(instanceId); + this.instances!.delete(instanceId); let prev = instance.status; instance.status = "deleted"; @@ -1097,7 +1093,7 @@ export default class Controller { connection = this.wsServer.controlConnections.get(dst.id); } else if (dst.type === lib.Address.instance) { - let instance = this.instances.get(dst.id); + let instance = this.instances!.get(dst.id); if (!instance) { return; } diff --git a/packages/controller/src/ControllerRouter.ts b/packages/controller/src/ControllerRouter.ts index 744a98c9..c7337611 100644 --- a/packages/controller/src/ControllerRouter.ts +++ b/packages/controller/src/ControllerRouter.ts @@ -40,7 +40,7 @@ export default class ControllerRouter { msg = `Host ${dst.id} is offline`; } } else if (dst.type === lib.Address.instance) { - let instance = this.controller.instances.get(dst.id); + let instance = this.controller.instances!.get(dst.id); if (!instance) { msg = `Instance ${dst.id} does not exist`; } else { diff --git a/packages/controller/src/HostConnection.ts b/packages/controller/src/HostConnection.ts index 6c21855f..9f820595 100644 --- a/packages/controller/src/HostConnection.ts +++ b/packages/controller/src/HostConnection.ts @@ -45,7 +45,7 @@ export default class HostConnection extends BaseConnection { this.plugins = new Map(Object.entries(registerData.plugins)); this._checkPluginVersions(); - this._controller.hosts.set(this._id, { + this._controller.hosts!.set(this._id, { agent: this._agent, id: this._id, name: this._name, @@ -65,7 +65,7 @@ export default class HostConnection extends BaseConnection { this.connector.on("close", () => { // Update status to unknown for instances on this host. - for (let instance of this._controller.instances.values()) { + for (let instance of this._controller.instances!.values()) { if (instance.config.get("instance.assigned_host") !== this._id) { continue; } @@ -100,7 +100,7 @@ export default class HostConnection extends BaseConnection { break; case lib.Address.instance: - let instance = this._controller.instances.get(message.src.id); + let instance = this._controller.instances!.get(message.src.id); if (!instance || instance.config.get("instance.assigned_host") !== this._id) { throw new lib.InvalidMessage( `Received message with invalid src ${message.src} from ${origin}` @@ -152,7 +152,7 @@ export default class HostConnection extends BaseConnection { } async handleInstanceStatusChangedEvent(request: lib.InstanceStatusChangedEvent) { - let instance = this._controller.instances.get(request.instanceId); + let instance = this._controller.instances!.get(request.instanceId); // It's possible to get updates from an instance that does not exist // or is not assigned to the host it originated from if it was @@ -182,7 +182,7 @@ export default class HostConnection extends BaseConnection { async handleInstancesUpdateRequest(request: lib.InstancesUpdateRequest) { // Push updated instance configs - for (let instance of this._controller.instances.values()) { + for (let instance of this._controller.instances!.values()) { if (instance.config.get("instance.assigned_host") === this._id) { await this.send( new lib.InstanceAssignInternalRequest(instance.id, instance.config.serialize("host")) @@ -195,7 +195,7 @@ export default class HostConnection extends BaseConnection { let instanceConfig = new lib.InstanceConfig("controller"); await instanceConfig.load(instanceData.config as lib.SerializedConfig, "host"); - let controllerInstance = this._controller.instances.get(instanceConfig.get("instance.id")); + let controllerInstance = this._controller.instances!.get(instanceConfig.get("instance.id")); if (controllerInstance) { // Check if this instance is assigned somewhere else. if (controllerInstance.config.get("instance.assigned_host") !== this._id) { @@ -220,7 +220,7 @@ export default class HostConnection extends BaseConnection { instanceConfig.set("instance.assigned_host", this._id); let newInstance = new InstanceInfo({ config: instanceConfig, status: instanceData.status as InstanceStatus }); - this._controller.instances.set(instanceConfig.get("instance.id"), newInstance); + this._controller.instances!.set(instanceConfig.get("instance.id"), newInstance); this._controller.addInstanceHooks(newInstance); await this.send( new lib.InstanceAssignInternalRequest( @@ -283,7 +283,7 @@ export default class HostConnection extends BaseConnection { user.recalculatePlayerStats(); this._controller.userUpdated(user); - let instance = this._controller.instances.get(instanceId); + let instance = this._controller.instances!.get(instanceId); await lib.invokeHook(this._controller.plugins, "onPlayerEvent", instance, { type: event.type, name: event.name, diff --git a/packages/controller/src/WsServer.ts b/packages/controller/src/WsServer.ts index 510ac852..e1651dd0 100644 --- a/packages/controller/src/WsServer.ts +++ b/packages/controller/src/WsServer.ts @@ -273,13 +273,13 @@ ${err.stack}` connector.on("close", () => { if (this.hostConnections.get(data.id) === connection) { this.hostConnections.delete(data.id); - this.controller.hostUpdated(this.controller.hosts.get(data.id) as HostInfo); + this.controller.hostUpdated(this.controller.hosts!.get(data.id) as HostInfo); } else { logger.warn("Unlisted HostConnection closed"); } }); this.hostConnections.set(data.id, connection); - this.controller.hostUpdated(this.controller.hosts.get(data.id) as HostInfo); + this.controller.hostUpdated(this.controller.hosts!.get(data.id) as HostInfo); let src = new lib.Address(lib.Address.host, data.id); connector.ready(socket, src, sessionToken, undefined); }