Skip to content

Commit 6a0cd8d

Browse files
authored
clientmanager: fix index mangling when removing balancer clients on balancer disconnect (#1214)
* clientmanager: fix index mangling when removing balancer clients on balancer disconnect * add a unit test
1 parent 7b1e287 commit 6a0cd8d

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

server/clientmanager.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,17 @@ function onBalancerConnect(conn: BalancerConnection) {
229229

230230
function onBalancerDisconnect(conn: BalancerConnection) {
231231
log.info(`Disconnected from balancer ${conn.id}`);
232+
// We can't immediately remove the balancer clients from the connections array because that would mess up the index of the other clients, so we have to do it later
233+
const leavingClients: BalancerClient[] = [];
232234
for (const client of connections) {
233235
if (client instanceof BalancerClient && client.conn.id === conn.id) {
234236
log.debug(`Kicking balancer client ${client.id}`);
235-
client.leave();
237+
leavingClients.push(client);
236238
}
237239
}
240+
for (const client of leavingClients) {
241+
client.leave();
242+
}
238243
}
239244

240245
async function onBalancerMessage(conn: BalancerConnection, message: MsgB2M) {

server/tests/unit/clientmanager.spec.ts

+31
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,37 @@ describe("ClientManager", () => {
117117
const joins2 = clientmanager.getClientsInRoom("foo");
118118
expect(joins2).toHaveLength(0);
119119
});
120+
121+
it("should disconnect only clients that were from the balancer when a balancer disconnects", async () => {
122+
const mockBalancerCon = new BalancerConnectionMock();
123+
const mockBalancerCon2 = new BalancerConnectionMock();
124+
balancerManager.addBalancerConnection(mockBalancerCon);
125+
balancerManager.addBalancerConnection(mockBalancerCon2);
126+
const client1 = new BalancerClient("foo", "foo1", mockBalancerCon);
127+
const client2 = new BalancerClient("foo", "foo2", mockBalancerCon);
128+
const client3 = new TestClient("foo");
129+
const client4 = new BalancerClient("foo", "bar", mockBalancerCon2);
130+
const client5 = new BalancerClient("foo", "foo2", mockBalancerCon);
131+
const clients = [client1, client2, client3, client4, client5];
132+
for (let [i, client] of clients.entries()) {
133+
clientmanager.addClient(client);
134+
client.emit("auth", client, "token" + i, { isLoggedIn: false, username: "foo" + i });
135+
}
136+
await new Promise(resolve => setTimeout(resolve, 100));
137+
const joins = clientmanager.getClientsInRoom("foo");
138+
expect(joins).toHaveLength(5);
139+
140+
mockBalancerCon.emit("disconnect", 1000, "reason");
141+
142+
expect(clientmanager.getClient(client1.id)).toBeUndefined();
143+
expect(clientmanager.getClient(client2.id)).toBeUndefined();
144+
expect(clientmanager.getClient(client3.id)).toBeDefined();
145+
expect(clientmanager.getClient(client4.id)).toBeDefined();
146+
expect(clientmanager.getClient(client5.id)).toBeUndefined();
147+
148+
const joins2 = clientmanager.getClientsInRoom("foo");
149+
expect(joins2).toHaveLength(2);
150+
});
120151
});
121152

122153
describe("BalancerManager", () => {

0 commit comments

Comments
 (0)