Merge pull request #519 from Hornwitser/small-things-11

Small things 11
This commit is contained in:
Hornwitser authored and GitHub committed 2023-11-25 17:53:08 +01:00
commit 702c323610
12 files changed
+55 -29

No files matched your search

+2
View File
@@ -72,6 +72,8 @@ The documentation uses the binaries provided by the packages, but for the develo
npx clusteriohost -> node packages/host
npx clusterioctl -> node packages/ctl
By default node does not enable source maps, to get stack traces pointing to the `.ts` files you will need to pass `--enable-source-maps` to `node` or set the environment variable `NODE_OPTIONS=--enable-source-maps`.
Note that to use `clusterioctl` you will have to create a control config first:
node packages/controller bootstrap create-ctl-config [admin-user]
+2
View File
@@ -260,6 +260,7 @@ async function initialize(): Promise<InitializeParameters> {
levels,
});
clusterLogger.add(new DailyRotateFile({
format: winston.format.json(),
filename: "cluster-%DATE%.log",
utc: true,
dirname: path.join(args.logDirectory, "cluster"),
@@ -269,6 +270,7 @@ async function initialize(): Promise<InitializeParameters> {
logger.add(new DailyRotateFile({
format: winston.format.json(),
filename: "controller-%DATE%.log",
utc: true,
dirname: path.join(args.logDirectory, "controller"),
}));
logger.add(new winston.transports.Stream({
+1 -1
View File
@@ -265,7 +265,7 @@ export default class Controller {
if (args.dev) {
// eslint-disable-next-line node/no-missing-require
webpackConfigs.push(require("../../../webpack.config")({})); // Path outside of build
webpackConfigs.push(require("../../webpack.config")({})); // Path outside of build
}
if (args.devPlugin) {
let devPlugins = new Map();
+13 -3
View File
@@ -375,17 +375,26 @@ async function writeScripts(mode) {
if (process.platform === "win32") {
await safeOutputFile(
"run-controller.cmd",
"@echo off\n.\\node_modules\\.bin\\clusteriocontroller.cmd run\n"
`\
@echo off.
set "NODE_OPTIONS=--enable-source-maps %NODE_OPTIONS%"
\\node_modules\\.bin\\clusteriocontroller.cmd run
`
);
} else {
await safeOutputFile(
"run-controller.sh",
"#!/bin/sh\nexec ./node_modules/.bin/clusteriocontroller run\n",
`\
#!/bin/sh
export "NODE_OPTIONS=--enable-source-maps $NODE_OPTIONS"
exec ./node_modules/.bin/clusteriocontroller run
`,
{ mode: 0o755 },
);
await safeOutputFile(
"systemd/clusteriocontroller.service",
`[Unit]
`\
[Unit]
Description=Clusterio Controller
[Service]
@@ -394,6 +403,7 @@ Group=${await groupIdToName(os.userInfo().gid)}
WorkingDirectory=${process.cwd()}
KillMode=mixed
KillSignal=SIGINT
Environment=NODE_OPTIONS=--enable-source-maps
ExecStart=${process.cwd()}/node_modules/.bin/clusteriocontroller run --log-level=warn
[Install]
+9 -13
View File
@@ -214,6 +214,9 @@ class HostRouter {
);
}
logger.warn(`Failed to deliver ${(message as any).name || "message"} (${message.type}): ${err.message}`);
if (err instanceof lib.InvalidMessage && err.errors) {
logger.warn(JSON.stringify(err.errors, null, 4));
}
}
}
@@ -470,7 +473,7 @@ export default class Host extends lib.Link {
let instanceConnection = this.instanceConnections.get(instanceId);
this.send(
new lib.InstanceStatusChangedEvent(
instanceId, instanceConnection ? instanceConnection.status : "stopped", undefined
instanceId, instanceConnection ? instanceConnection.instance.status : "stopped", undefined
)
);
@@ -490,7 +493,7 @@ export default class Host extends lib.Link {
let instanceInfo = this.instanceInfos.get(instanceId);
if (instanceInfo) {
let instanceConnection = this.instanceConnections.get(instanceId);
if (instanceConnection && ["starting", "running"].includes(instanceConnection.status)) {
if (instanceConnection && ["starting", "running"].includes(instanceConnection.instance.status)) {
await instanceConnection.send(new lib.InstanceStopRequest());
}
@@ -530,10 +533,10 @@ export default class Host extends lib.Link {
let hostAddress = new lib.Address(lib.Address.host, this.config.get("host.id"));
let instanceAddress = new lib.Address(lib.Address.instance, instanceId);
let [connectionClient, connectionServer] = lib.VirtualConnector.makePair(instanceAddress, hostAddress);
let instanceConnection = new InstanceConnection(connectionServer, this, instanceId);
let instance = new Instance(
this, connectionClient, instanceInfo.path, this.config.get("host.factorio_directory"), instanceInfo.config
);
let instanceConnection = new InstanceConnection(connectionServer, this, instance);
this.instanceConnections.set(instanceId, instanceConnection);
await instance.init(this.pluginInfos);
@@ -750,13 +753,6 @@ export default class Host extends lib.Link {
});
}
async stopInstance(instanceId: number) {
let instanceConnection = this.instanceConnections.get(instanceId);
if (instanceConnection) {
await instanceConnection.send(new lib.InstanceStopRequest());
}
}
async handleInstanceDeleteInternalRequest(request: lib.InstanceDeleteInternalRequest) {
let instanceId = request.instanceId;
if (this.instanceConnections.has(instanceId)) {
@@ -786,7 +782,7 @@ export default class Host extends lib.Link {
let instanceConnection = this.instanceConnections.get(instanceId);
list.push(new lib.RawInstanceInfo(
instanceInfo.config.serialize("controller"),
instanceConnection ? instanceConnection.status : "stopped",
instanceConnection ? instanceConnection.instance.status : "stopped",
));
}
await this.send(new lib.InstancesUpdateRequest(list));
@@ -828,9 +824,9 @@ export default class Host extends lib.Link {
}
this._shuttingDown = true;
for (let instanceId of this.instanceConnections.keys()) {
for (let instanceConnection of this.instanceConnections.values()) {
try {
await this.stopInstance(instanceId);
await instanceConnection.instance.stop();
} catch (err: any) {
logger.error(`Unexpected error stopping instance:\n${err.stack}`);
}
+5 -1
View File
@@ -592,7 +592,11 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
* factorio_settings config entry.
*/
async writeServerSettings() {
let serverSettings = await this.resolveServerSettings(this.config.get("factorio.settings"));
const warning = "Changes to this file will be overwitten by the factorio.settings config on the instance.";
const serverSettings = {
"_comment_warning": warning,
...await this.resolveServerSettings(this.config.get("factorio.settings")),
};
await lib.safeOutputFile(
this.server.writePath("server-settings.json"),
JSON.stringify(serverSettings, null, 4)
+3 -5
View File
@@ -5,12 +5,11 @@ import type Instance from "./Instance";
export default class InstanceConnection extends lib.Link {
plugins = new Map<string, string>();
status: Instance["status"] = "stopped";
constructor(
connector: lib.VirtualConnector,
public host: Host,
public instanceId: number
public instance: Instance,
) {
super(connector);
this.router = this.host.router;
@@ -24,9 +23,8 @@ export default class InstanceConnection extends lib.Link {
}
async snoopInstanceStatusChangedEvent(event: lib.InstanceStatusChangedEvent) {
this.status = event.status as Instance["status"];
if (this.status === "stopped") {
this.host.instanceConnections.delete(this.instanceId);
if (this.instance.status === "stopped") {
this.host.instanceConnections.delete(this.instance.id);
}
}
}
+5
View File
@@ -11,6 +11,11 @@
* @returns sections parsed from the ini file.
*/
export function parse(input: string) {
// Ignore BOM at the start of the file
if (input[0] === "\uFEFF") {
input = input.slice(1);
}
const sections: Record<string, string | Record<string, string>> = {};
let currentSection: Record<string, string> = sections as Record<string, string>;
const lines = input.split(/\r\n|\n/);
+4 -4
View File
@@ -11,8 +11,8 @@ import type { User } from "../users";
import type { AddressType, JSONDeserialisable, MessageRoutable, MessageRequest, MessageEvent } from "../data";
export interface Request<Req, Res> {
constructor: Partial<JSONDeserialisable<Request<Req, Res>>> & {
new (...args: any): Request<Req, Res>,
constructor: Partial<JSONDeserialisable<Req & Request<Req, Res>>> & {
new (...args: any): Req & Request<Req, Res>,
name: string,
type: "request";
src: AddressType | readonly AddressType[];
@@ -25,8 +25,8 @@ export interface Request<Req, Res> {
export type RequestClass<Req, Res> = Request<Req, Res>["constructor"];
export interface Event<T> {
constructor: Partial<JSONDeserialisable<Event<T>>> & {
new (...args: any): Event<T>,
constructor: Partial<JSONDeserialisable<T & Event<T>>> & {
new (...args: any): T & Event<T>,
name: string,
type: "event";
src: AddressType | readonly AddressType[];
+2 -2
View File
@@ -215,7 +215,7 @@ export class SubscriptionController {
* Channels are an optional feature which can be implemented to only get notifications of reliant updates
* Multiple handlers can be subscribed at the same time, on the same or different channels
*/
export class EventSubscriber<T, V=T> {
export class EventSubscriber<T extends Event<T>, V=T> {
_callbacks = new Array<EventSubscriberCallback<V>>();
_channelCallbacks = new Map<string | number, Array<EventSubscriberCallback<V>>>();
lastResponse: Event<T> | null = null;
@@ -365,7 +365,7 @@ export class EventSubscriber<T, V=T> {
));
if (response.eventReplay) {
await this._handle(response.eventReplay);
await this._handle(response.eventReplay as any);
}
}
}
+2
View File
@@ -0,0 +1,2 @@
[spam]
foo=bar
+7
View File
@@ -1,5 +1,6 @@
"use strict";
const assert = require("assert").strict;
const fs = require("fs-extra");
const lib = require("@clusterio/lib");
describe("lib/ini", function() {
@@ -58,6 +59,12 @@ describe("lib/ini", function() {
new Error("Duplicated key key on line 2")
);
});
it("should parse a file with BOM", async function() {
assert.deepEqual(
lib.parse(await fs.readFile("test/file/bom.cfg", "utf8")),
{ spam: { foo: "bar" }},
);
});
});
describe("stringify()", function() {
it("should serialize to reference output", function() {