diff --git a/packages/controller/src/ControlConnection.ts b/packages/controller/src/ControlConnection.ts index b502429b..60f3e263 100644 --- a/packages/controller/src/ControlConnection.ts +++ b/packages/controller/src/ControlConnection.ts @@ -53,7 +53,7 @@ export default class ControlConnection extends BaseConnection { }); this.connector.on("close", () => { if (this.logTransport) { - logger.remove(this.logTransport); + this._controller.clusterLogger.remove(this.logTransport); this.logTransport = null; } if (this.ws_dumper) { @@ -1325,6 +1325,9 @@ export default class ControlConnection extends BaseConnection { } async handleDebugDumpWsRequest(request: lib.DebugDumpWsRequest) { + if (this.ws_dumper) { + return; // Already dumping + } this.ws_dumper = data => { if (this.connector.connected) { this.send(new lib.DebugWsMessageEvent(data.direction, data.content)); diff --git a/test/controller/ControlConnection.test.js b/test/controller/ControlConnection.test.js index 2ad0db9d..b97c5527 100644 --- a/test/controller/ControlConnection.test.js +++ b/test/controller/ControlConnection.test.js @@ -1,5 +1,10 @@ import assert from "node:assert/strict"; -import { ControlConnection } from "@clusterio/controller"; +import events from "node:events"; +import * as lib from "@clusterio/lib"; +import { ControlConnection, ControllerHooks } from "@clusterio/controller"; +import { MockConnector, MockLogger } from "../mock.js"; + +const addr = lib.Address.fromShorthand; describe("controller/src/ControlConnection", function() { describe(".handleControllerRestartRequest()", function() { @@ -38,4 +43,52 @@ describe("controller/src/ControlConnection", function() { assert.equal(mockController.stopped, false); }); }); + + describe("close cleanup", function() { + let connector; + let mockController; + let connection; + + beforeEach(function() { + connector = new MockConnector(addr("controller"), addr({ controlId: 1 })); + connector._socket = {}; + const transports = new Set(); + mockController = { + hooks: new ControllerHooks(new MockLogger()), + router: null, + _registeredRequests: new Map(), + _fallbackedRequests: new Map(), + _registeredEvents: new Map(), + _snoopedEvents: new Map(), + subscriptions: { unsubscribeLink() {} }, + clusterLogger: { + transports, + add(transport) { transports.add(transport); }, + remove(transport) { transports.delete(transport); }, + }, + debugEvents: new events.EventEmitter(), + sendRequestToHostByInstanceId() {}, + }; + connection = new ControlConnection({ version: "test" }, connector, mockController, {}, 1); + }); + + it("removes the log transport from clusterLogger", async function() { + await connection.handleLogSetSubscriptionsRequest( + new lib.LogSetSubscriptionsRequest(true, false, [], []) + ); + assert.equal(mockController.clusterLogger.transports.size, 1); + connector.emit("close"); + assert.equal(mockController.clusterLogger.transports.size, 0); + assert.equal(connection.logTransport, null); + }); + + it("removes the debug dump listener after repeated requests", async function() { + await connection.handleDebugDumpWsRequest(new lib.DebugDumpWsRequest()); + await connection.handleDebugDumpWsRequest(new lib.DebugDumpWsRequest()); + assert.equal(mockController.debugEvents.listenerCount("message"), 1); + assert.equal(connector._socket.clusterio_ignore_dump, true); + connector.emit("close"); + assert.equal(mockController.debugEvents.listenerCount("message"), 0); + }); + }); });