package com.jenjinstudios.client.net; import com.jenjinstudios.core.MessageIO; import com.jenjinstudios.core.io.Message; import com.jenjinstudios.core.io.MessageRegistry; import java.util.logging.Level; import java.util.logging.Logger; /** * The {@code AuthClient} class is a {@code Client} with the ability to store user information and attempt to log into a * {@code Server} using a username and password. * * @author Caleb Brinkman */ public class AuthClient extends Client { private final ClientUser user; private final LoginTracker loginTracker; /** * Construct a new client with authentication abilities. * * @param messageIO The MessageIO used by this client to communicate with a server. * @param user The user which this client will attempt to authenticate. */ public AuthClient(MessageIO messageIO, ClientUser user) { super(messageIO); this.loginTracker = new LoginTracker(this); this.user = user; } /** * Generate a LogoutRequest message. * * @return The LogoutRequestMessage. */ public static Message generateLogoutRequest() { return MessageRegistry.getInstance().createMessage ("LogoutRequest"); } /** * Generate a LoginRequest message. This message will be encrypted if possible. * * @param user The User for which to generate the login request. * @return The LoginRequest message. */ public static Message generateLoginRequest(ClientUser user) {// Create the login request. Message loginRequest = MessageRegistry.getInstance().createMessage("LoginRequest"); loginRequest.setArgument("username", user.getUsername()); loginRequest.setArgument("password", user.getPassword()); return loginRequest; } /** * Get the LoginTracker managed by this client. * * @return The login tracker managed by this client. */ public LoginTracker getLoginTracker() { return loginTracker; } /** * Get the username of this client. * * @return The username of this client. */ public ClientUser getUser() { return user; } /** * Used to track the status of login requests and responses. * * @author Caleb Brinkman */ public static class LoginTracker { private static final Logger LOGGER = Logger.getLogger(LoginTracker.class.getName()); private static final int MILLIS_IN_30_SECONDS = 30000; private volatile boolean loggedIn; private volatile boolean waitingForResponse; private long loggedInTime; private final AuthClient client; /** * Construct a new LoginTracker working for the given client. * * @param client The client using this LoginTracker. */ public LoginTracker(AuthClient client) { this.client = client; } /** * Returns whether this login tracker has received a successful login response. * * @return Whether this login tracker has received a successful login response. */ public boolean isLoggedIn() { return loggedIn; } /** * Set when a successful login response has been received. * * @param loggedIn Whether the login was successful. */ public void setLoggedIn(boolean loggedIn) { waitingForResponse = false; this.loggedIn = loggedIn; } /** * Get the time at which the login was performed. * * @return The time at which the login was performed. */ public long getLoggedInTime() { return loggedInTime; } /** * Set the time at which the login was performed. * * @param loggedInTime The time at which the login was performed. */ public void setLoggedInTime(long loggedInTime) { this.loggedInTime = loggedInTime; } /** * Send a login request for this tracker's client. */ protected void sendLoginRequest() { waitingForResponse = true; Message message = generateLoginRequest(client.getUser()); client.getMessageIO().queueOutgoingMessage(message); } /** * Send a login request and await the response. * * @return Whether the login was successful. */ @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") public boolean sendLoginRequestAndWaitForResponse() { sendLoginRequest(); long startTime = System.currentTimeMillis(); while (waitingForResponse && ((System.currentTimeMillis() - startTime) < MILLIS_IN_30_SECONDS)) { waitTenMillis(); } return loggedIn; } /** * Send a logout request and block execution until the response is received. */ public void sendLogoutRequestAndWaitForResponse() { sendLogoutRequest(); long startTime = System.currentTimeMillis(); while (waitingForResponse && ((System.currentTimeMillis() - startTime) < MILLIS_IN_30_SECONDS)) { waitTenMillis(); } } private void sendLogoutRequest() { waitingForResponse = true; Message message = generateLogoutRequest(); client.getMessageIO().queueOutgoingMessage(message); } private static void waitTenMillis() { try { Thread.sleep(10); } catch (InterruptedException e) { LOGGER.log(Level.WARNING, "Interrupted while waiting for login response.", e); } } } }