package envoy.server.net; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; import com.jenkov.nioserver.ISocketIdListener; import envoy.data.User.UserStatus; import envoy.server.data.*; import envoy.server.processors.UserStatusChangeProcessor; /** * @author Kai S. K. Engelbart * @since Envoy Server Standalone v0.1-alpha */ public final class ConnectionManager implements ISocketIdListener { /** * Contains all socket IDs that have not yet performed a handshake / acquired their * corresponding user ID. * * @since Envoy Server Standalone v0.1-alpha */ private final Set pendingSockets = new HashSet<>(); /** * Contains all socket IDs that have acquired a user ID as keys to these IDs. * * @since Envoy Server Standalone v0.1-alpha */ private final Map sockets = new HashMap<>(); private static ConnectionManager connectionManager = new ConnectionManager(); private ConnectionManager() {} /** * @return a singleton instance of this object * @since Envoy Server Standalone v0.1-alpha */ public static ConnectionManager getInstance() { return connectionManager; } @Override public void socketCancelled(long socketID) { if (!pendingSockets.remove(socketID)) { // Notify contacts of this users offline-going final envoy.server.data.User user = PersistenceManager.getInstance().getUserByID(getUserIDBySocketID(socketID)); if (user != null) { user.setLastSeen(Instant.now()); UserStatusChangeProcessor.updateUserStatus(user, UserStatus.OFFLINE); } // Remove the socket sockets.entrySet().removeIf(e -> e.getValue() == socketID); } } @Override public void socketRegistered(long socketID) { pendingSockets.add(socketID); } /** * Associates a socket ID with a user ID. * * @param userID the user ID * @param socketID the socket ID * @since Envoy Server Standalone v0.1-alpha */ public void registerUser(long userID, long socketID) { sockets.put(userID, socketID); pendingSockets.remove(socketID); } /** * @param userID the ID of the user registered at a socket * @return the ID of the socket * @since Envoy Server Standalone v0.1-alpha */ public long getSocketID(long userID) { return sockets.get(userID); } /** * @param socketID the id of the socket whose User is needed * @return the userId associated with this socketId * @since Envoy Server Standalone v0.1-alpha */ public long getUserIDBySocketID(long socketID) { return sockets.entrySet().stream().filter(entry -> entry.getValue().equals(socketID)) .findFirst().get().getKey(); } /** * @param userID the ID of the user to check for * @return {@code true} if the user is online * @since Envoy Server Standalone v0.1-alpha */ public boolean isOnline(long userID) { return sockets.containsKey(userID); } /** * @return the userIDs of all users who are currently online * @since Envoy Server Standalone v0.1-alpha */ public Set getOnlineUsers() { return sockets.keySet(); } /** * @param group the group to search for * @return a set of all IDs of currently active members in this group * @since Envoy Server Standalone v0.1-beta */ public Set getOnlineUsersOfGroup(Group group) { return group.getContacts().stream().map(Contact::getID).filter(this::isOnline) .collect(Collectors.toSet()); } }