added pingInfo to user info

This commit is contained in:
betasteward 2015-06-01 10:51:20 -04:00
parent bc51a8fc79
commit 481e177d71
13 changed files with 159 additions and 24 deletions

View file

@ -84,6 +84,7 @@ import java.awt.image.BufferedImage;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -92,6 +93,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.prefs.Preferences;
import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository;
import mage.client.util.audio.AudioManager;
import mage.interfaces.ServerState;
import mage.view.ChatMessage;
@ -140,7 +143,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
private static final Map<UUID, DraftPanel> drafts = new HashMap<>();
private static final MageUI ui = new MageUI();
private static final ScheduledExecutorService pingTaskExecutor = Executors.newSingleThreadScheduledExecutor();
// private static final ScheduledExecutorService pingTaskExecutor = Executors.newSingleThreadScheduledExecutor();
private static UpdateMemUsageTask updateMemUsageTask;
private static long startTime;
@ -700,9 +703,46 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public boolean connect(Connection connection) {
client = new Client(instance);
boolean result = client.connect(connection.getUsername(), connection.getHost(), connection.getPort(), true, version);
if (result) {
updateDatabase(connection.isForceDBComparison(), serverState);
}
return result;
}
private void updateDatabase(boolean forceDBComparison, ServerState serverState) {
long cardDBVersion = CardRepository.instance.getContentVersionFromDB();
if (forceDBComparison || serverState.getCardsContentVersion() > cardDBVersion) {
List<String> classNames = CardRepository.instance.getClassNames();
List<CardInfo> cards = CardRepository.instance.getMissingCards(classNames);
CardRepository.instance.addCards(cards);
CardRepository.instance.setContentVersion(serverState.getCardsContentVersion());
logger.info("Updating client cards DB - existing cards: " + classNames.size() + " new cards: " + cards.size() +
" content versions - server: " + serverState.getCardsContentVersion() + " client: " + cardDBVersion);
}
long expansionDBVersion = ExpansionRepository.instance.getContentVersionFromDB();
if (forceDBComparison || serverState.getExpansionsContentVersion() > expansionDBVersion) {
List<String> setCodes = ExpansionRepository.instance.getSetCodes();
List<ExpansionInfo> expansions = getMissingExpansionData(setCodes);
for (ExpansionInfo expansion : expansions) {
ExpansionRepository.instance.add(expansion);
}
ExpansionRepository.instance.setContentVersion(serverState.getExpansionsContentVersion());
logger.info("Updating client expansions DB - existing sets: " + setCodes.size() + " new sets: " + expansions.size()+
" content versions - server: " + serverState.getExpansionsContentVersion() + " client: " + expansionDBVersion);
}
}
private List<ExpansionInfo> getMissingExpansionData(List<String> codes) {
List<ExpansionInfo> result = new ArrayList<>();
for (ExpansionInfo expansionInfo : ExpansionRepository.instance.getAll()) {
if (!codes.contains(expansionInfo.getCode())) {
result.add(expansionInfo);
}
}
return result;
}
// public static boolean stopConnecting() {
// return session.stopConnecting();
// }

View file

@ -216,7 +216,7 @@ public class Client {
}
public String getSessionId() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
return channel.id().asLongText();
}
public TableView createTournamentTable(UUID roomId, TournamentOptions tOptions) {

View file

@ -36,6 +36,7 @@ import org.mage.network.handlers.server.ServerMessageHandler;
import org.mage.network.interfaces.MageServer;
import org.mage.network.model.InformClientMessage;
import org.mage.network.model.MessageType;
import org.mage.network.model.PingMessage;
import org.mage.network.model.ReceiveChatMessage;
/**
@ -48,12 +49,13 @@ public class Server {
private static final int IDLE_PING_TIME = 30;
private static final int IDLE_TIMEOUT = 60;
private static final PingMessage ping = new PingMessage();
public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
private SslContext sslCtx;
private final HeartbeatHandler heartbeatHandler;
private final MageServer server;
private final PingMessageHandler pingMessageHandler = new PingMessageHandler();
private final EventExecutorGroup handlersExecutor = new DefaultEventExecutorGroup(Runtime.getRuntime().availableProcessors() * 2);
private final RegisterClientMessageHandler registerClientMessageHandler;
@ -66,7 +68,7 @@ public class Server {
private final RoomMessageHandler roomMessageHandler;
public Server(MageServer server) {
heartbeatHandler = new HeartbeatHandler(server);
this.server = server;
registerClientMessageHandler = new RegisterClientMessageHandler(server);
chatMessageHandler = new ChatMessageHandler(server);
joinChatMessageHandler = new JoinChatMessageHandler(server);
@ -117,18 +119,18 @@ public class Server {
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(IDLE_TIMEOUT, IDLE_PING_TIME, 0));
ch.pipeline().addLast(handlersExecutor, heartbeatHandler);
ch.pipeline().addLast(handlersExecutor, "heartbeatHandler", new HeartbeatHandler(server));
ch.pipeline().addLast("pingMessageHandler", pingMessageHandler);
ch.pipeline().addLast("connectionHandler", new ConnectionHandler());
ch.pipeline().addLast(handlersExecutor, registerClientMessageHandler);
ch.pipeline().addLast(handlersExecutor, "registerClientMessageHandler", registerClientMessageHandler);
ch.pipeline().addLast(handlersExecutor, chatRoomIdHandler);
ch.pipeline().addLast(handlersExecutor, chatMessageHandler);
ch.pipeline().addLast(handlersExecutor, joinChatMessageHandler);
ch.pipeline().addLast(handlersExecutor, leaveChatMessageHandler);
ch.pipeline().addLast(handlersExecutor, serverMessageHandler);
ch.pipeline().addLast(handlersExecutor, roomMessageHandler);
ch.pipeline().addLast(handlersExecutor, "chatRoomIdHandler", chatRoomIdHandler);
ch.pipeline().addLast(handlersExecutor, "chatMessageHandler", chatMessageHandler);
ch.pipeline().addLast(handlersExecutor, "joinChatMessageHandler", joinChatMessageHandler);
ch.pipeline().addLast(handlersExecutor, "leaveChatMessageHandler", leaveChatMessageHandler);
ch.pipeline().addLast(handlersExecutor, "serverMessageHandler", serverMessageHandler);
ch.pipeline().addLast(handlersExecutor, "roomMessageHandler", roomMessageHandler);
}
}
@ -158,4 +160,12 @@ public class Server {
clients.writeAndFlush(new InformClientMessage(message, type));
}
public void pingClient(String sessionId) {
Channel ch = findChannel(sessionId);
if (ch != null) {
HeartbeatHandler heartbeatHandler = (HeartbeatHandler)ch.pipeline().get("heartbeatHandler");
heartbeatHandler.pingClient();
}
}
}

View file

@ -5,28 +5,38 @@ import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import java.util.concurrent.TimeUnit;
import mage.remote.DisconnectReason;
import org.apache.log4j.Logger;
import org.mage.network.interfaces.MageServer;
import org.mage.network.model.PingMessage;
import org.mage.network.model.PongMessage;
/**
*
* @author BetaSteward
*/
@Sharable
public class HeartbeatHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(HeartbeatHandler.class);
private static PingMessage ping = new PingMessage();
private ChannelHandlerContext ctx;
private long startTime;
private final MageServer server;
public HeartbeatHandler (MageServer server) {
this.server = server;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
super.channelActive(ctx);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
@ -36,9 +46,24 @@ public class HeartbeatHandler extends ChannelHandlerAdapter {
ctx.disconnect();
logger.info("Disconnected due to extended idle");
} else if (e.state() == IdleState.WRITER_IDLE) {
startTime = System.nanoTime();
ctx.writeAndFlush(ping);
logger.info("Sending ping");
}
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof PongMessage) {
long milliSeconds = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
server.pingTime(milliSeconds, ctx.channel().id().asLongText());
}
ctx.fireChannelRead(msg);
}
public void pingClient() {
startTime = System.nanoTime();
ctx.writeAndFlush(ping);
}
}

View file

@ -26,5 +26,7 @@ public interface MageServer {
List<String> getServerMessages();
RoomView getRoom(UUID roomId);
void pingTime(long milliSeconds, String sessionId);
}

View file

@ -491,6 +491,16 @@ public class Main implements MageServer {
// public boolean ping(String sessionId, String pingInfo) {
// return SessionManager.getInstance().extendUserSession(sessionId, pingInfo);
// }
public void pingClient(String sessionId) {
server.pingClient(sessionId);
}
@Override
public void pingTime(long milliSeconds, String sessionId) {
SessionManager.getInstance().recordPingTime(sessionId, milliSeconds);
}
//
// @Override
// public void deregisterClient(final String sessionId) throws MageException {

View file

@ -33,6 +33,8 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
@ -57,6 +59,7 @@ import org.jboss.remoting.callback.InvokerCallbackHandler;
public class Session {
private static final Logger logger = Logger.getLogger(Session.class);
private static final ScheduledExecutorService pingTaskExecutor = Executors.newScheduledThreadPool(10);
private final String sessionId;
private UUID userId;
@ -64,6 +67,10 @@ public class Session {
private int messageId = 0;
private final Date timeConnected;
private boolean isAdmin = false;
private final static int PING_CYCLES = 10;
private final LinkedList<Long> pingTime = new LinkedList<>();
private String pingInfo = "";
// private final AsynchInvokerCallbackHandler callbackHandler;
private final ReentrantLock lock;
@ -82,6 +89,12 @@ public class Session {
// sendErrorMessageToClient(returnMessage);
// }
// return returnMessage;
pingTaskExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Main.getInstance().pingClient(sessionId);
}
}, 10, 60, TimeUnit.SECONDS);
return registerUserHandling(userName);
}
@ -260,6 +273,7 @@ public class Session {
logger.error("SESSION LOCK - kill: userId " + userId);
}
UserManager.getInstance().removeUser(userId, reason);
pingTime.clear();
} catch (InterruptedException ex) {
logger.error("SESSION LOCK - kill: userId " + userId, ex);
}
@ -324,4 +338,21 @@ public class Session {
}
return t;
}
public void recordPingTime(long milliSeconds) {
pingTime.add(milliSeconds);
String lastPing = milliSeconds > 0 ? milliSeconds+"ms" : "<1ms";
if (pingTime.size() > PING_CYCLES) {
pingTime.poll();
}
long sum = 0;
for (Long time :pingTime) {
sum += time;
}
pingInfo = lastPing + " (Av: " + (milliSeconds > 0 ? milliSeconds + "ms":"<1ms")+")";
}
public String getPingInfo() {
return pingInfo;
}
}

View file

@ -223,4 +223,11 @@ public class SessionManager {
// }
// return false;
// }
void recordPingTime(String sessionId, long milliSeconds) {
Session session = sessions.get(sessionId);
if (session != null) {
session.recordPingTime(milliSeconds);
}
}
}

View file

@ -375,7 +375,7 @@ public class TableManager {
logger.debug(user.getId()
+ " | " + formatter.format(user.getConnectionTime())
+ " | " + sessionState
+ " | " + user.getName() +" (" +user.getUserState().toString() + " - " + user.getPingInfo() + ")");
+ " | " + user.getName() +" (" +user.getUserState().toString() + " - " + session.getPingInfo() + ")");
}
ArrayList<ChatSession> chatSessions = ChatManager.getInstance().getChatSessions();
logger.debug("------- ChatSessions: " + chatSessions.size() + " ----------------------------------");

View file

@ -512,12 +512,12 @@ public class User {
return userState;
}
public String getPingInfo() {
if (isConnected()) {
return pingInfo;
} else {
return " (discon. "+ getDisconnectDuration() + ")";
}
}
// public String getPingInfo() {
// if (isConnected()) {
// return pingInfo;
// } else {
// return " (discon. "+ getDisconnectDuration() + ")";
// }
// }
}

View file

@ -197,4 +197,8 @@ public class UserManager {
logger.fatal("User manager exception - null");
}
}
void recordPingTime(UUID userId, long milliSeconds) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -73,6 +73,8 @@ import mage.interfaces.Action;
import mage.players.Player;
import mage.server.ChatManager;
import mage.server.Main;
import mage.server.Session;
import mage.server.SessionManager;
import mage.server.TableManager;
import mage.server.User;
import mage.server.UserManager;
@ -363,7 +365,8 @@ public class GameController implements GameCallback {
GameManager.getInstance().joinGame(game.getId(), user.getId());
logger.debug("Player " + player.getLogName() + " (disconnected) has joined gameId: " +game.getId());
}
ChatManager.getInstance().broadcast(chatId, user, user.getPingInfo() + " is pending to join the game", MessageColor.BLUE, true, ChatMessage.MessageType.STATUS);
Session session = SessionManager.getInstance().getSession(user.getSessionId());
ChatManager.getInstance().broadcast(chatId, user, session.getPingInfo() + " is pending to join the game", MessageColor.BLUE, true, ChatMessage.MessageType.STATUS);
if (user.getSecondsDisconnected() > 240) {
// Cancel player join possibility lately after 4 minutes
logger.debug("Player " + player.getLogName() + " - canceled game (after 240 seconds) gameId: " +game.getId());

View file

@ -46,6 +46,8 @@ import mage.game.Table;
import mage.game.match.MatchOptions;
import mage.game.tournament.TournamentOptions;
import mage.server.RoomImpl;
import mage.server.Session;
import mage.server.SessionManager;
import mage.server.TableManager;
import mage.server.User;
import mage.server.UserManager;
@ -119,11 +121,12 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
matchView = matchList;
List<UsersView> users = new ArrayList<>();
for (User user : UserManager.getInstance().getUsers()) {
Session session = SessionManager.getInstance().getSession(user.getSessionId());
try {
users.add(new UsersView(user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo()));
users.add(new UsersView(user.getName(), user.getInfo(), user.getGameInfo(), session.getPingInfo()));
} catch (Exception ex) {
logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex);
users.add(new UsersView(user.getName(), user.getInfo(), "[exception]", user.getPingInfo()));
users.add(new UsersView(user.getName(), user.getInfo(), "[exception]", session.getPingInfo()));
}
}