remove dead clients
refactor the injector out to the servlet context
This commit is contained in:
parent
9508575949
commit
8a45078d77
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
|
||||
<display-name>cah</display-name>
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.htm</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
<servlet>
|
||||
<servlet-name>TestServlet</servlet-name>
|
||||
<servlet-class>net.socialgamer.cah.TestServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>LongPollServlet</servlet-name>
|
||||
<servlet-class>net.socialgamer.cah.LongPollServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>AjaxServlet</servlet-name>
|
||||
<servlet-class>net.socialgamer.cah.AjaxServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Schema</servlet-name>
|
||||
<servlet-class>net.socialgamer.cah.Schema</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>TestServlet</servlet-name>
|
||||
<url-pattern>/TestServlet</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>LongPollServlet</servlet-name>
|
||||
<url-pattern>/LongPollServlet</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>AjaxServlet</servlet-name>
|
||||
<url-pattern>/AjaxServlet</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Schema</servlet-name>
|
||||
<url-pattern>/Schema</url-pattern>
|
||||
</servlet-mapping>
|
||||
<listener>
|
||||
<listener-class>net.socialgamer.cah.StartupUtils</listener-class>
|
||||
</listener>
|
||||
</web-app>
|
|
@ -4,11 +4,8 @@ import java.io.IOException;
|
|||
import java.io.PrintWriter;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
@ -16,9 +13,6 @@ import javax.servlet.http.HttpSession;
|
|||
import net.socialgamer.cah.handlers.Handler;
|
||||
import net.socialgamer.cah.handlers.Handlers;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
|
||||
/**
|
||||
* Servlet implementation class AjaxServlet
|
||||
|
@ -29,25 +23,6 @@ import com.google.inject.Injector;
|
|||
public class AjaxServlet extends CahServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Injector injector;
|
||||
|
||||
/**
|
||||
* @see HttpServlet#HttpServlet()
|
||||
*/
|
||||
public AjaxServlet() {
|
||||
super();
|
||||
|
||||
injector = Guice.createInjector();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Servlet#init(ServletConfig)
|
||||
*/
|
||||
@Override
|
||||
public void init(final ServletConfig config) throws ServletException {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CahServlet#doPost(HttpServletRequest request, HttpServletResponse response, HttpSession
|
||||
* hSession)
|
||||
|
@ -76,7 +51,7 @@ public class AjaxServlet extends CahServlet {
|
|||
|
||||
final Handler handler;
|
||||
try {
|
||||
handler = injector.getInstance(Handlers.LIST.get(op));
|
||||
handler = getInjector().getInstance(Handlers.LIST.get(op));
|
||||
} catch (final Exception e) {
|
||||
returnError(out, "bad_op", "Invalid operation.", serial);
|
||||
return;
|
||||
|
|
|
@ -8,7 +8,6 @@ public class CahModule extends AbstractModule {
|
|||
|
||||
@Override
|
||||
protected void configure() {
|
||||
// TODO Auto-generated method stub
|
||||
bind(Server.class).in(Singleton.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ import javax.servlet.http.HttpSession;
|
|||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
|
||||
|
||||
/**
|
||||
* Servlet implementation class CahServlet
|
||||
|
@ -109,4 +111,7 @@ public abstract class CahServlet extends HttpServlet {
|
|||
writer.println(JSONValue.toJSONString(data));
|
||||
}
|
||||
|
||||
protected Injector getInjector() {
|
||||
return (Injector) getServletContext().getAttribute(StartupUtils.INJECTOR);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package net.socialgamer.cah;
|
||||
|
||||
import java.util.Timer;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
|
||||
|
||||
public class StartupUtils extends GuiceServletContextListener {
|
||||
|
||||
public static final String INJECTOR = "injector";
|
||||
|
||||
private static final long PING_START_DELAY = 60 * 1000;
|
||||
|
||||
private static final long PING_CHECK_DELAY = 5 * 1000;
|
||||
|
||||
private static final String PING_TIMER_NAME = "ping_timer";
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(final ServletContextEvent contextEvent) {
|
||||
final ServletContext context = contextEvent.getServletContext();
|
||||
final Timer timer = (Timer) context.getAttribute(PING_TIMER_NAME);
|
||||
assert (timer != null);
|
||||
timer.cancel();
|
||||
context.removeAttribute(PING_TIMER_NAME);
|
||||
context.removeAttribute(INJECTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextInitialized(final ServletContextEvent contextEvent) {
|
||||
final ServletContext context = contextEvent.getServletContext();
|
||||
final Injector injector = getInjector();
|
||||
final UserPing ping = injector.getInstance(UserPing.class);
|
||||
final Timer timer = new Timer();
|
||||
timer.schedule(ping, PING_START_DELAY, PING_CHECK_DELAY);
|
||||
context.setAttribute(PING_TIMER_NAME, timer);
|
||||
context.setAttribute(INJECTOR, injector);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Injector getInjector() {
|
||||
return Guice.createInjector();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package net.socialgamer.cah;
|
||||
|
||||
import java.util.TimerTask;
|
||||
|
||||
import net.socialgamer.cah.data.ConnectedUsers;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
public class UserPing extends TimerTask {
|
||||
|
||||
private final ConnectedUsers users;
|
||||
|
||||
@Inject
|
||||
public UserPing(final Server server) {
|
||||
users = server.getConnectedUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
users.checkForPingTimeouts();
|
||||
}
|
||||
}
|
|
@ -2,9 +2,11 @@ package net.socialgamer.cah.data;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.socialgamer.cah.data.QueuedMessage.Type;
|
||||
import net.socialgamer.cah.data.User.DisconnectReason;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -16,6 +18,11 @@ import net.socialgamer.cah.data.QueuedMessage.Type;
|
|||
*/
|
||||
public class ConnectedUsers {
|
||||
|
||||
/**
|
||||
* Duration of a ping timeout, in nanoseconds.
|
||||
*/
|
||||
public static final long PING_TIMEOUT = 3L * 60L * 1000L * 1000000L;
|
||||
|
||||
private final Map<String, User> users = new HashMap<String, User>();
|
||||
|
||||
public boolean hasUser(final String userName) {
|
||||
|
@ -33,10 +40,31 @@ public class ConnectedUsers {
|
|||
}
|
||||
|
||||
public void removeUser(final User user, final User.DisconnectReason reason) {
|
||||
// TODO fire an event for a disconnected user to interested parties
|
||||
// synchronized (users) {
|
||||
//
|
||||
// }
|
||||
synchronized (users) {
|
||||
users.remove(user.getNickname());
|
||||
notifyRemoveUser(user, reason);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRemoveUser(final User user, final User.DisconnectReason reason) {
|
||||
final HashMap<String, Object> data = new HashMap<String, Object>();
|
||||
data.put("event", "player_leave");
|
||||
data.put("nickname", user.getNickname());
|
||||
data.put("reason", reason.toString());
|
||||
broadcastToAll(Type.PLAYER_DISCONNECT, data);
|
||||
}
|
||||
|
||||
public void checkForPingTimeouts() {
|
||||
synchronized (users) {
|
||||
final Iterator<User> iterator = users.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final User u = iterator.next();
|
||||
if (System.nanoTime() - u.getLastHeardFrom() > PING_TIMEOUT) {
|
||||
notifyRemoveUser(u, DisconnectReason.PING_TIMEOUT);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue