diff --git a/changelog.d/257.bugfix b/changelog.d/257.bugfix new file mode 100644 index 00000000..cdf8e1ee --- /dev/null +++ b/changelog.d/257.bugfix @@ -0,0 +1 @@ +Fix an issue where the bridge bot would rejoin a room after being removed. \ No newline at end of file diff --git a/src/Bridge.ts b/src/Bridge.ts index e1be3dd6..2dae2d6b 100644 --- a/src/Bridge.ts +++ b/src/Bridge.ts @@ -180,6 +180,10 @@ export class Bridge { return this.onRoomEvent(roomId, event); }); + this.as.on("room.leave", async (roomId, event) => { + return this.onRoomLeave(roomId, event); + }); + this.as.on("room.join", async (roomId, event) => { return this.onRoomJoin(roomId, event); }); @@ -681,6 +685,20 @@ export class Bridge { } } + + private async onRoomLeave(roomId: string, event: MatrixEvent) { + if (event.state_key !== this.as.botUserId) { + // Only interested in bot leaves. + return; + } + // If the bot has left the room, we want to vape all connections for that room. + try { + await this.connectionManager?.removeConnectionsForRoom(roomId); + } catch (ex) { + log.warn(`Failed to remove connections on leave for ${roomId}`); + } + } + private async onRoomMessage(roomId: string, event: MatrixEvent) { if (!this.connectionManager) { // Not ready yet. @@ -799,7 +817,7 @@ export class Bridge { for (const connection of existingConnections) { try { if (event.content.disabled === true) { - await this.connectionManager.removeConnection(connection.roomId, connection.connectionId); + await this.connectionManager.purgeConnection(connection.roomId, connection.connectionId); } else { connection.onStateUpdate?.(event); } diff --git a/src/ConnectionManager.ts b/src/ConnectionManager.ts index cdf65c98..03989bda 100644 --- a/src/ConnectionManager.ts +++ b/src/ConnectionManager.ts @@ -387,8 +387,8 @@ export class ConnectionManager { return this.connections.find((c) => c.connectionId === connectionId && c.roomId === roomId); } - public async removeConnection(roomId: string, connectionId: string) { - const connection = this.connections.find((c) => c.connectionId === connectionId && c.roomId); + public async purgeConnection(roomId: string, connectionId: string) { + const connection = this.connections.find((c) => c.connectionId === connectionId && c.roomId == roomId); if (!connection) { throw Error("Connection not found"); } @@ -404,6 +404,16 @@ export class ConnectionManager { } } + /** + * Removes connections for a room from memory. This does NOT remove the state + * event from the room. + * @param roomId + */ + public async removeConnectionsForRoom(roomId: string) { + log.info(`Removing all connections from ${roomId}`); + this.connections = this.connections.filter((c) => c.roomId !== roomId); + } + public registerProvisioningConnection(connType: {getProvisionerDetails: (botUserId: string) => GetConnectionTypeResponseItem}) { const details = connType.getProvisionerDetails(this.as.botUserId); if (this.enabledForProvisioning[details.type]) { diff --git a/src/provisioning/provisioner.ts b/src/provisioning/provisioner.ts index 42cd6e8f..02239665 100644 --- a/src/provisioning/provisioner.ts +++ b/src/provisioning/provisioner.ts @@ -235,7 +235,7 @@ export class Provisioner { if (!connection.onRemove) { return next(new ApiError("Connection does not support removal", ErrCode.UnsupportedOperation)); } - await this.connMan.removeConnection(req.params.roomId, req.params.connectionId); + await this.connMan.purgeConnection(req.params.roomId, req.params.connectionId); res.send({ok: true}); } catch (ex) { return next(ex);