package com.cardshifter.server.clients;
import com.cardshifter.api.CardshifterSerializationException;
import com.cardshifter.api.serial.ByteTransformer;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.zomis.cardshifter.ecs.usage.CardshifterIO;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.java_websocket.WebSocket;
import com.cardshifter.api.ClientIO;
import com.cardshifter.api.messages.Message;
import com.cardshifter.server.model.Server;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
public class ClientWebSocket extends ClientIO {
private static final Logger logger = LogManager.getLogger(ClientWebSocket.class);
private final WebSocket conn;
private final ByteTransformer transformer = CardshifterIO.createByteTransformer();
private final ObjectMapper jsonMapper = CardshifterIO.mapper();
/**
* true if this client uses Base64
* null if it is unknown
* false if this client uses JSON
*
* This is not the best way of doing this, but it works, and right now I just want it to work.
*/
private Boolean knownBase64client;
public ClientWebSocket(Server server, WebSocket conn) {
super(server);
this.conn = conn;
}
@Override
public void close() {
logger.info("Manual close " + this);
conn.close();
}
@Override
protected void onSendToClient(Message message) {
if (!conn.isOpen()) {
this.disconnected();
return;
}
String data;
try {
if (knownBase64client == null) {
logger.error("It is not yet known whether or not client is Base64 or JSON, " +
"ignoring sending of " + message + " to " + this);
return;
}
if (knownBase64client) {
byte[] bytes = transformer.transform(message);
data = Base64Utils.toBase64(bytes);
logger.info("Sending to client: " + message + " - " + Arrays.toString(bytes));
conn.send(data);
} else {
try {
data = jsonMapper.writeValueAsString(message);
logger.info("Sending to client: " + message + " - " + data);
conn.send(data);
} catch (JsonProcessingException e) {
throw new CardshifterSerializationException(e);
}
}
} catch (CardshifterSerializationException e) {
throw new RuntimeException("Error serializing message " + message + " to " + this, e);
} catch (WebsocketNotConnectedException ex) {
this.disconnected();
logger.error("Websocket not connected: " + this, ex);
}
}
@Override
public String getRemoteAddress() {
if (conn == null) {
return "null connection";
}
if (conn.isOpen()) {
return "connection not open";
}
if (conn.getRemoteSocketAddress() == null) {
return "null address";
}
return conn.getRemoteSocketAddress().toString();
}
public void handleMessage(String message) throws CardshifterSerializationException {
if (knownBase64client == null) {
knownBase64client = Base64Utils.isBase64(message, 0, 5);
}
if (knownBase64client) {
byte[] bytes = Base64Utils.fromBase64(message);
logger.info("Connection message from: " + conn + ": " + Arrays.toString(bytes));
this.sentToServer(transformer.readOnce(new ByteArrayInputStream(bytes)));
} else {
try {
Message messageObject = jsonMapper.readValue(message, Message.class);
logger.info("Connection message from: " + conn + ": " + messageObject);
this.sentToServer(messageObject);
} catch (IOException e) {
throw new RuntimeException("Could not read JSON expected message from " + this +
", message was: " + message, e);
}
}
}
}