Kick non-admins after being idle for an hour. Any user activity resets this timer. This is a roundabout way of addressing #52, but brings more to the table in general and is significantly simpler than making each game have a timer task to manage it.
Increase the ping timeout delay from 45 seconds to 90 seconds, while reducing the timeout on long poll requests on the client side to 30 seconds. (This is still less than the 25 seconds that LongPollServlet will wait.)
This commit is contained in:
parent
e58e436285
commit
014495007a
|
@ -100,6 +100,7 @@ cah.$.DisconnectReason.BANNED = "B&";
|
|||
cah.$.DisconnectReason.PING_TIMEOUT = "pt";
|
||||
cah.$.DisconnectReason.KICKED = "k";
|
||||
cah.$.DisconnectReason.MANUAL = "man";
|
||||
cah.$.DisconnectReason.IDLE_TIMEOUT = "it";
|
||||
|
||||
cah.$.ErrorCode = function() {
|
||||
// Dummy constructor to make Eclipse auto-complete.
|
||||
|
|
|
@ -40,6 +40,7 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.NEW_PLAYER] = function(data) {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO Not sure why this isn't done with localizable strings in constants.
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.PLAYER_LEAVE] = function(data) {
|
||||
var friendly_reason = "Leaving";
|
||||
var show = !cah.hideConnectQuit;
|
||||
|
@ -48,6 +49,9 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.PLAYER_LEAVE] = function(data) {
|
|||
friendly_reason = "Banned";
|
||||
show = true;
|
||||
break;
|
||||
case cah.$.DisconnectReason.IDLE_TIMEOUT:
|
||||
friendly_reason = "Kicked due to idle";
|
||||
break;
|
||||
case cah.$.DisconnectReason.KICKED:
|
||||
friendly_reason = "Kicked by server administrator";
|
||||
show = true;
|
||||
|
@ -133,15 +137,15 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_PLAYER_LEAVE] = function(dat
|
|||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_SPECTATOR_JOIN] = function(data) {
|
||||
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.spectatorJoin,
|
||||
data[cah.$.LongPollResponse.NICKNAME],
|
||||
"spectator join (if you just joined a game this may be OK)");
|
||||
};
|
||||
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.spectatorJoin,
|
||||
data[cah.$.LongPollResponse.NICKNAME],
|
||||
"spectator join (if you just joined a game this may be OK)");
|
||||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_SPECTATOR_LEAVE] = function(data) {
|
||||
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.spectatorLeave,
|
||||
data[cah.$.LongPollResponse.NICKNAME], "spectator leave");
|
||||
};
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_SPECTATOR_LEAVE] = function(data) {
|
||||
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.spectatorLeave,
|
||||
data[cah.$.LongPollResponse.NICKNAME], "spectator leave");
|
||||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.HAND_DEAL] = function(data) {
|
||||
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.dealtCards,
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
*/
|
||||
|
||||
cah.longpoll = {};
|
||||
cah.longpoll.TIMEOUT = 45 * 1000;
|
||||
// cah.longpoll.TIMEOUT = 30 * 1000;
|
||||
cah.longpoll.TIMEOUT = 30 * 1000;
|
||||
|
||||
/**
|
||||
* Backoff when there was an error.
|
||||
|
|
|
@ -101,6 +101,10 @@ public class Constants {
|
|||
* The client was banned by the server administrator.
|
||||
*/
|
||||
BANNED("B&"),
|
||||
/**
|
||||
* The client made no user-caused requests within the timeout window.
|
||||
*/
|
||||
IDLE_TIMEOUT("it"),
|
||||
/**
|
||||
* The client was kicked by the server administrator.
|
||||
*/
|
||||
|
|
|
@ -31,7 +31,7 @@ import com.google.inject.Inject;
|
|||
|
||||
|
||||
/**
|
||||
* Timer task to check for disconnected clients.
|
||||
* Timer task to check for disconnected and idle clients.
|
||||
*
|
||||
* @author Andy Janata (ajanata@gmail.com)
|
||||
*/
|
||||
|
@ -46,6 +46,6 @@ public class UserPing extends TimerTask {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
users.checkForPingTimeouts();
|
||||
users.checkForPingAndIdleTimeouts();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,9 @@ package net.socialgamer.cah.data;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -60,7 +59,12 @@ public class ConnectedUsers {
|
|||
/**
|
||||
* Duration of a ping timeout, in nanoseconds.
|
||||
*/
|
||||
public static final long PING_TIMEOUT = TimeUnit.SECONDS.toNanos(45);
|
||||
public static final long PING_TIMEOUT = TimeUnit.SECONDS.toNanos(90);
|
||||
|
||||
/**
|
||||
* Duration of an idle timeout, in nanoseconds.
|
||||
*/
|
||||
public static final long IDLE_TIMEOUT = TimeUnit.MINUTES.toNanos(60);
|
||||
|
||||
/**
|
||||
* Key (username) must be stored in lower-case to facilitate case-insensitivity in nicks.
|
||||
|
@ -158,25 +162,35 @@ public class ConnectedUsers {
|
|||
|
||||
/**
|
||||
* Check for any users that have not communicated with the server within the ping timeout delay,
|
||||
* and remove users which have not so communicated.
|
||||
* and remove users which have not so communicated. Also remove clients which are still connected,
|
||||
* but have not actually done anything for a long time.
|
||||
*/
|
||||
public void checkForPingTimeouts() {
|
||||
final Set<User> removedUsers = new HashSet<User>();
|
||||
public void checkForPingAndIdleTimeouts() {
|
||||
final Map<User, DisconnectReason> removedUsers = new HashMap<User, DisconnectReason>();
|
||||
synchronized (users) {
|
||||
final Iterator<User> iterator = users.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final User u = iterator.next();
|
||||
DisconnectReason reason = null;
|
||||
if (System.nanoTime() - u.getLastHeardFrom() > PING_TIMEOUT) {
|
||||
removedUsers.add(u);
|
||||
reason = DisconnectReason.PING_TIMEOUT;
|
||||
}
|
||||
else if (!u.isAdmin() && System.nanoTime() - u.getLastUserAction() > IDLE_TIMEOUT) {
|
||||
reason = DisconnectReason.IDLE_TIMEOUT;
|
||||
}
|
||||
if (null != reason) {
|
||||
removedUsers.put(u, reason);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do this later to not keep users locked
|
||||
for (final User u : removedUsers) {
|
||||
for (final Entry<User, DisconnectReason> entry : removedUsers.entrySet()) {
|
||||
try {
|
||||
u.noLongerVaild();
|
||||
notifyRemoveUser(u, DisconnectReason.PING_TIMEOUT);
|
||||
entry.getKey().noLongerVaild();
|
||||
notifyRemoveUser(entry.getKey(), entry.getValue());
|
||||
logger.info(String.format("Automatically kicking user %s due to %s", entry.getKey(),
|
||||
entry.getValue()));
|
||||
} catch (final Exception e) {
|
||||
logger.error("Unable to remove pinged-out user", e);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ public class User {
|
|||
|
||||
private long lastHeardFrom = 0;
|
||||
|
||||
private long lastUserAction = 0;
|
||||
|
||||
private Game currentGame;
|
||||
|
||||
private final String hostName;
|
||||
|
@ -177,6 +179,14 @@ public class User {
|
|||
return lastHeardFrom;
|
||||
}
|
||||
|
||||
public void userDidSomething() {
|
||||
lastUserAction = System.nanoTime();
|
||||
}
|
||||
|
||||
public long getLastUserAction() {
|
||||
return lastUserAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return False when this user object is no longer valid, probably because it pinged out.
|
||||
*/
|
||||
|
|
|
@ -65,6 +65,9 @@ public class AjaxServlet extends CahServlet {
|
|||
IOException {
|
||||
final PrintWriter out = response.getWriter();
|
||||
final User user = (User) hSession.getAttribute(SessionAttribute.USER);
|
||||
if (null != user) {
|
||||
user.userDidSomething();
|
||||
}
|
||||
int serial = -1;
|
||||
if (request.getParameter(AjaxRequest.SERIAL.toString()) != null) {
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue