package tc.oc.commons.bukkit.sessions; import java.net.InetAddress; import java.util.UUID; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerQuitEvent; import tc.oc.api.bukkit.users.BukkitUserStore; import tc.oc.api.bukkit.users.OnlinePlayers; import tc.oc.api.docs.Server; import tc.oc.api.docs.Session; import tc.oc.minecraft.scheduler.SyncExecutor; import tc.oc.api.sessions.SessionService; import tc.oc.api.sessions.SessionStartRequest; import tc.oc.commons.bukkit.event.UserLoginEvent; import tc.oc.commons.bukkit.nick.PlayerIdentityChangeEvent; import tc.oc.commons.core.logging.Loggers; import tc.oc.commons.core.plugin.PluginFacet; import tc.oc.commons.core.util.SystemFutureCallback; /** * Adds login sessions to the local cache * Finishes sessions when players quit or login is denied * Restarts sessions when players change nickname */ @Singleton public class SessionListener implements Listener, PluginFacet { private final Logger logger; private final SyncExecutor syncExecutor; private final Server localServer; private final SessionService sessionService; private final OnlinePlayers onlinePlayers; private final BukkitUserStore userStore; @Inject SessionListener(Loggers loggers, SyncExecutor syncExecutor, Server localServer, SessionService sessionService, OnlinePlayers onlinePlayers, BukkitUserStore userStore) { this.logger = loggers.get(getClass()); this.localServer = localServer; this.onlinePlayers = onlinePlayers; this.userStore = userStore; this.syncExecutor = syncExecutor; this.sessionService = sessionService; } private void restartSession(final Player player) { final UUID uuid = player.getUniqueId(); final int entityId = player.getEntityId(); syncExecutor.callback( this.sessionService.start(new SessionStartRequest() { @Override public String server_id() { return localServer._id(); } @Override public String player_id() { return userStore.getUser(player).player_id(); } @Override public InetAddress ip() { return player.getAddress().getAddress(); } @Override public @Nullable String previous_session_id() { return userStore.session(player) .map(Session::_id) .orElse(null); } }), new SystemFutureCallback<Session>() { @Override public void onSuccessThrows(Session session) throws Exception { final Player player1 = onlinePlayers.find(uuid); if(player1 != null && player1.getEntityId() == entityId) { // If player is still online, store their session userStore.setSession(player1, session); logger.info("Start session " + session._id() + " for " + player1.getName() + " (identity change)"); } else { // If the player disconnected while we were starting their session, finish it right away sessionService.finish(session); logger.info("End session " + session._id() + " for " + player1.getName() + " (quick disconnect)"); } } } ); } private void finishSession(Player player) { Session session = userStore.removeSession(player); if(session != null) { this.sessionService.finish(session); logger.info("End session " + session._id() + " for " + player.getName()); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onLoginEarly(UserLoginEvent event) { if(event.getSession() != null) { userStore.setSession(event.getPlayer(), event.getSession()); logger.info("Start session " + event.getSession()._id() + " for " + event.getPlayer().getName() + " (login)"); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) public void onLoginLate(UserLoginEvent event) { if(event.getResult() != PlayerLoginEvent.Result.ALLOWED) { finishSession(event.getPlayer()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerQuit(PlayerQuitEvent event) { finishSession(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onNickChange(PlayerIdentityChangeEvent event) { restartSession(event.getPlayer()); } }