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());
}
}