package com.faforever.client.remote; import com.faforever.client.fx.JavaFxUtil; import com.faforever.client.remote.domain.FafServerMessage; import com.faforever.client.remote.io.QDataInputStream; import org.apache.commons.compress.utils.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PreDestroy; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.net.Socket; /** * Super class for all server accessors. */ public abstract class AbstractServerAccessor { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private boolean stopped; private QDataInputStream dataInput; /** * Reads data received from the server and dispatches it. So far, there are two types of data sent by the server: <ol> * <li><strong>Server messages</strong> are simple words like ACK or PING, followed by some bytes..</li> * <li><strong>Objects</strong> are JSON-encoded objects like game or player information. Those are converted into a * {@link FafServerMessage}</li> </ol> I'm not yet happy with those terms, so any suggestions are welcome. */ protected void blockingReadServer(Socket socket) throws IOException { JavaFxUtil.assertBackgroundThread(); dataInput = new QDataInputStream(new DataInputStream(new BufferedInputStream(socket.getInputStream()))); while (!stopped && !socket.isInputShutdown()) { dataInput.skipBlockSize(); String message = dataInput.readQString(); logger.debug("Message from server: {}", message); try { onServerMessage(message); } catch (Exception e) { logger.warn("Error while handling server message: " + message, e); } } logger.info("Connection to server {} has been closed", socket.getRemoteSocketAddress()); } protected abstract void onServerMessage(String message) throws IOException; protected String readNextString() throws IOException { return dataInput.readQString(); } @PreDestroy void close() throws IOException { stopped = true; IOUtils.closeQuietly(dataInput); } }