Move filepath into config class

This commit is contained in:
Cooldude2606 committed 2025-05-12 21:30:48 +01:00
1 parent c650f42276
commit 17db53403a
12 files changed
+51 -62

No files matched your search

+5 -12
View File
@@ -210,7 +210,6 @@ interface InitializeParameters {
shouldRun: boolean;
clusterLogger: winston.Logger;
pluginInfos: lib.PluginNodeEnvInfo[] | null;
controllerConfigPath: string | null;
controllerConfig: lib.ControllerConfig | null;
}
@@ -334,7 +333,6 @@ async function initialize(): Promise<InitializeParameters> {
shouldRun,
clusterLogger,
pluginInfos: null,
controllerConfigPath: null,
controllerConfig: null,
};
}
@@ -344,17 +342,17 @@ async function initialize(): Promise<InitializeParameters> {
lib.registerPluginMessages(pluginInfos);
lib.addPluginConfigFields(pluginInfos);
let controllerConfig;
const controllerConfigPath = args.config;
logger.info(`Loading config from ${controllerConfigPath}`);
let controllerConfig = new lib.ControllerConfig("controller");
try {
let jsonConfig = JSON.parse(await fs.readFile(controllerConfigPath, { encoding: "utf8" }));
controllerConfig = lib.ControllerConfig.fromJSON(jsonConfig, "controller");
controllerConfig = lib.ControllerConfig.fromJSON(jsonConfig, "controller", controllerConfigPath);
} catch (err: any) {
if (err.code === "ENOENT") {
logger.info("Config not found, initializing new config");
controllerConfig = new lib.ControllerConfig("controller");
controllerConfig = new lib.ControllerConfig("controller", undefined, controllerConfigPath);
} else {
throw new lib.StartupError(`Failed to load ${controllerConfigPath}: ${err.message}`);
@@ -374,9 +372,7 @@ async function initialize(): Promise<InitializeParameters> {
}
if (command === "config") {
await lib.handleConfigCommand(
args, controllerConfig, controllerConfigPath
);
await lib.handleConfigCommand(args, controllerConfig);
} else if (command === "bootstrap") {
await handleBootstrapCommand(args, controllerConfig);
@@ -386,7 +382,6 @@ async function initialize(): Promise<InitializeParameters> {
args,
clusterLogger,
pluginInfos,
controllerConfigPath,
controllerConfig,
shouldRun,
};
@@ -402,17 +397,15 @@ async function startup() {
shouldRun,
clusterLogger,
pluginInfos,
controllerConfigPath,
controllerConfig,
} = await initialize();
if (!shouldRun || !pluginInfos || !controllerConfigPath || !controllerConfig) {
if (!shouldRun || !pluginInfos || !controllerConfig) {
return;
}
controller = new Controller(
clusterLogger,
pluginInfos,
controllerConfigPath,
controllerConfig,
Boolean(args.canRestart),
Boolean(args.recovery),
+1 -4
View File
@@ -50,7 +50,6 @@ export default class Controller {
clusterLogger: winston.Logger;
/** Array of plugin info objects for known plugins */
pluginInfos: lib.PluginNodeEnvInfo[];
configPath: string;
/** Controller config. */
config: lib.ControllerConfig;
app: Application;
@@ -155,7 +154,6 @@ export default class Controller {
constructor(
clusterLogger: winston.Logger,
pluginInfos: lib.PluginNodeEnvInfo[],
configPath: string,
config: lib.ControllerConfig,
/**
@@ -184,7 +182,6 @@ export default class Controller {
) {
this.clusterLogger = clusterLogger;
this.pluginInfos = pluginInfos;
this.configPath = configPath;
this.config = config;
this.app = express();
@@ -586,7 +583,7 @@ export default class Controller {
private async _saveDataInternal() {
if (this.config.dirty) {
this.config.dirty = false;
await lib.safeOutputFile(this.configPath, JSON.stringify(this.config, null, "\t"));
await lib.safeOutputFile(this.config.filepath!, JSON.stringify(this.config, null, "\t"));
}
await Promise.all([
+6 -5
View File
@@ -209,16 +209,17 @@ async function startControl() {
.parse() as CtlArguments
;
logger.verbose(`Loading config from ${args.config}`);
let controlConfig;
const controlConfigPath = args.config;
logger.verbose(`Loading config from ${controlConfigPath}`);
try {
const jsonConfig = JSON.parse(await fs.readFile(args.config, "utf8"));
controlConfig = lib.ControlConfig.fromJSON(jsonConfig, "control");
const jsonConfig = JSON.parse(await fs.readFile(controlConfigPath, "utf8"));
controlConfig = lib.ControlConfig.fromJSON(jsonConfig, "control", controlConfigPath);
} catch (err: any) {
if (err.code === "ENOENT") {
logger.verbose("Config not found, initializing new config");
controlConfig = new lib.ControlConfig("control");
controlConfig = new lib.ControlConfig("control", undefined, controlConfigPath);
} else {
throw new lib.StartupError(`Failed to load ${args.config}: ${err.message}`);
@@ -232,7 +233,7 @@ async function startControl() {
// Handle the control-config command before trying to connect.
if (args._[0] === "control-config") {
await lib.handleConfigCommand(args, controlConfig, args.config);
await lib.handleConfigCommand(args, controlConfig);
return;
}
+6 -6
View File
@@ -167,16 +167,17 @@ async function startHost() {
lib.registerPluginMessages(pluginInfos);
lib.addPluginConfigFields(pluginInfos);
logger.info(`Loading config from ${args.config}`);
let hostConfig;
const hostConfigPath = args.config;
logger.info(`Loading config from ${hostConfigPath}`);
try {
const jsonConfig = JSON.parse(await fs.readFile(args.config, "utf8"));
hostConfig = lib.HostConfig.fromJSON(jsonConfig, "host");
const jsonConfig = JSON.parse(await fs.readFile(hostConfigPath, "utf8"));
hostConfig = lib.HostConfig.fromJSON(jsonConfig, "host", hostConfigPath);
} catch (err: any) {
if (err.code === "ENOENT") {
logger.info("Config not found, initializing new config");
hostConfig = new lib.HostConfig("host");
hostConfig = new lib.HostConfig("host", undefined, hostConfigPath);
} else {
throw new lib.StartupError(`Failed to load ${args.config}: ${err.message}`);
@@ -186,7 +187,7 @@ async function startHost() {
hostConfig.set("host.version", version); // Allows tracking last loaded version
if (command === "config") {
await lib.handleConfigCommand(args, hostConfig, args.config);
await lib.handleConfigCommand(args, hostConfig);
return;
}
@@ -229,7 +230,6 @@ async function startHost() {
let hostConnector = new HostConnector(hostConfig, tlsCa, pluginInfos);
host = new Host(
hostConnector,
args.config,
hostConfig,
tlsCa,
pluginInfos,
+5 -10
View File
@@ -48,14 +48,14 @@ async function discoverInstances(instancesDir: string) {
try {
const jsonConfig = JSON.parse(await fs.readFile(configPath, "utf8"));
instanceConfig = lib.InstanceConfig.fromJSON(jsonConfig, "host");
instanceConfig = lib.InstanceConfig.fromJSON(jsonConfig, "host", configPath);
} catch (err: any) {
if (err.code === "ENOENT") {
continue; // Ignore folders without config.json
}
logger.error(`Error occured while parsing ${configPath}: ${err.message}`);
logger.error(`Error occurred while parsing ${configPath}: ${err.message}`);
continue;
}
@@ -258,7 +258,6 @@ export default class Host extends lib.Link {
*/
tlsCa?: string;
pluginInfos: lib.PluginNodeEnvInfo[];
configPath: string;
config: lib.HostConfig;
/** Mapping of plugin name to loaded plugin */
@@ -289,7 +288,6 @@ export default class Host extends lib.Link {
constructor(
connector: HostConnector,
hostConfigPath: string,
hostConfig: lib.HostConfig,
tlsCa: string | undefined,
pluginInfos: lib.PluginNodeEnvInfo[],
@@ -309,7 +307,6 @@ export default class Host extends lib.Link {
this.tlsCa = tlsCa;
this.pluginInfos = pluginInfos;
this.configPath = hostConfigPath;
this.config = hostConfig;
this.config.on("fieldChanged", (name, curr, prev) => {
@@ -659,6 +656,7 @@ export default class Host extends lib.Link {
instanceConfig.update(config, false, "controller");
let instanceDir = await this._createNewInstanceDir(instanceConfig.get("instance.name"));
instanceConfig.filepath = path.join(instanceDir, "instance.json");
logger.info(`Creating ${instanceDir}`);
await Instance.populate_folders(instanceDir);
@@ -701,10 +699,7 @@ export default class Host extends lib.Link {
_warning: "Changes to this file will be overwritten by the controller's copy.",
...instanceInfo.config.toJSON(),
};
await lib.safeOutputFile(
path.join(instanceInfo.path, "instance.json"),
JSON.stringify(warnedOutput, null, "\t")
);
await lib.safeOutputFile(instanceInfo.config.filepath!, JSON.stringify(warnedOutput, null, "\t"));
}
async handleInstanceUnassignInternalRequest(request: lib.InstanceUnassignInternalRequest) {
@@ -1157,7 +1152,7 @@ export default class Host extends lib.Link {
}
logger.info("Saving config");
await lib.safeOutputFile(this.configPath, JSON.stringify(this.config, null, "\t"));
await lib.safeOutputFile(this.config.filepath!, JSON.stringify(this.config, null, "\t"));
for (const instanceInfo of this.instanceInfos.values()) {
// Save in case host_assigned_game_port changed in the config.
await this.saveInstanceConfig(instanceInfo);
+10 -4
View File
@@ -201,8 +201,9 @@ export class Config<
/** Defines the default access locations for the config class */
static defaultAccess: ConfigLocation[] = ["controller", "host", "control"];
fields: Fields;
_unknownFields: Record<string, FieldValue> = {};
/** Contains the fields and their values */
private fields: Fields;
private _unknownFields: Record<string, FieldValue> = {};
/** Set to true when a field in the config is changed. */
dirty = false;
@@ -213,13 +214,16 @@ export class Config<
* Create a new instance of the given config
*
* @param location -
* Location to evaluate access for this instance from
* Location to evaluate access for this instance from.
* @param fields -
* Serialized representation of fields to load.
* @param filepath -
* Filepath for the config to save to.
*/
constructor(
public location: ConfigLocation,
fields?: Static<typeof Config.jsonSchema>,
public filepath?: string,
) {
if (typeof location !== "string") {
throw new Error("location must be a string");
@@ -306,11 +310,13 @@ export class Config<
*
* @param json - Serialized config to load.
* @param location - Location used for access control.
* @param filepath - Filepath for the config to save to.
* @returns Instance of this config
*/
static fromJSON(
json: Static<typeof this.jsonSchema>,
location: ConfigLocation,
filepath?: string,
) {
// migrate: Pre alpha 14 config format
if (typeof json === "object" && json !== null && json.groups instanceof Array) {
@@ -326,7 +332,7 @@ export class Config<
if (!valid) {
throw new Error("Invalid config");
}
return new this(location, json);
return new this(location, json, filepath);
}
toJSON() {
+6 -4
View File
@@ -3,6 +3,8 @@ import * as classes from "./classes";
import type { PluginNodeEnvInfo, PluginWebpackEnvInfo } from "../plugin";
import { Static } from "@sinclair/typebox";
type configFromJSON<T> = (...args: Parameters<typeof classes.Config.fromJSON>) => T;
export interface ControllerConfigFields {
"controller.version": string;
"controller.name": string;
@@ -36,7 +38,7 @@ export interface ControllerConfigFields {
* @extends classes.Config
*/
export class ControllerConfig extends classes.Config<ControllerConfigFields> {
declare static fromJSON: (json: classes.ConfigSchema, location: classes.ConfigLocation) => ControllerConfig;
declare static fromJSON: configFromJSON<ControllerConfig>;
static migrations(config: Static<typeof this.jsonSchema>) {
if (config.hasOwnProperty("controller.external_address")) {
config["controller.public_url"] = config["controller.external_address"];
@@ -243,7 +245,7 @@ export interface HostConfigFields {
* @extends classes.Config
*/
export class HostConfig extends classes.Config<HostConfigFields> {
declare static fromJSON: (json: classes.ConfigSchema, location: classes.ConfigLocation) => HostConfig;
declare static fromJSON: configFromJSON<HostConfig>;
static fieldDefinitions: classes.ConfigDefs<HostConfigFields> = {
"host.version": {
type: "string",
@@ -375,7 +377,7 @@ export interface InstanceConfigFields {
* @extends classes.Config
*/
export class InstanceConfig extends classes.Config<InstanceConfigFields> {
declare static fromJSON: (json: classes.ConfigSchema, location: classes.ConfigLocation) => InstanceConfig;
declare static fromJSON: configFromJSON<InstanceConfig>;
static migrations(config: Static<typeof this.jsonSchema>) {
function boolToEnableDisable(name: string) {
if (config.hasOwnProperty(name) && typeof config[name] === "boolean") {
@@ -568,7 +570,7 @@ export interface ControlConfigFields {
* @extends classes.Config
*/
export class ControlConfig extends classes.Config<ControlConfigFields> {
declare static fromJSON: (json: classes.ConfigSchema, location: classes.ConfigLocation) => ControlConfig;
declare static fromJSON: configFromJSON<ControlConfig>;
static fieldDefinitions: classes.ConfigDefs<ControlConfigFields> = {
"control.controller_url": {
description: "URL to connect to the controller at",
+1 -2
View File
@@ -135,7 +135,6 @@ export function configCommand(yargs: any) {
export async function handleConfigCommand(
args: Record<string, unknown>,
instance: libConfig.Config<any>,
configPath: string
) {
let command = (args._ as string[])[1];
@@ -165,7 +164,7 @@ export async function handleConfigCommand(
try {
instance.set(args.field as string, args.value);
await libFileOps.safeOutputFile(configPath, JSON.stringify(instance, null, "\t"));
await libFileOps.safeOutputFile(instance.filepath!, JSON.stringify(instance, null, "\t"));
} catch (err) {
if (err instanceof libConfig.InvalidField || err instanceof libConfig.InvalidValue) {
logger.error(err.message);
+1 -1
View File
@@ -28,7 +28,7 @@ describe("controller/src/Controller", function() {
/** @type {Controller} */
let controller, mockInstanceConfig;
before(async function() {
controller = new Controller({}, [], "", new ControllerConfig("controller"));
controller = new Controller({}, [], new ControllerConfig("controller"));
mockInstanceConfig = new MockInstanceConfig(new Map([
["instance.id", 100], ["instance.name", "test"], ["factorio.settings", []],
]));
+1 -1
View File
@@ -10,7 +10,7 @@ describe("controller/src/WsServer", function() {
before(function() {
let config = new ControllerConfig("controller");
config.set("controller.trusted_proxies", "127.0.0.0/8, ::1");
let controller = new Controller({}, [], "", config);
let controller = new Controller({}, [], config);
wsServer = controller.wsServer;
});
describe(".remoteAddr()", function() {
+7 -6
View File
@@ -10,13 +10,14 @@ const { _discoverInstances } = require("@clusterio/host/dist/node/src/Host");
describe("Host testing", function() {
describe("discoverInstances()", function() {
it("should discover test instance", async function() {
let instancePath = path.join("test", "file", "instances");
let instanceInfos = await _discoverInstances(instancePath);
const instancePath = path.join("test", "file", "instances");
const instanceInfos = await _discoverInstances(instancePath);
let referenceConfig = new lib.InstanceConfig("host");
referenceConfig.set("instance.id", 1);
referenceConfig.set("instance.name", "test");
referenceConfig.dirty = false;
const configPath = path.join(instancePath, "test", "instance.json");
const referenceConfig = new lib.InstanceConfig("host", {
"instance.id": 1,
"instance.name": "test",
}, configPath);
assert.deepEqual(instanceInfos, new Map([
[1, {
+2 -7
View File
@@ -23,7 +23,7 @@ function connectHost(controller, hostId, plugins) {
controller.wsServer.hostConnections.set(hostId, hostConnection);
const hostConfig = new lib.HostConfig("host");
hostConfig.set("host.id", hostId);
return new Host(hostSide, "invalid", hostConfig, undefined, []);
return new Host(hostSide, hostConfig, undefined, []);
}
/**
@@ -107,12 +107,7 @@ describe("Integration of link routing", function() {
let controlB;
beforeEach(function() {
controller = new Controller(
{},
[],
"invalid",
new lib.ControllerConfig("controller")
);
controller = new Controller({}, [], new lib.ControllerConfig("controller"));
hostA = connectHost(controller, 10, []);
hostB = connectHost(controller, 20, []);
instanceA1 = connectInstance(controller, hostA, 11);