package jj.http.server.websocket; import static java.util.concurrent.TimeUnit.SECONDS; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.inject.Singleton; import jj.event.Listener; import jj.event.Subscriber; import jj.execution.ServerTask; import jj.execution.TaskRunner; import jj.http.server.HttpServerStarted; import jj.http.server.HttpServerStopped; /** * * @author jason * */ @Singleton @Subscriber public class WebSocketConnectionTracker { private final class ActivityChecker extends ServerTask { /** * @param name */ public ActivityChecker() { super("WebSocket connection activity checker"); } @Override public void run() { // do nothing if we've been interrupted if (!Thread.currentThread().isInterrupted()) { for (WebSocketConnection connection : allConnections.keySet()) { if (System.currentTimeMillis() - connection.lastActivity() > 35000) { connection.close(); } } repeat(); } } @Override protected long delay() { return TimeUnit.MILLISECONDS.convert(5, SECONDS); } } private final ConcurrentMap<WebSocketConnection, Boolean> allConnections = new ConcurrentHashMap<>(16, 0.75F, 2); private final TaskRunner taskRunner; private final AtomicReference<ActivityChecker> currentActivityChecker = new AtomicReference<>(); @Inject public WebSocketConnectionTracker(final TaskRunner taskRunner) { this.taskRunner = taskRunner; } @Listener void on(HttpServerStarted event) { if (currentActivityChecker.get() == null) { currentActivityChecker.set(new ActivityChecker()); taskRunner.execute(currentActivityChecker.get()); } } @Listener void on(HttpServerStopped event) { ActivityChecker current = currentActivityChecker.getAndSet(null); assert current != null : "server was running with no web socket activity checker!"; current.cancelKey().cancel(); } void addConnection(WebSocketConnection connection) { allConnections.putIfAbsent(connection, Boolean.TRUE); } void removeConnection(WebSocketConnection connection) { allConnections.remove(connection); } }