From d7b3c02d5f9afe69b029bced9310080cdf6da307 Mon Sep 17 00:00:00 2001 From: Xerus <27jf@web.de> Date: Mon, 9 Sep 2019 10:29:15 +0200 Subject: [PATCH 1/3] TEMP: Work on CancelRequest --- server/src/sc/server/Lobby.kt | 6 +- .../test/sc/protocol/requests/RequestTest.kt | 102 +++++++++--------- .../client/TestLobbyClientListener.java | 41 +++++-- .../framework/sc/shared/WelcomeMessage.java | 13 ++- .../sc/networking/clients/LobbyClient.java | 3 + .../sc/protocol/requests/CancelRequest.java | 8 +- .../sc/protocol/responses/LeftGameEvent.java | 6 ++ .../responses/ProtocolErrorMessage.java | 8 ++ 8 files changed, 118 insertions(+), 69 deletions(-) diff --git a/server/src/sc/server/Lobby.kt b/server/src/sc/server/Lobby.kt index 16f68abd8..0d6385b32 100644 --- a/server/src/sc/server/Lobby.kt +++ b/server/src/sc/server/Lobby.kt @@ -54,7 +54,7 @@ class Lobby : IClientListener { source.removeClientListener(this) } - /** handle requests or moves of clients */ + /** Handle requests or moves of clients. */ @Throws(RescuableClientException::class, InvalidGameStateException::class) override fun onRequest(source: Client, callback: PacketCallback) { val packet = callback.packet @@ -109,10 +109,10 @@ class Lobby : IClientListener { room.step(packet.forced) } is CancelRequest -> if (source.isAdministrator) { + if(packet.roomId == null) + throw IllegalArgumentException("Can't cancel a game with roomId null!") val room = this.gameManager.findRoom(packet.roomId) room.cancel() - // TODO check whether all clients receive game over message - this.gameManager.games.remove(room) } is TestModeRequest -> if (source.isAdministrator) { val testMode = packet.testMode diff --git a/server/test/sc/protocol/requests/RequestTest.kt b/server/test/sc/protocol/requests/RequestTest.kt index 84bd1ab2b..3927e3ec5 100644 --- a/server/test/sc/protocol/requests/RequestTest.kt +++ b/server/test/sc/protocol/requests/RequestTest.kt @@ -1,7 +1,7 @@ package sc.protocol.requests import com.thoughtworks.xstream.XStream -import org.junit.Assert +import org.junit.Assert.* import org.junit.Before import org.junit.Test import sc.framework.plugins.RoundBasedGameInstance @@ -39,7 +39,7 @@ class RequestTest : RealServerTest() { TestHelper.waitMillis(200) player3 = connectClient("localhost", serverPort) TestHelper.waitMillis(200) - } catch (e: Exception) { + } catch(e: Exception) { // happens if port is already in use e.printStackTrace() } @@ -50,7 +50,7 @@ class RequestTest : RealServerTest() { player1.joinRoomRequest(TestPlugin.TEST_PLUGIN_UUID) TestHelper.assertEqualsWithTimeout(1, { lobby.gameManager.games.size }) - Assert.assertEquals(1, lobby.gameManager.games.iterator().next().clients.size.toLong()) + assertEquals(1, lobby.gameManager.games.iterator().next().clients.size.toLong()) } @Test @@ -58,15 +58,15 @@ class RequestTest : RealServerTest() { player1.authenticate(PASSWORD) TestHelper.waitMillis(200) val clients = lobby.clientManager.clients - Assert.assertTrue(clients[0].isAdministrator) - Assert.assertEquals(3, lobby.clientManager.clients.size.toLong()) + assertTrue(clients[0].isAdministrator) + assertEquals(3, lobby.clientManager.clients.size.toLong()) player2.authenticate("PASSWORD_FAIL_TEST") TestHelper.waitMillis(200) //Player2 got kicked - Assert.assertEquals(2, lobby.clientManager.clients.size.toLong()) - Assert.assertFalse(clients[1].isAdministrator) + assertEquals(2, lobby.clientManager.clients.size.toLong()) + assertFalse(clients[1].isAdministrator) } @Test @@ -77,11 +77,11 @@ class RequestTest : RealServerTest() { player1.addListener(listener) TestHelper.waitMillis(200) - Assert.assertNotNull(listener.response) + assertNotNull(listener.response) - Assert.assertEquals(1, lobby.gameManager.games.size.toLong()) - Assert.assertEquals(0, lobby.gameManager.games.iterator().next().clients.size.toLong()) - Assert.assertTrue(lobby.gameManager.games.iterator().next().isPauseRequested) + assertEquals(1, lobby.gameManager.games.size.toLong()) + assertEquals(0, lobby.gameManager.games.iterator().next().clients.size.toLong()) + assertTrue(lobby.gameManager.games.iterator().next().isPauseRequested) } @@ -98,8 +98,8 @@ class RequestTest : RealServerTest() { " \n" + " \n" + "") - Assert.assertEquals(PrepareGameRequest::class.java, request.javaClass) - Assert.assertEquals("Häschenschule", (request as PrepareGameRequest).slotDescriptors[0].displayName) + assertEquals(PrepareGameRequest::class.java, request.javaClass) + assertEquals("Häschenschule", (request as PrepareGameRequest).slotDescriptors[0].displayName) } @Test @@ -115,15 +115,15 @@ class RequestTest : RealServerTest() { val reservation = response.reservations[0] player1.joinPreparedGame(reservation) TestHelper.waitMillis(200) - Assert.assertEquals(1, lobby.gameManager.games.iterator().next().clients.size.toLong()) + assertEquals(1, lobby.gameManager.games.iterator().next().clients.size.toLong()) player2.joinPreparedGame(response.reservations[1]) TestHelper.waitMillis(200) - Assert.assertEquals(2, lobby.gameManager.games.iterator().next().clients.size.toLong()) + assertEquals(2, lobby.gameManager.games.iterator().next().clients.size.toLong()) player3.joinPreparedGame(response.reservations[1]) TestHelper.waitMillis(200) - Assert.assertEquals(2, lobby.clientManager.clients.size.toLong()) + assertEquals(2, lobby.clientManager.clients.size.toLong()) } @Test @@ -142,12 +142,12 @@ class RequestTest : RealServerTest() { val roles = lobby.clientManager.clients[2].roles.iterator() var hasRole = false - while (roles.hasNext()) { - if (roles.next() is ObserverRole) { + while(roles.hasNext()) { + if(roles.next() is ObserverRole) { hasRole = true } } - Assert.assertTrue(hasRole) + assertTrue(hasRole) } @Test @@ -184,25 +184,25 @@ class RequestTest : RealServerTest() { // Wait for the server to register that TestHelper.waitUntilTrue({ room.isPauseRequested }, 2000) - Assert.assertTrue(room.isPauseRequested) + assertTrue(room.isPauseRequested) val pr1 = room.slots[0].role val pr2 = room.slots[1].role - Assert.assertTrue(pr1.player.isShouldBePaused) - Assert.assertTrue(pr2.player.isShouldBePaused) + assertTrue(pr1.player.isShouldBePaused) + assertTrue(pr2.player.isShouldBePaused) // Wait for it to register // no state will be send if game is paused TestHelper.waitUntilTrue(()->listener.newStateReceived, 2000); listener.newStateReceived = false - Assert.assertTrue(TestHelper.waitUntilTrue({ p1Listener.playerEventReceived }, 2000)) + assertTrue(TestHelper.waitUntilTrue({ p1Listener.playerEventReceived }, 2000)) p1Listener.playerEventReceived = false - Assert.assertEquals(p1Listener.requests.size.toLong(), 1) - Assert.assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) + assertEquals(p1Listener.requests.size.toLong(), 1) + assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) player1.sendMessageToRoom(room.id, TestMove(1)) TestHelper.waitMillis(100) - Assert.assertEquals(room.status, GameRoom.GameStatus.OVER) + assertEquals(room.status, GameRoom.GameStatus.OVER) } @Test @@ -241,18 +241,18 @@ class RequestTest : RealServerTest() { val pr1 = room.slots[0].role val pr2 = room.slots[1].role - Assert.assertTrue(pr1.player.isShouldBePaused) - Assert.assertTrue(pr2.player.isShouldBePaused) + assertTrue(pr1.player.isShouldBePaused) + assertTrue(pr2.player.isShouldBePaused) // Wait for it to register // no state will be send if game is paused TestHelper.waitUntilTrue(()->listener.newStateReceived, 2000); listener.newStateReceived = false - Assert.assertTrue(TestHelper.waitUntilTrue({ p1Listener.playerEventReceived }, 2000)) + assertTrue(TestHelper.waitUntilTrue({ p1Listener.playerEventReceived }, 2000)) p1Listener.playerEventReceived = false - Assert.assertEquals(p1Listener.requests.size.toLong(), 1) - Assert.assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) + assertEquals(p1Listener.requests.size.toLong(), 1) + assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) // enabling this should result in a GameLogicException // player1.sendMessageToRoom(room.getId(), new TestMove(1)); @@ -292,34 +292,36 @@ class RequestTest : RealServerTest() { TestHelper.waitMillis(500) // There should not come another request - Assert.assertTrue(p1Listener.playerEventReceived) - Assert.assertNotEquals(p2Listener.requests[p2Listener.requests.size - 1].javaClass, TestTurnRequest::class.java) + assertTrue(p1Listener.playerEventReceived) + assertNotEquals(p2Listener.requests[p2Listener.requests.size - 1].javaClass, TestTurnRequest::class.java) // Should not result in a new game state - Assert.assertFalse(listener.newStateReceived) + assertFalse(listener.newStateReceived) p1Listener.playerEventReceived = false p2Listener.playerEventReceived = false listener.newStateReceived = false // Game should be deleted, because player3 send invalid move - Assert.assertEquals(0L, lobby.gameManager.games.size.toLong()) + assertEquals(0L, lobby.gameManager.games.size.toLong()) } @Test fun cancelRequest() { + val listener = TestLobbyClientListener() + player1.addListener(listener) + player1.authenticate(PASSWORD) player1.joinRoomRequest(TestPlugin.TEST_PLUGIN_UUID) player2.joinRoomRequest(TestPlugin.TEST_PLUGIN_UUID) - val listener = TestLobbyClientListener() - player1.addListener(listener) - // Wait for messages to get to server - Assert.assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isNotEmpty() }, 1000)) + // Wait for server to go + assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isNotEmpty() }, 1000)) + assertTrue(TestHelper.waitUntilTrue({ listener.roomId != null }, 2000)) - player1.send(CancelRequest(listener.roomid)) - Assert.assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isEmpty() }, 3000)) - Assert.assertEquals(0, lobby.gameManager.games.size.toLong()) + player1.send(CancelRequest(listener.roomId)) + assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isEmpty() }, 10000)) + assertEquals(0, lobby.gameManager.games.size) } @Test @@ -353,12 +355,12 @@ class RequestTest : RealServerTest() { TestHelper.waitUntilEqual(1, { lobby.gameManager.games.size }, 2000) var room = gameMgr.games.iterator().next() - Assert.assertTrue(room.slots[0].role.player.isCanTimeout) + assertTrue(room.slots[0].role.player.isCanTimeout) val req = ControlTimeoutRequest(room.id, false, 0) player1.send(req) TestHelper.waitMillis(2000) room = gameMgr.games.iterator().next() - Assert.assertFalse(room.slots[0].role.player.isCanTimeout) + assertFalse(room.slots[0].role.player.isCanTimeout) } @Test @@ -381,11 +383,11 @@ class RequestTest : RealServerTest() { splayer2.addPlayerListener(p2Listener) splayer2.displayName = "player2..." - Assert.assertFalse(room.isPauseRequested) + assertFalse(room.isPauseRequested) TestHelper.waitUntilEqual(2, { p1Listener.requests.size }, 2000) - Assert.assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) + assertEquals(p1Listener.requests[0].javaClass, WelcomeMessage::class.java) TestHelper.waitMillis(500) - Assert.assertEquals(p1Listener.requests[1].javaClass, TestTurnRequest::class.java) + assertEquals(p1Listener.requests[1].javaClass, TestTurnRequest::class.java) listener.newStateReceived = false player1.send(PauseGameRequest(room.id, true)) @@ -394,7 +396,7 @@ class RequestTest : RealServerTest() { player1.sendMessageToRoom(room.id, TestMove(42)) TestHelper.waitMillis(1000) // assert that (if the game is paused) no new gameState is send to the observers after a pending Request was received - Assert.assertFalse(listener.newStateReceived) + assertFalse(listener.newStateReceived) p1Listener.playerEventReceived = false @@ -404,8 +406,8 @@ class RequestTest : RealServerTest() { TestHelper.waitMillis(500) - Assert.assertTrue(p2Listener.playerEventReceived) - Assert.assertEquals(p2Listener.requests[p2Listener.requests.size - 1].javaClass, + assertTrue(p2Listener.playerEventReceived) + assertEquals(p2Listener.requests[p2Listener.requests.size - 1].javaClass, TestTurnRequest::class.java) } diff --git a/server/test/sc/server/client/TestLobbyClientListener.java b/server/test/sc/server/client/TestLobbyClientListener.java index 60acb3ef5..49223987b 100644 --- a/server/test/sc/server/client/TestLobbyClientListener.java +++ b/server/test/sc/server/client/TestLobbyClientListener.java @@ -18,7 +18,7 @@ public class TestLobbyClientListener implements ILobbyClientListener { public boolean errorReceived = false; public boolean newStateReceived = false; - public String roomid; + public String roomId; public Player player; public GameResult result; public PrepareGameProtocolMessage prepareGameResponse; @@ -41,27 +41,27 @@ public boolean equals(Object obj) { errorReceived == o.errorReceived && newStateReceived == o.newStateReceived && roomMessage != null && - roomMessage.equals(o.roomid); + roomMessage.equals(o.roomId); } @Override public void onNewState(String roomId, Object state) { newStateReceived = true; - this.roomid = roomId; + this.roomId = roomId; this.newState = state; } @Override public void onError(String roomId, ProtocolErrorMessage error) { errorReceived = true; - this.roomid = roomId; + this.roomId = roomId; this.errorResponse = error; } @Override public void onRoomMessage(String roomId, Object data) { roomMessageReceived = true; - this.roomid = roomId; + this.roomId = roomId; this.roomMessage = data; } @@ -74,33 +74,54 @@ public void onGamePrepared(PrepareGameProtocolMessage response) { @Override public void onGameLeft(String roomId) { gameLeftReceived = true; - this.roomid = roomId; + this.roomId = roomId; } @Override public void onGameJoined(String roomId) { gameJoinedReceived = true; - this.roomid = roomId; + this.roomId = roomId; } @Override public void onGameOver(String roomId, GameResult data) { gameOverReceived = true; - this.roomid = roomId; + this.roomId = roomId; this.result = data; } @Override public void onGamePaused(String roomId, Player nextPlayer) { gamePausedReceived = true; - this.roomid = roomId; + this.roomId = roomId; this.player = nextPlayer; } @Override public void onGameObserved(String roomId) { observedReceived = true; - this.roomid = roomId; + this.roomId = roomId; } + @Override + public String toString() { + return "TestLobbyClientListener{" + + "observedReceived=" + observedReceived + + ", gamePausedReceived=" + gamePausedReceived + + ", gameOverReceived=" + gameOverReceived + + ", gameJoinedReceived=" + gameJoinedReceived + + ", gameLeftReceived=" + gameLeftReceived + + ", gamePreparedReceived=" + gamePreparedReceived + + ", roomMessageReceived=" + roomMessageReceived + + ", errorReceived=" + errorReceived + + ", newStateReceived=" + newStateReceived + + ", roomId='" + roomId + '\'' + + ", player=" + player + + ", result=" + result + + ", prepareGameResponse=" + prepareGameResponse + + ", roomMessage=" + roomMessage + + ", errorResponse=" + errorResponse + + ", newState=" + newState + + '}'; + } } diff --git a/socha-sdk/src/framework/sc/shared/WelcomeMessage.java b/socha-sdk/src/framework/sc/shared/WelcomeMessage.java index fb7b02640..771b1845e 100644 --- a/socha-sdk/src/framework/sc/shared/WelcomeMessage.java +++ b/socha-sdk/src/framework/sc/shared/WelcomeMessage.java @@ -4,10 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import sc.protocol.responses.ProtocolMessage; -/** - * Nachricht, die zu Beginn eines Spiels an einen Client geschickt wird, - * um ihm seine Spielerfarbe mitzuteilen - */ +/** Nachricht, die zu Beginn eines Spiels an einen Client geschickt wird, um ihm seine Spielerfarbe mitzuteilen. */ @XStreamAlias(value = "welcomeMessage") public class WelcomeMessage implements ProtocolMessage { @@ -25,5 +22,11 @@ public WelcomeMessage(PlayerColor c) { public PlayerColor getPlayerColor() { return PlayerColor.valueOf(color.toUpperCase()); } - + + @Override + public String toString() { + return "WelcomeMessage{" + + "color='" + color + '\'' + + '}'; + } } diff --git a/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java b/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java index e4ecc1435..5d8dadbb6 100644 --- a/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java +++ b/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java @@ -102,9 +102,12 @@ protected final void onObject(ProtocolMessage o) { this.rooms.add(roomId); onGameJoined(roomId); } else if (o instanceof LeftGameEvent) { + logger.info("Received LeftGameEvent"); String roomId = ((LeftGameEvent) o).getRoomId(); this.rooms.remove(roomId); onGameLeft(roomId); + logger.info(listeners.toString()); + logger.info("Left " + roomId); } else if (o instanceof ProtocolErrorMessage) { ProtocolErrorMessage response = (ProtocolErrorMessage) o; diff --git a/socha-sdk/src/server-api/sc/protocol/requests/CancelRequest.java b/socha-sdk/src/server-api/sc/protocol/requests/CancelRequest.java index 3bc5c8da0..ded5319bc 100644 --- a/socha-sdk/src/server-api/sc/protocol/requests/CancelRequest.java +++ b/socha-sdk/src/server-api/sc/protocol/requests/CancelRequest.java @@ -14,5 +14,11 @@ public class CancelRequest implements ILobbyRequest { public CancelRequest(String roomId) { this.roomId = roomId; } - + + @Override + public String toString() { + return "CancelRequest{" + + "roomId='" + roomId + '\'' + + '}'; + } } diff --git a/socha-sdk/src/server-api/sc/protocol/responses/LeftGameEvent.java b/socha-sdk/src/server-api/sc/protocol/responses/LeftGameEvent.java index aad036d9e..190494c69 100644 --- a/socha-sdk/src/server-api/sc/protocol/responses/LeftGameEvent.java +++ b/socha-sdk/src/server-api/sc/protocol/responses/LeftGameEvent.java @@ -20,4 +20,10 @@ public String getRoomId() { return this.roomId; } + @Override + public String toString() { + return "LeftGameEvent{" + + "roomId='" + roomId + '\'' + + '}'; + } } diff --git a/socha-sdk/src/server-api/sc/protocol/responses/ProtocolErrorMessage.java b/socha-sdk/src/server-api/sc/protocol/responses/ProtocolErrorMessage.java index fe8e22543..6eaa3655c 100644 --- a/socha-sdk/src/server-api/sc/protocol/responses/ProtocolErrorMessage.java +++ b/socha-sdk/src/server-api/sc/protocol/responses/ProtocolErrorMessage.java @@ -27,4 +27,12 @@ public String getMessage() { return this.message; } + @Override + public String toString() { + return "ProtocolErrorMessage{" + + "originalRequest=" + originalRequest + + ", message='" + message + '\'' + + '}'; + } + } From 1a23c221592e3681fb6b7d643bb3623efe571be4 Mon Sep 17 00:00:00 2001 From: Xerus <27jf@web.de> Date: Sat, 19 Oct 2019 16:07:23 +0200 Subject: [PATCH 2/3] fix(server): update CancelRequest testing --- server/src/sc/server/Lobby.kt | 6 ++---- server/test/sc/protocol/requests/RequestTest.kt | 12 +++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/server/src/sc/server/Lobby.kt b/server/src/sc/server/Lobby.kt index 16f68abd8..ddaba1d8c 100644 --- a/server/src/sc/server/Lobby.kt +++ b/server/src/sc/server/Lobby.kt @@ -54,7 +54,7 @@ class Lobby : IClientListener { source.removeClientListener(this) } - /** handle requests or moves of clients */ + /** Handle requests or moves of clients. */ @Throws(RescuableClientException::class, InvalidGameStateException::class) override fun onRequest(source: Client, callback: PacketCallback) { val packet = callback.packet @@ -101,7 +101,6 @@ class Lobby : IClientListener { val room = this.gameManager.findRoom(packet.roomId) val slot = room.slots[packet.slot] slot.role.player.isCanTimeout = packet.activate - } is StepRequest -> // It is not checked whether there is a prior pending StepRequest if (source.isAdministrator) { @@ -109,10 +108,9 @@ class Lobby : IClientListener { room.step(packet.forced) } is CancelRequest -> if (source.isAdministrator) { + requireNotNull(packet.roomId) { "Can't cancel a game with roomId null!" } val room = this.gameManager.findRoom(packet.roomId) room.cancel() - // TODO check whether all clients receive game over message - this.gameManager.games.remove(room) } is TestModeRequest -> if (source.isAdministrator) { val testMode = packet.testMode diff --git a/server/test/sc/protocol/requests/RequestTest.kt b/server/test/sc/protocol/requests/RequestTest.kt index e85046363..3927e3ec5 100644 --- a/server/test/sc/protocol/requests/RequestTest.kt +++ b/server/test/sc/protocol/requests/RequestTest.kt @@ -308,18 +308,20 @@ class RequestTest : RealServerTest() { @Test fun cancelRequest() { + val listener = TestLobbyClientListener() + player1.addListener(listener) + player1.authenticate(PASSWORD) player1.joinRoomRequest(TestPlugin.TEST_PLUGIN_UUID) player2.joinRoomRequest(TestPlugin.TEST_PLUGIN_UUID) - val listener = TestLobbyClientListener() - player1.addListener(listener) - // Wait for messages to get to server + // Wait for server to go assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isNotEmpty() }, 1000)) + assertTrue(TestHelper.waitUntilTrue({ listener.roomId != null }, 2000)) player1.send(CancelRequest(listener.roomId)) - assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isEmpty() }, 3000)) - assertEquals(0, lobby.gameManager.games.size.toLong()) + assertTrue(TestHelper.waitUntilTrue({ lobby.gameManager.games.isEmpty() }, 10000)) + assertEquals(0, lobby.gameManager.games.size) } @Test From 2281528cfefa1acc4d8b29faabfdda2870a45153 Mon Sep 17 00:00:00 2001 From: Xerus <27jf@web.de> Date: Sat, 19 Oct 2019 17:47:14 +0200 Subject: [PATCH 3/3] feat(sdk): log game leave --- .../src/server-api/sc/networking/clients/LobbyClient.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java b/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java index a208e5961..40d84845b 100644 --- a/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java +++ b/socha-sdk/src/server-api/sc/networking/clients/LobbyClient.java @@ -103,9 +103,12 @@ protected final void onObject(ProtocolMessage o) { this.rooms.add(roomId); onGameJoined(roomId); } else if (o instanceof LeftGameEvent) { + logger.info("Received LeftGameEvent"); String roomId = ((LeftGameEvent) o).getRoomId(); this.rooms.remove(roomId); onGameLeft(roomId); + logger.info(listeners.toString()); + logger.info("Left {}", roomId); } else if (o instanceof ProtocolErrorMessage) { ProtocolErrorMessage response = (ProtocolErrorMessage) o;