From 908a13c5da38cbaeb5c3fc6316776f903f163cc9 Mon Sep 17 00:00:00 2001 From: alyssa Date: Wed, 6 Nov 2024 08:24:56 +0000 Subject: [PATCH] port logout request --- .../main/java/online/screen/EntropyLobby.java | 10 +-- .../java/online/util/XmlBuilderClient.java | 10 --- client/src/main/java/util/MessageSender.java | 3 +- client/src/main/kotlin/http/SessionApi.kt | 8 ++ client/src/main/kotlin/util/ClientGlobals.kt | 2 +- core/src/main/java/util/XmlConstants.java | 3 - core/src/main/kotlin/http/Routes.kt | 1 + .../src/main/java/server/EntropyServer.java | 45 +--------- .../java/server/InactiveCheckRunnable.java | 86 ------------------- .../java/server/MessageHandlerRunnable.java | 20 +---- .../routes/session/SessionController.kt | 11 ++- .../kotlin/routes/session/SessionService.kt | 28 ++++++ server/src/main/kotlin/store/Store.kt | 4 + server/src/main/kotlin/util/ServerGlobals.kt | 2 + 14 files changed, 58 insertions(+), 175 deletions(-) delete mode 100644 server/src/main/java/server/InactiveCheckRunnable.java diff --git a/client/src/main/java/online/screen/EntropyLobby.java b/client/src/main/java/online/screen/EntropyLobby.java index 5937e6c..a1595aa 100644 --- a/client/src/main/java/online/screen/EntropyLobby.java +++ b/client/src/main/java/online/screen/EntropyLobby.java @@ -6,8 +6,6 @@ import http.dto.RoomSummary; import object.RoomTable; import online.util.HeartbeatRunnable; -import online.util.XmlBuilderClient; -import org.w3c.dom.Document; import screen.MainScreen; import screen.ScreenCache; import util.*; @@ -26,7 +24,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import static achievement.AchievementUtilKt.getAchievementsEarned; import static util.Images.ICON_ONLINE; public class EntropyLobby extends JFrame @@ -373,12 +370,7 @@ public void exit(boolean forceClose) if (!forceClose) { //Send a disconnect message. - Document disconnectRequest = XmlBuilderClient.factoryDisconnectRequest(username); - String messageString = XmlUtil.getStringFromDocument(disconnectRequest); - - MessageSenderParams params = new MessageSenderParams(messageString, 0, 5); - params.setExpectResponse(false); - MessageUtil.sendMessage(params, true); + ClientGlobals.sessionApi.finishSession(); } ScreenCache.get(MainScreen.class).maximise(); diff --git a/client/src/main/java/online/util/XmlBuilderClient.java b/client/src/main/java/online/util/XmlBuilderClient.java index 3bc2226..b80c84b 100644 --- a/client/src/main/java/online/util/XmlBuilderClient.java +++ b/client/src/main/java/online/util/XmlBuilderClient.java @@ -15,16 +15,6 @@ public static Document factoryHeartbeat(String username) return XmlUtil.factorySimpleMessage(username, ROOT_TAG_HEARTBEAT); } - public static Document factoryDisconnectRequest(String username) - { - Document document = XmlUtil.factoryNewDocument(); - Element rootElement = document.createElement(ROOT_TAG_DISCONNECT_REQUEST); - rootElement.setAttribute("Username", username); - - document.appendChild(rootElement); - return document; - } - public static Document factoryNewChatXml(String roomId, String username, String colour, String message) { Document document = XmlUtil.factoryNewDocument(); diff --git a/client/src/main/java/util/MessageSender.java b/client/src/main/java/util/MessageSender.java index 09571df..b35907a 100644 --- a/client/src/main/java/util/MessageSender.java +++ b/client/src/main/java/util/MessageSender.java @@ -202,7 +202,6 @@ private boolean isResponseIgnored(String xmlStr) String name = rootElement.getTagName(); - return name.equals(XmlConstants.ROOT_TAG_NEW_CHAT) - || name.equals(XmlConstants.ROOT_TAG_DISCONNECT_REQUEST); + return name.equals(XmlConstants.ROOT_TAG_NEW_CHAT); } } diff --git a/client/src/main/kotlin/http/SessionApi.kt b/client/src/main/kotlin/http/SessionApi.kt index 46b5959..22b7051 100644 --- a/client/src/main/kotlin/http/SessionApi.kt +++ b/client/src/main/kotlin/http/SessionApi.kt @@ -8,6 +8,7 @@ import javax.swing.JOptionPane import javax.swing.SwingUtilities import kong.unirest.HttpMethod import online.screen.EntropyLobby +import screen.MainScreen import screen.ScreenCache import util.ClientGlobals import util.DialogUtilNew @@ -40,6 +41,11 @@ class SessionApi(private val httpClient: HttpClient) { ) } + fun finishSession() { + httpClient.doCall(HttpMethod.POST, Routes.FINISH_SESSION) + ClientGlobals.httpClient.sessionId = null + } + private fun handleConnectSuccess(response: BeginSessionResponse) { ClientGlobals.httpClient.sessionId = response.sessionId @@ -48,6 +54,8 @@ class SessionApi(private val httpClient: HttpClient) { lobby.setLocationRelativeTo(null) lobby.isVisible = true lobby.init(response.lobby) + + ScreenCache.get().minimise() } private fun handleBeginSessionFailure(response: FailureResponse<*>) = diff --git a/client/src/main/kotlin/util/ClientGlobals.kt b/client/src/main/kotlin/util/ClientGlobals.kt index c3066e8..f6e75d4 100644 --- a/client/src/main/kotlin/util/ClientGlobals.kt +++ b/client/src/main/kotlin/util/ClientGlobals.kt @@ -17,7 +17,7 @@ object ClientGlobals { val consoleAppender = LoggingConsoleAppender(loggingConsole) val healthCheckApi = HealthCheckApi(httpClient) val devApi = DevApi(httpClient) - var sessionApi = SessionApi(httpClient) + @JvmField var sessionApi = SessionApi(httpClient) var updateManager = UpdateManager() val webSocketReceiver = WebSocketReceiver() @JvmField var achievementStore: AbstractSettingStore = DefaultSettingStore("achievements") diff --git a/core/src/main/java/util/XmlConstants.java b/core/src/main/java/util/XmlConstants.java index 074eeca..9a882ca 100644 --- a/core/src/main/java/util/XmlConstants.java +++ b/core/src/main/java/util/XmlConstants.java @@ -7,7 +7,6 @@ public interface XmlConstants { //Client public static final String ROOT_TAG_HEARTBEAT = "Heartbeat"; - public static final String ROOT_TAG_DISCONNECT_REQUEST = "DisconnectRequest"; public static final String ROOT_TAG_NEW_CHAT = "NewChat"; public static final String ROOT_TAG_ROOM_JOIN_REQUEST = "RoomJoinRequest"; public static final String ROOT_TAG_CLOSE_ROOM_REQUEST = "CloseRoomRequest"; @@ -41,6 +40,4 @@ public interface XmlConstants public static final String RESPONSE_TAG_ACKNOWLEDGEMENT = "Acknowledgement"; public static final String RESPONSE_TAG_STACK_TRACE = "StackTrace"; public static final String RESPONSE_TAG_SOCKET_TIME_OUT = "SocketTimeOut"; - - public static final String REMOVAL_REASON_FAILED_USERNAME_CHECK = "There has been an authentication error."; } diff --git a/core/src/main/kotlin/http/Routes.kt b/core/src/main/kotlin/http/Routes.kt index 1059f8a..12263cf 100644 --- a/core/src/main/kotlin/http/Routes.kt +++ b/core/src/main/kotlin/http/Routes.kt @@ -5,4 +5,5 @@ object Routes { const val DEV_COMMAND = "/dev-command" const val BEGIN_SESSION = "/begin-session" const val ACHIEVEMENT_COUNT = "/achievement-count" + const val FINISH_SESSION = "/finish-session" } diff --git a/server/src/main/java/server/EntropyServer.java b/server/src/main/java/server/EntropyServer.java index 78cacec..aeddc02 100644 --- a/server/src/main/java/server/EntropyServer.java +++ b/server/src/main/java/server/EntropyServer.java @@ -8,7 +8,6 @@ import object.Room; import object.ServerRunnable; import object.ServerThread; -import org.w3c.dom.Document; import util.*; import java.util.ArrayList; @@ -43,7 +42,6 @@ private void onStart() { Debug.append("Starting permanent threads"); - startInactiveCheckRunnable(); startListenerThreads(); Debug.appendBanner("Server is ready - accepting connections"); @@ -111,13 +109,6 @@ private void registerDefaultRooms() { Debug.append("Finished creating " + hmRoomByName.size() + " rooms"); } - private void startInactiveCheckRunnable() { - InactiveCheckRunnable runnable = new InactiveCheckRunnable(this); - - ServerThread inactiveCheckThread = new ServerThread(runnable, "InactiveCheck"); - inactiveCheckThread.start(); - } - private void startListenerThreads() { try { ServerThread listenerThread = new ServerThread(new MessageListener(this, SERVER_PORT_NUMBER)); @@ -132,37 +123,7 @@ public void executeInWorkerPool(ServerRunnable runnable) { ServerGlobals.workerPool.executeServerRunnable(runnable); } - public void removeFromUsersOnline(UserConnection usc) { - //Null these out so we don't try to send any more notifications - usc.destroyNotificationSockets(); - - //Need to remove them from rooms too - String username = usc.getName(); - if (username != null) { - ColourGenerator.freeUpColour(usc.getColour()); - - List rooms = getRooms(); - for (int i = 0; i < rooms.size(); i++) { - Room room = rooms.get(i); - room.removeFromObservers(username); - room.removePlayer(username, false); - } - - Debug.append(username + " has disconnected"); - } - - //Now remove the user connection. - ServerGlobals.INSTANCE.getUscStore().remove(usc.getIpAddress()); - if (ServerGlobals.INSTANCE.getUscStore().getAll().size() == 0 - && username != null) { - resetLobby(); - return; - } - - ServerGlobals.lobbyService.lobbyChanged(); - } - - private void resetLobby() { + public void resetLobby() { int countRemoved = 0; List rooms = getRooms(); @@ -178,10 +139,10 @@ private void resetLobby() { //Log out if we've actually removed some rooms if (countRemoved > 0) { - Debug.append("Removed " + countRemoved + " excess rooms"); + logger.info("roomsRemoved", "Removed " + countRemoved + " excess rooms"); } - Debug.append("Cleared lobby messages"); + logger.info("clearedMessages", "Cleared lobby messages"); lobbyMessages.clear(); } diff --git a/server/src/main/java/server/InactiveCheckRunnable.java b/server/src/main/java/server/InactiveCheckRunnable.java deleted file mode 100644 index dc58368..0000000 --- a/server/src/main/java/server/InactiveCheckRunnable.java +++ /dev/null @@ -1,86 +0,0 @@ -package server; - -import java.util.List; - -import auth.UserConnection; -import object.ServerRunnable; -import util.Debug; -import util.ServerGlobals; - -import static utils.CoreGlobals.logger; - -public class InactiveCheckRunnable implements ServerRunnable -{ - private static int SLEEP_TIME_MILLIS = 5 * 1000; //10 seconds - private static int KICK_OFF_TIME_MILLIS = 60 * 1000; //60 seconds - - private EntropyServer server; - private String statusText = ""; - - public InactiveCheckRunnable(EntropyServer server) - { - this.server = server; - } - - @Override - public void run() - { - while (true) - { - try - { - runInactiveCheck(); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - } - - private void runInactiveCheck() throws InterruptedException - { - List userConnections = ServerGlobals.INSTANCE.getUscStore().getAll(); - int size = userConnections.size(); - - statusText = "Running for " + size + " uscs"; - - for (int i=size-1; i>=0; i--) - { - UserConnection usc = userConnections.get(i); - String username = usc.getName(); - long lastActiveMillis = usc.getLastActive(); - long currentMillis = System.currentTimeMillis(); - long timeSinceLastActive = currentMillis - lastActiveMillis; - - if (timeSinceLastActive >= KICK_OFF_TIME_MILLIS) - { - server.removeFromUsersOnline(usc); - - if (username != null) - { - logger.info("removedInactiveUser", "Removed " + username + " due to inactivity."); - } - else - { - logger.info("removedInactiveUser", "Removed unused connection for IP " + usc.getIpAddress()); - } - } - } - - statusText = "Sleeping between checks"; - Thread.sleep(SLEEP_TIME_MILLIS); - } - - @Override - public String getDetails() - { - return statusText; - } - - @Override - public UserConnection getUserConnection() - { - return null; - } -} diff --git a/server/src/main/java/server/MessageHandlerRunnable.java b/server/src/main/java/server/MessageHandlerRunnable.java index b446c98..da6e54d 100644 --- a/server/src/main/java/server/MessageHandlerRunnable.java +++ b/server/src/main/java/server/MessageHandlerRunnable.java @@ -209,28 +209,10 @@ private Document getResponseForMessage() throws Throwable String id = root.getAttribute("RoomId"); String username = root.getAttribute("Username"); String name = root.getNodeName(); - - String usernameForThisConnection = usc.getName(); - if (usernameForThisConnection == null - || !usernameForThisConnection.equals(username)) - { - Debug.stackTrace("Failed username check for IP " + ipAddress + ": client passed up " + username - + " but connected as " + usernameForThisConnection); - Debug.appendWithoutDate("Message passed up: " + messageStr); - server.removeFromUsersOnline(usc); - - return XmlBuilderServer.getKickOffResponse(usernameForThisConnection, REMOVAL_REASON_FAILED_USERNAME_CHECK); - } - usc.setLastActiveNow(); - if (name.equals(ROOT_TAG_DISCONNECT_REQUEST)) - { - server.removeFromUsersOnline(usc); - return null; - } - else if (name.equals(ROOT_TAG_NEW_CHAT)) + if (name.equals(ROOT_TAG_NEW_CHAT)) { String newMessage = root.getAttribute("MessageText"); String colour = root.getAttribute("Colour"); diff --git a/server/src/main/kotlin/routes/session/SessionController.kt b/server/src/main/kotlin/routes/session/SessionController.kt index 64a5d17..f269c94 100644 --- a/server/src/main/kotlin/routes/session/SessionController.kt +++ b/server/src/main/kotlin/routes/session/SessionController.kt @@ -10,14 +10,13 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import routes.requiresSession -import util.ServerGlobals +import util.ServerGlobals.sessionService class SessionController { - private val sessionService = SessionService(ServerGlobals.sessionStore, ServerGlobals.uscStore) - fun installRoutes(application: Application) { application.routing { post(Routes.BEGIN_SESSION) { beginSession(call) } + post(Routes.FINISH_SESSION) { finishSession(call) } post(Routes.ACHIEVEMENT_COUNT) { updateAchievementCount(call) } } } @@ -29,6 +28,12 @@ class SessionController { call.respond(response) } + private suspend fun finishSession(call: ApplicationCall) = + requiresSession(call) { session -> + sessionService.finishSession(session) + call.respond(HttpStatusCode.NoContent) + } + private suspend fun updateAchievementCount(call: ApplicationCall) = requiresSession(call) { session -> val request = call.receive() diff --git a/server/src/main/kotlin/routes/session/SessionService.kt b/server/src/main/kotlin/routes/session/SessionService.kt index 716f0ce..85337ec 100644 --- a/server/src/main/kotlin/routes/session/SessionService.kt +++ b/server/src/main/kotlin/routes/session/SessionService.kt @@ -10,11 +10,14 @@ import http.dto.BeginSessionRequest import http.dto.BeginSessionResponse import io.ktor.http.* import java.util.* +import `object`.Room import routes.ClientException import store.Store +import util.ColourGenerator import util.OnlineConstants import util.ServerGlobals import utils.Achievement +import utils.CoreGlobals.logger class SessionService( private val sessionStore: Store, @@ -72,6 +75,31 @@ class SessionService( else nameToCheck } + fun finishSession(session: Session) { + val usc = uscStore.get(session.ip) + usc.destroyNotificationSockets() + + // Need to remove them from rooms too + ColourGenerator.freeUpColour(usc.colour) + + val rooms: List = ServerGlobals.server.getRooms() + rooms.forEach { room -> + room.removeFromObservers(usc.name) + room.removePlayer(usc.name, false) + } + + uscStore.remove(session.ip) + sessionStore.remove(session.id) + + logger.info("finishSession", "Session ended for ${usc.name}") + + if (sessionStore.count() == 0) { + ServerGlobals.server.resetLobby() + } + + ServerGlobals.lobbyService.lobbyChanged() + } + fun updateAchievementCount(session: Session, achievementCount: Int) { validateAchievementCount(achievementCount) diff --git a/server/src/main/kotlin/store/Store.kt b/server/src/main/kotlin/store/Store.kt index 82d7f62..87f5fc7 100644 --- a/server/src/main/kotlin/store/Store.kt +++ b/server/src/main/kotlin/store/Store.kt @@ -15,6 +15,8 @@ interface Store> { fun putAll(vararg items: T) + fun count(): Int + fun update(key: K, updater: (T) -> T) { val current = get(key) put(updater(current)) @@ -41,4 +43,6 @@ abstract class MemoryStore> : Store { override fun putAll(vararg items: T) { items.forEach(::put) } + + override fun count() = map.size } diff --git a/server/src/main/kotlin/util/ServerGlobals.kt b/server/src/main/kotlin/util/ServerGlobals.kt index 04efe96..fa97935 100644 --- a/server/src/main/kotlin/util/ServerGlobals.kt +++ b/server/src/main/kotlin/util/ServerGlobals.kt @@ -5,6 +5,7 @@ import java.util.* import java.util.concurrent.ArrayBlockingQueue import java.util.concurrent.TimeUnit import routes.lobby.LobbyService +import routes.session.SessionService import server.EntropyServer import store.MemoryUserConnectionStore import store.SessionStore @@ -33,4 +34,5 @@ object ServerGlobals { val server: EntropyServer = EntropyServer() @JvmField val lobbyService: LobbyService = LobbyService(server, sessionStore, uscStore) + @JvmField val sessionService = SessionService(sessionStore, uscStore) }