Merge pull request #573 from CCpersonguy/feature/instance-version-2

Display Instance's Factorio version in the web UI
This commit is contained in:
Hornwitser authored and GitHub committed 2024-09-03 21:57:42 +02:00
commit a1856e6edf
11 files changed
+51 -11

No files matched your search

+4
View File
@@ -45,18 +45,22 @@ Many thanks to the following for contributing to this release:
- Fixed spaces passed in arguments to the installer causing it to break [#620](https://github.com/clusterio/clusterio/issues/620)
- Fixed numeric admin name breaking login [#536](https://github.com/clusterio/clusterio/issues/536)
- Added factorio.executable_path option which allows overriding the default path to the Factorio executable run.
- Added instance version display [#573](https://github.com/clusterio/clusterio/pull/573)
### Breaking Changes
- Previously silent errors for controller.sendEvent now throw exceptions [#625](https://github.com/clusterio/clusterio/pull/625).
- @clusterio/controller export InstanceInfo has added factorioVersion parameter.
Many thanks to the following for contributing to this release:
[@CCpersonguy](https://github.com/CCpersonguy)
[@Cooldude2606](https://github.com/Cooldude2606)
[@Danielv123](https://github.com/Danielv123)
[@Hornwitser](https://github.com/Hornwitser)
[@Laar](https://github.com/Laar)
[@psihius](https://github.com/psihius)
## Version 2.0.0-alpha.18
### Features
+1 -1
View File
@@ -896,7 +896,7 @@ export default class Controller {
};
instanceConfig.set("factorio.settings", settings);
let instance = new InstanceInfo(instanceConfig, "unassigned", undefined, Date.now());
let instance = new InstanceInfo(instanceConfig, "unassigned", undefined, undefined, Date.now());
this.instances.set(instanceId, instance);
this.instancesDirty = true;
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance);
@@ -188,6 +188,7 @@ export default class HostConnection extends BaseConnection {
let prev = instance.status;
instance.status = request.status;
instance.gamePort = request.gamePort;
instance.factorioVersion = request.factorioVersion;
instance.updatedAtMs = Date.now();
logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`);
this._controller.instanceDetailsUpdated([instance]);
@@ -225,6 +226,7 @@ export default class HostConnection extends BaseConnection {
let prev = controllerInstance.status;
controllerInstance.status = instanceData.status;
controllerInstance.gamePort = instanceData.gamePort;
controllerInstance.factorioVersion = instanceData.factorioVersion;
controllerInstance.updatedAtMs = Date.now();
logger.verbose(`Instance ${instanceConfig.get("instance.name")} State: ${instanceData.status}`);
instanceUpdates.push(controllerInstance);
@@ -240,6 +242,7 @@ export default class HostConnection extends BaseConnection {
instanceConfig,
instanceData.status,
instanceData.gamePort,
instanceData.factorioVersion,
Date.now(),
);
this._controller.instances.set(instanceConfig.get("instance.id"), newInstance);
+4
View File
@@ -11,6 +11,7 @@ export default class InstanceInfo {
public config: lib.InstanceConfig,
public status: lib.InstanceStatus,
public gamePort?: number,
public factorioVersion?: string,
public updatedAtMs = 0,
) {
this.config = config;
@@ -22,6 +23,7 @@ export default class InstanceInfo {
"status": lib.InstanceStatus,
"gamePort": Type.Optional(Type.Number()),
"updatedAtMs": Type.Optional(Type.Number()),
"factorioVersion": Type.Optional(Type.String()),
});
static fromJSON(json: Static<typeof this.jsonSchema>, location: lib.ConfigLocation) {
@@ -29,6 +31,7 @@ export default class InstanceInfo {
lib.InstanceConfig.fromJSON(json.config, location),
json.status,
json.gamePort,
json.factorioVersion,
json.updatedAtMs,
);
}
@@ -40,6 +43,7 @@ export default class InstanceInfo {
this.config.get("instance.assigned_host") ?? undefined,
this.gamePort,
this.status,
this.factorioVersion,
this.updatedAtMs,
);
}
+5 -1
View File
@@ -667,6 +667,9 @@ export default class Host extends lib.Link {
instanceId,
instanceConnection ? instanceConnection.instance.status : "stopped",
instanceConnection ? instanceConnection.instance.server.gamePort : this.gamePort(instanceId),
instanceConnection
? instanceConnection.instance.server.version
: instanceInfo.config.get("factorio.version"),
)
);
@@ -736,7 +739,7 @@ export default class Host extends lib.Link {
}
assignGamePort(instanceId: number) {
const availablePorts = lib.parseRanges(this.config.get("host.factorio_port_range"), 1, 2**16 - 1);
const availablePorts = lib.parseRanges(this.config.get("host.factorio_port_range"), 1, 2 ** 16 - 1);
for (const [id, instance] of this.instanceInfos) {
if (id === instanceId) {
continue;
@@ -1060,6 +1063,7 @@ export default class Host extends lib.Link {
instanceInfo.config.toRemote("controller"),
instanceConnection ? instanceConnection.instance.status : "stopped",
instanceConnection ? instanceConnection.instance.server.gamePort : this.gamePort(instanceId),
instanceConnection ? instanceConnection.instance.server.version : undefined,
));
}
await this.send(new lib.InstancesUpdateRequest(list));
+1
View File
@@ -454,6 +454,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
this.id,
status,
this.server.gamePort,
status === "running"? this.server.version : this.config.get("factorio.version"),
),
);
}
+1 -1
View File
@@ -64,7 +64,7 @@ async function generateExportMod(server: FactorioServer) {
sourceDir: path.join(__dirname, "..", "..", "..", "lua", "export"),
outputDir: server.writePath("mods"),
bumpPatch: false,
factorioVersion: server.version.replace(/\.\d+$/, ""),
factorioVersion: server.version?.replace(/\.\d+$/, ""),
dependencies,
});
}
+5 -5
View File
@@ -730,12 +730,12 @@ export class FactorioServer extends events.EventEmitter {
}
/**
* The version of Factorio in use. This will be the actual version if
* "latest" (the default) was specified as `factorioVersion` to the
* constructor.
* The version of Factorio in use. This will be the actual version if
* "latest" (the default) was specified as `factorioVersion` to the constructor.
* This will be undefined before the server is initialized, or if init failed.
*/
get version() {
return this._version!;
get version(): string | undefined {
return this._version ?? undefined;
}
/**
+9 -2
View File
@@ -42,6 +42,7 @@ export class InstanceDetails {
public assignedHost: number | undefined,
public gamePort: number | undefined,
public status: InstanceStatus,
public factorioVersion: string | undefined,
/** Millisecond Unix timestamp this entry was last updated at */
public updatedAtMs = 0,
) { }
@@ -55,6 +56,7 @@ export class InstanceDetails {
"unknown", "unassigned", "stopped", "starting", "running", "stopping",
"creating_save", "exporting_data", "deleted",
]),
"factorioVersion": Type.Optional(Type.String()),
"updatedAtMs": Type.Optional(Type.Number()),
});
@@ -65,6 +67,7 @@ export class InstanceDetails {
json.assignedHost,
json.gamePort,
json.status,
json.factorioVersion,
json.updatedAtMs,
);
}
@@ -717,6 +720,7 @@ export class HostInstanceUpdate {
public config: Static<typeof InstanceConfig.jsonSchema>,
public status: InstanceStatus,
public gamePort: undefined | number,
public factorioVersion: undefined | string,
) { }
static jsonSchema = Type.Object({
@@ -725,10 +729,11 @@ export class HostInstanceUpdate {
"stopped", "starting", "running", "stopping", "creating_save", "exporting_data",
]),
"gamePort": Type.Optional(Type.Number()),
"factorioVersion": Type.Optional(Type.String()),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(json.config, json.status, json.gamePort);
return new this(json.config, json.status, json.gamePort, json.factorioVersion);
}
}
@@ -822,6 +827,7 @@ export class InstanceStatusChangedEvent {
public instanceId: number,
public status: InstanceStatus,
public gamePort?: number,
public factorioVersion?: string,
) { }
static jsonSchema = Type.Object({
@@ -830,10 +836,11 @@ export class InstanceStatusChangedEvent {
"stopped", "starting", "running", "stopping", "creating_save", "exporting_data",
]),
"gamePort": Type.Optional(Type.Integer()),
"factorioVersion": Type.Optional(Type.String()),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(json.instanceId, json.status, json.gamePort);
return new this(json.instanceId, json.status, json.gamePort, json.factorioVersion);
}
}
@@ -9,7 +9,7 @@ import { useAccount } from "../model/account";
import { useHosts } from "../model/host";
import InstanceStatusTag from "./InstanceStatusTag";
import StartStopInstanceButton from "./StartStopInstanceButton";
import { InstanceDetails } from "@clusterio/lib";
import { InstanceDetails, integerFactorioVersion } from "@clusterio/lib";
import Link from "./Link";
const strcmp = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare;
@@ -46,6 +46,13 @@ export default function InstanceList(props: InstanceListProps) {
return `${host.publicAddress}:${instance.gamePort}`;
}
function integerFactorioVersionOrDefault(instance: InstanceDetails) {
if (instance.factorioVersion === undefined) {
return -1;
}
return integerFactorioVersion(instance.factorioVersion);
}
let columns: ColumnsType<InstanceDetails> = [
{
title: "Name",
@@ -86,6 +93,13 @@ export default function InstanceList(props: InstanceListProps) {
sorter: (a, b) => strcmp(instancePublicAddress(a), instancePublicAddress(b)),
responsive: ["lg"],
},
{
title: "Factorio Version",
key: "version",
render: (_, instance) => instance.factorioVersion ?? "unknown",
sorter: (a, b) => integerFactorioVersionOrDefault(a) - integerFactorioVersionOrDefault(b),
responsive: ["xl"],
},
{
title: "Status",
key: "status",
@@ -59,6 +59,9 @@ function InstanceDescription(props: InstanceDescriptionProps) {
buttonContent={assigned ? "Reassign" : "Assign"}
/>}
</Descriptions.Item>
<Descriptions.Item label="Version">
{instance.factorioVersion ?? "unknown"}
</Descriptions.Item>
<Descriptions.Item label="Status"><InstanceStatusTag status={instance.status!} /></Descriptions.Item>
</Descriptions>;
}