From bf2f4e3078c1439cfdb96358bfba51b857e15efe Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Wed, 6 Jul 2011 22:50:01 -0400 Subject: [PATCH] remove stale users after 10 minutes --- .../main/java/mage/server/ChatManager.java | 18 ++++++++ .../main/java/mage/server/ChatSession.java | 7 ++-- .../main/java/mage/server/MageServerImpl.java | 18 ++++---- .../src/main/java/mage/server/Main.java | 10 +++-- .../src/main/java/mage/server/Session.java | 13 +++--- .../main/java/mage/server/SessionManager.java | 22 ++++++---- .../src/main/java/mage/server/User.java | 31 ++++++++++++++ .../main/java/mage/server/UserManager.java | 41 ++++++++++++++++++- .../java/mage/server/game/GameSession.java | 8 +++- 9 files changed, 135 insertions(+), 33 deletions(-) diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index de23636a9e7..e48219bdf40 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -70,6 +70,24 @@ public class ChatManager { chatSessions.get(chatId).broadcast(userName, message, color); } + /** + * + * use mainly for announcing that a user connection was lost or that a user has reconnected + * + * @param userId + * @param message + * @param color + */ + public void broadcast(UUID userId, String message, MessageColor color) { + User user = UserManager.getInstance().getUser(userId); + if (user != null) { + for (ChatSession chat: chatSessions.values()) { + if (chat.hasUser(userId)) + chat.broadcast(user.getName(), message, color); + } + } + } + void removeUser(UUID userId) { for (ChatSession chat: chatSessions.values()) { chat.kill(userId); diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java index e75c1dec361..46b30182907 100644 --- a/Mage.Server/src/main/java/mage/server/ChatSession.java +++ b/Mage.Server/src/main/java/mage/server/ChatSession.java @@ -32,7 +32,6 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; -import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import mage.interfaces.callback.ClientCallback; @@ -51,8 +50,6 @@ public class ChatSession { private UUID chatId; private DateFormat timeFormatter = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT); - //TODO: use sessionId for chatting - prevents sending without being part of the chat - public ChatSession() { chatId = UUID.randomUUID(); } @@ -98,4 +95,8 @@ public class ChatSession { return chatId; } + public boolean hasUser(UUID userId) { + return clients.containsKey(userId); + } + } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 55fd4593aca..bb7910a1f97 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -253,7 +253,7 @@ public class MageServerImpl implements MageServer { new Runnable() { @Override public void run() { - SessionManager.getInstance().disconnect(sessionId); + SessionManager.getInstance().disconnect(sessionId, true); logger.info("Client deregistered ..."); } } @@ -563,8 +563,8 @@ public class MageServerImpl implements MageServer { new Runnable() { @Override public void run() { - UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); - GameManager.getInstance().sendPlayerUUID(gameId, userId, data); + User user = SessionManager.getInstance().getUser(sessionId); + user.sendPlayerUUID(gameId, data); } } ); @@ -583,8 +583,8 @@ public class MageServerImpl implements MageServer { new Runnable() { @Override public void run() { - UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); - GameManager.getInstance().sendPlayerString(gameId, userId, data); + User user = SessionManager.getInstance().getUser(sessionId); + user.sendPlayerString(gameId, data); } } ); @@ -603,8 +603,8 @@ public class MageServerImpl implements MageServer { new Runnable() { @Override public void run() { - UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); - GameManager.getInstance().sendPlayerBoolean(gameId, userId, data); + User user = SessionManager.getInstance().getUser(sessionId); + user.sendPlayerBoolean(gameId, data); } } ); @@ -623,8 +623,8 @@ public class MageServerImpl implements MageServer { new Runnable() { @Override public void run() { - UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); - GameManager.getInstance().sendPlayerInteger(gameId, userId, data); + User user = SessionManager.getInstance().getUser(sessionId); + user.sendPlayerInteger(gameId, data); } } ); diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index 75e512f6147..7437c6fe278 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -138,12 +138,13 @@ public class Main { else sessionName = session.getHost(); if (throwable instanceof ClientDisconnectedException) { + SessionManager.getInstance().disconnect(client.getSessionId(), true); logger.info("client disconnected - " + sessionName); } else { + SessionManager.getInstance().disconnect(client.getSessionId(), false); logger.info("connection to client lost - " + sessionName); } - SessionManager.getInstance().disconnect(client.getSessionId()); } } } @@ -200,9 +201,10 @@ public class Main { @Override public void removeListener(InvokerCallbackHandler callbackHandler) { - ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler; - String sessionId = handler.getCallbackClient().getSessionId(); - SessionManager.getInstance().disconnect(sessionId); + logger.fatal("removeListener called"); +// ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler; +// String sessionId = handler.getCallbackClient().getSessionId(); +// SessionManager.getInstance().disconnect(sessionId); } } diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 1dc657efa0f..0f999842585 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -93,20 +93,21 @@ public class Session { return sessionId; } - public void kill() { -// TableManager.getInstance().removeSession(sessionId); -// GameManager.getInstance().removeSession(sessionId); -// ChatManager.getInstance().removeSession(sessionId); + public void disconnect() { UserManager.getInstance().disconnect(userId); } - + + public void kill() { + UserManager.getInstance().removeUser(userId); + } + synchronized void fireCallback(final ClientCallback call) { try { call.setMessageId(messageId++); callbackHandler.handleCallbackOneway(new Callback(call)); } catch (HandleCallbackException ex) { logger.fatal("Session fireCallback error", ex); - kill(); + disconnect(); } } diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index 15f973e0a32..d6cf60c40bd 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -28,13 +28,11 @@ package mage.server; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import mage.MageException; -import mage.view.UserView; import org.apache.log4j.Logger; import org.jboss.remoting.callback.InvokerCallbackHandler; @@ -83,10 +81,13 @@ public class SessionManager { return false; } - public synchronized void disconnect(String sessionId) { + public synchronized void disconnect(String sessionId, boolean voluntary) { Session session = sessions.get(sessionId); if (session != null) { - session.kill(); + if (voluntary) + session.kill(); + else + session.disconnect(); sessions.remove(sessionId); } } @@ -101,10 +102,7 @@ public class SessionManager { public void disconnectUser(String sessionId, String userSessionId) { if (isAdmin(sessionId)) { - Session session = sessions.get(userSessionId); - if (session != null) { - session.kill(); - } + disconnect(userSessionId, true); } } @@ -122,4 +120,10 @@ public class SessionManager { return false; } + public User getUser(String sessionId) { + if (sessions.containsKey(sessionId)) { + return UserManager.getInstance().getUser(sessions.get(sessionId).getUserId()); + } + return null; + } } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 3acabe1b22d..d64102df237 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -53,6 +53,7 @@ public class User { private String sessionId = ""; private String host; private Date connectionTime = new Date(); + private Date lastActivity = new Date(); private UserState userState; private Map gameSessions = new HashMap(); @@ -133,6 +134,30 @@ public class User { fireCallback(new ClientCallback("replayGame", gameId)); } + public void sendPlayerUUID(final UUID gameId, final UUID data) { + lastActivity = new Date(); + GameManager.getInstance().sendPlayerUUID(gameId, userId, data); + } + + public void sendPlayerString(final UUID gameId, final String data) { + lastActivity = new Date(); + GameManager.getInstance().sendPlayerString(gameId, userId, data); + } + + public void sendPlayerBoolean(final UUID gameId, final Boolean data) { + lastActivity = new Date(); + GameManager.getInstance().sendPlayerBoolean(gameId, userId, data); + } + + public void sendPlayerInteger(final UUID gameId, final Integer data) { + lastActivity = new Date(); + GameManager.getInstance().sendPlayerInteger(gameId, userId, data); + } + + public boolean isExpired(Date expired) { + return userState == UserState.Disconnected && lastActivity.before(expired); + } + private void reconnect() { for (Entry entry: gameSessions.entrySet()) { gameStarted(entry.getValue().getGameId(), entry.getKey()); @@ -148,5 +173,11 @@ public class User { public void removeGame(UUID playerId) { gameSessions.remove(playerId); } + + public void kill() { + for (Entry entry: gameSessions.entrySet()) { + entry.getValue().kill(); + } + } } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index 138b7d95bae..29944af1e15 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -27,23 +27,41 @@ */ package mage.server; +import java.util.Calendar; import java.util.Collection; +import java.util.Date; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import mage.view.ChatMessage.MessageColor; /** * + * manages users - if a user is disconnected and 10 minutes have passed with no + * activity the user is removed + * * @author BetaSteward_at_googlemail.com */ public class UserManager { + protected static ScheduledExecutorService expireExecutor = Executors.newSingleThreadScheduledExecutor(); + private final static UserManager INSTANCE = new UserManager(); public static UserManager getInstance() { return INSTANCE; } - private UserManager() {} + private UserManager() { + expireExecutor.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + checkExpired(); + } + }, 60, 60, TimeUnit.SECONDS); + } private ConcurrentHashMap users = new ConcurrentHashMap(); @@ -82,6 +100,7 @@ public class UserManager { public void disconnect(UUID userId) { if (users.containsKey(userId)) { users.get(userId).setSessionId(""); + ChatManager.getInstance().broadcast(userId, "has lost connection", MessageColor.BLACK); } } @@ -91,5 +110,25 @@ public class UserManager { } return false; } + + public void removeUser(UUID userId) { + if (users.containsKey(userId)) { + users.get(userId).setSessionId(""); + ChatManager.getInstance().broadcast(userId, "has disconnected", MessageColor.BLACK); + users.get(userId).kill(); + users.remove(userId); + } + } + + private void checkExpired() { + Calendar expired = Calendar.getInstance(); + expired.add(Calendar.MINUTE, -10) ; + for (User user: users.values()) { + if (user.isExpired(expired.getTime())) { + user.kill(); + users.remove(user.getId()); + } + } + } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameSession.java b/Mage.Server/src/main/java/mage/server/game/GameSession.java index 41eec5c57eb..a386c66ac71 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSession.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSession.java @@ -210,11 +210,17 @@ public class GameSession extends GameWatcher { } public void removeGame() { - UserManager.getInstance().getUser(userId).removeGame(playerId); + User user = UserManager.getInstance().getUser(userId); + if (user != null) + user.removeGame(playerId); } public UUID getGameId() { return game.getId(); } + + public void kill() { + game.quit(playerId); + } }