Amélioration librairie réseau et ajout de packet pour PandacubeWeb
This commit is contained in:
parent
55748b0d5e
commit
5f10f1d55f
@ -7,10 +7,10 @@ import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
|
||||
import fr.pandacube.java.Pandacube;
|
||||
import fr.pandacube.java.util.Log;
|
||||
@ -18,6 +18,7 @@ import fr.pandacube.java.util.network.packet.Packet;
|
||||
import fr.pandacube.java.util.network.packet.PacketClient;
|
||||
import fr.pandacube.java.util.network.packet.PacketException;
|
||||
import fr.pandacube.java.util.network.packet.PacketServer;
|
||||
import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
|
||||
|
||||
public class TCPClient extends Thread implements Closeable {
|
||||
|
||||
@ -40,7 +41,11 @@ public class TCPClient extends Thread implements Closeable {
|
||||
socket.connect(a);
|
||||
addr = a;
|
||||
listener = l;
|
||||
listener.onConnect(this);
|
||||
try {
|
||||
listener.onConnect(this);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling TCPClientListener.onConnect()", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,28 +66,35 @@ public class TCPClient extends Thread implements Closeable {
|
||||
byte[] packetData = ByteBuffer.allocate(1 + 4 + size).put(code).put(sizeB).put(content).array();
|
||||
|
||||
try {
|
||||
if (listener == null) throw new InvalidServerMessage(
|
||||
"Le serveur ne peut actuellement pas prendre en charge de nouvelles requêtes. Les listeners n'ont pas encore été définis");
|
||||
|
||||
|
||||
Packet p = Packet.constructPacket(packetData);
|
||||
|
||||
if (!(p instanceof PacketServer)) throw new InvalidServerMessage(
|
||||
"Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName());
|
||||
if (!(p instanceof PacketServer))
|
||||
throw new PacketException(p.getClass().getCanonicalName() + " is not a subclass of PacketServer");
|
||||
|
||||
if (p instanceof PacketServerException) {
|
||||
|
||||
try {
|
||||
listener.onServerException(this, ((PacketServerException)p).getExceptionString());
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e);
|
||||
}
|
||||
}
|
||||
|
||||
PacketServer ps = (PacketServer) p;
|
||||
|
||||
listener.onPacketReceive(this, ps);
|
||||
} catch (PacketException | InvalidServerMessage e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Message du serveur mal formé", e);
|
||||
try {
|
||||
listener.onPacketReceive(this, ps);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling TCPClientListener.onPacketReceive()", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur", e);
|
||||
Log.severe("Exception while handling packet from server", e);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SocketTimeoutException e) {
|
||||
System.err.println("Le serveur a prit trop de temps à répondre");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.severe(e);
|
||||
}
|
||||
close();
|
||||
}
|
||||
@ -110,10 +122,15 @@ public class TCPClient extends Thread implements Closeable {
|
||||
if (isClosed.get()) return;
|
||||
socket.close();
|
||||
isClosed.set(true);
|
||||
listener.onDisconnect(this);
|
||||
|
||||
try {
|
||||
listener.onDisconnect(this);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling TCPClientListener.onDisconnect()", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.warning(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,13 +147,12 @@ public class TCPClient extends Thread implements Closeable {
|
||||
public boolean isClosed() {
|
||||
return isClosed.get() || socket.isClosed();
|
||||
}
|
||||
|
||||
public static class InvalidServerMessage extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidServerMessage(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("thread", getName())
|
||||
.append("socket", socket.getRemoteSocketAddress()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,42 @@
|
||||
package fr.pandacube.java.util.network.client;
|
||||
|
||||
import fr.pandacube.java.util.Log;
|
||||
import fr.pandacube.java.util.network.packet.PacketServer;
|
||||
|
||||
public interface TCPClientListener {
|
||||
|
||||
/**
|
||||
* Called when a connection is opened
|
||||
* @param connection the connection which is opening
|
||||
*/
|
||||
public void onConnect(TCPClient connection);
|
||||
|
||||
/**
|
||||
* Called when the server send us a PacketServerException when an exception is thrown
|
||||
* server side when handling our packets or eventually when the client is concerned
|
||||
* with this error.<br/>
|
||||
* The default implementation of this method just call the internal Logger of PandacubeUtil
|
||||
* to print the stacktrace of the Exception.
|
||||
* @param connection the connection which just received the error
|
||||
* @param exceptionString a string representation of the exception. If the server
|
||||
* use this Java library, it may be a full representation of
|
||||
* {@link Throwable#printStackTrace()}.
|
||||
*/
|
||||
public default void onServerException(TCPClient connection, String exceptionString) {
|
||||
Log.severe("Exception thrown by server through " + connection + " : \n"+exceptionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server send us a packet
|
||||
* @param connection the connection where the packet come from
|
||||
* @param packet the packet
|
||||
*/
|
||||
public void onPacketReceive(TCPClient connection, PacketServer packet);
|
||||
|
||||
/**
|
||||
* Called before the connection closed
|
||||
* @param connection the connection which is closing
|
||||
*/
|
||||
public void onDisconnect(TCPClient connection);
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,31 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.pandacube.java.Pandacube;
|
||||
import fr.pandacube.java.util.Log;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteSerializable;
|
||||
import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
|
||||
import fr.pandacube.java.util.network.packet.packets.web.PacketClientWebRequest;
|
||||
import fr.pandacube.java.util.network.packet.packets.web.PacketServerWebResponse;
|
||||
|
||||
/** <pre>
|
||||
* Identification des packets réseaux
|
||||
* byte (xxxxxxxx)
|
||||
* client : server :
|
||||
* clt / sv (x-------) (0-------) (1-------)
|
||||
* 0x00 - 0x7F 0x80 - 0xFF
|
||||
* use case (-xxx----)
|
||||
* - web (-000----) 0x00 - 0x0F 0x80 - 0x8F (client is Apache, server is PandacubeCore master (PandacubeWeb))
|
||||
* - spigot (-001----) 0x10 - 0x1F 0x90 - 0x9F (client is PandacubeSpigot, server is PandacubeCore master)
|
||||
* - bungee (-010----) 0x20 - 0x2F 0xA0 - 0xAF (client is PandacubeBungee, server is PandacubeCore master)
|
||||
* - global (-101----) 0x50 - 0x5F 0xD0 - 0xDF
|
||||
*
|
||||
* - reserved if not enough packet id in certain use case
|
||||
* (-11x----) 0x60 - 0x7F 0xE0 - 0xFF
|
||||
*
|
||||
* packet id (----xxxx)
|
||||
* </pre>
|
||||
*/
|
||||
public abstract class Packet implements ByteSerializable {
|
||||
|
||||
private final byte code;
|
||||
@ -34,7 +56,8 @@ public abstract class Packet implements ByteSerializable {
|
||||
|
||||
public static Packet constructPacket(byte[] data) {
|
||||
if (!packetTypes.containsKey(data[0]))
|
||||
throw new PacketException("l'identifiant du packet ne correspond à aucun type de packet : " + data[0]);
|
||||
throw new PacketException("Packet identifier not recognized: 0x" + String.format("%02X", data[0])
|
||||
+ ". Maybe this packet is not registered with Packet.addPacket()");
|
||||
|
||||
try {
|
||||
Packet p = packetTypes.get(data[0]).newInstance();
|
||||
@ -42,27 +65,28 @@ public abstract class Packet implements ByteSerializable {
|
||||
p.deserializeFromByteBuffer(dataBuffer);
|
||||
return p;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new PacketException("erreur lors de la construction du packet");
|
||||
throw new PacketException("Error while constructing packet", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static <T extends Packet> void addPacket(Class<T> packetClass) {
|
||||
try {
|
||||
Packet p = packetClass.newInstance();
|
||||
packetTypes.put(p.code, packetClass);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.severe(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
|
||||
/*
|
||||
* Ajout des types de packets (client + serveur)
|
||||
*/
|
||||
// addPacket(PacketToto.class);
|
||||
addPacket(PacketClientWebRequest.class);
|
||||
addPacket(PacketServerWebResponse.class);
|
||||
addPacket(PacketServerException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package fr.pandacube.java.util.network.packet;
|
||||
|
||||
/**
|
||||
*
|
||||
* Thrown when there is a problem when constructing, sending or handling a packet.
|
||||
*
|
||||
* Only the server may send a string representation of an exception to the client, not the reverse
|
||||
*
|
||||
*/
|
||||
public class PacketException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
package fr.pandacube.java.util.network.packet.packets.global;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import fr.pandacube.java.util.network.packet.PacketServer;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
|
||||
|
||||
public class PacketServerException extends PacketServer {
|
||||
|
||||
private String exception;
|
||||
|
||||
public PacketServerException() {
|
||||
super((byte)0xE0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeToByteBuffer(ByteBuffer buffer) {
|
||||
buffer.putString(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeFromByteBuffer(ByteBuffer buffer) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setException(Exception e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
exception = sw.toString();
|
||||
}
|
||||
|
||||
public String getExceptionString() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package fr.pandacube.java.util.network.packet.packets.web;
|
||||
|
||||
import fr.pandacube.java.util.network.packet.PacketClient;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
|
||||
|
||||
public class PacketClientWebRequest extends PacketClient {
|
||||
|
||||
private String password;
|
||||
private String jsonData;
|
||||
|
||||
public PacketClientWebRequest() {
|
||||
super((byte)0x00);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeToByteBuffer(ByteBuffer buffer) {
|
||||
buffer.putString(password);
|
||||
buffer.putString(jsonData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeFromByteBuffer(ByteBuffer buffer) {
|
||||
password = buffer.getString();
|
||||
jsonData = buffer.getString();
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getJsonData() {
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
public void setJsonData(String jsonData) {
|
||||
this.jsonData = jsonData;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package fr.pandacube.java.util.network.packet.packets.web;
|
||||
|
||||
import fr.pandacube.java.util.network.packet.PacketServer;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
|
||||
|
||||
public class PacketServerWebResponse extends PacketServer {
|
||||
|
||||
private String jsonData;
|
||||
|
||||
public PacketServerWebResponse() {
|
||||
super((byte)0x80);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeToByteBuffer(ByteBuffer buffer) {
|
||||
buffer.putString(jsonData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeFromByteBuffer(ByteBuffer buffer) {
|
||||
jsonData = buffer.getString();
|
||||
}
|
||||
|
||||
public String getJsonData() {
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
public void setJsonData(String jsonData) {
|
||||
this.jsonData = jsonData;
|
||||
}
|
||||
|
||||
}
|
@ -17,12 +17,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
|
||||
import fr.pandacube.java.Pandacube;
|
||||
import fr.pandacube.java.util.Log;
|
||||
import fr.pandacube.java.util.network.packet.Packet;
|
||||
import fr.pandacube.java.util.network.packet.PacketClient;
|
||||
import fr.pandacube.java.util.network.packet.PacketException;
|
||||
import fr.pandacube.java.util.network.packet.PacketServer;
|
||||
import fr.pandacube.java.util.network.packet.bytebuffer.ByteBuffer;
|
||||
import fr.pandacube.java.util.network.packet.packets.global.PacketServerException;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -50,7 +54,11 @@ public class TCPServer extends Thread implements Closeable {
|
||||
socket.setPerformancePreferences(0, 2, 1);
|
||||
socket.bind(new InetSocketAddress(port));
|
||||
listener = l;
|
||||
listener.onSocketOpen(this);
|
||||
try {
|
||||
listener.onSocketOpen(this);
|
||||
} catch(Exception e) {
|
||||
Log.severe("Exception while calling TCPServerListener.onSocketOpen()", e);
|
||||
}
|
||||
socketName = sckName;
|
||||
}
|
||||
|
||||
@ -67,7 +75,6 @@ public class TCPServer extends Thread implements Closeable {
|
||||
TCPServerClientConnection co = new TCPServerClientConnection(socketClient,
|
||||
connectionCounterId.getAndIncrement());
|
||||
clients.add(co);
|
||||
listener.onClientConnect(this, co);
|
||||
co.start();
|
||||
} catch (IOException e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Connexion impossible avec " + socketClient.getInetAddress());
|
||||
@ -91,7 +98,11 @@ public class TCPServer extends Thread implements Closeable {
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
address = new InetSocketAddress(socket.getInetAddress(), socket.getPort());
|
||||
listener.onClientConnect(TCPServer.this, this);
|
||||
try {
|
||||
listener.onClientConnect(TCPServer.this, this);
|
||||
} catch(Exception e) {
|
||||
Log.severe("Exception while calling TCPServerListener.onClientConnect()", e);
|
||||
}
|
||||
outThread = new TCPServerConnectionOutputThread(coId);
|
||||
outThread.start();
|
||||
}
|
||||
@ -102,7 +113,7 @@ public class TCPServer extends Thread implements Closeable {
|
||||
byte[] code = new byte[1];
|
||||
while (!socket.isClosed() && in.read(code) != -1) {
|
||||
byte[] sizeB = new byte[4];
|
||||
if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " fermé");
|
||||
if (in.read(sizeB) != 4) throw new IOException("Socket " + address + " closed");
|
||||
|
||||
int size = new ByteBuffer(sizeB, Packet.CHARSET).getInt();
|
||||
|
||||
@ -117,17 +128,16 @@ public class TCPServer extends Thread implements Closeable {
|
||||
|
||||
try {
|
||||
interpreteReceivedMessage(this, packetData);
|
||||
} catch (InvalidClientMessage e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Erreur protocole de : ", e);
|
||||
} catch (Exception e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Erreur lors de la prise en charge du message par le serveur",
|
||||
e);
|
||||
e.printStackTrace();
|
||||
Log.severe("Exception while handling packet. This exception will be sent to the client with PacketServerException packet.", e);
|
||||
PacketServerException packet = new PacketServerException();
|
||||
packet.setException(e);
|
||||
send(packet);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.getLogger().log(Level.SEVERE, "Fermeture de la connexion de " + address, e);
|
||||
Log.severe("Closing connection " + address, e);
|
||||
}
|
||||
|
||||
close();
|
||||
@ -149,7 +159,11 @@ public class TCPServer extends Thread implements Closeable {
|
||||
public void close() {
|
||||
if (socket.isClosed()) return;
|
||||
|
||||
listener.onClientDisconnect(TCPServer.this, this);
|
||||
try {
|
||||
listener.onClientDisconnect(TCPServer.this, this);
|
||||
} catch(Exception e) {
|
||||
Log.severe("Exception while calling TCPServerListener.onClientDisconnect()", e);
|
||||
}
|
||||
clients.remove(this);
|
||||
|
||||
try {
|
||||
@ -163,9 +177,7 @@ public class TCPServer extends Thread implements Closeable {
|
||||
});
|
||||
// provoque une exception dans le thread de sortie, et la
|
||||
// termine
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
|
||||
private class TCPServerConnectionOutputThread extends Thread {
|
||||
@ -200,18 +212,30 @@ public class TCPServer extends Thread implements Closeable {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("thread", getName())
|
||||
.append("socket", socket).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void interpreteReceivedMessage(TCPServerClientConnection co, byte[] data) {
|
||||
|
||||
Packet p = Packet.constructPacket(data);
|
||||
|
||||
if (!(p instanceof PacketClient)) throw new InvalidClientMessage(
|
||||
"Le type de packet reçu n'est pas un packet attendu : " + p.getClass().getCanonicalName());
|
||||
if (!(p instanceof PacketClient))
|
||||
throw new PacketException(p.getClass().getCanonicalName() + " is not an instanceof PacketClient");
|
||||
|
||||
PacketClient pc = (PacketClient) p;
|
||||
|
||||
listener.onPacketReceive(this, co, pc);
|
||||
try {
|
||||
listener.onPacketReceive(this, co, pc);
|
||||
} catch(Exception e) {
|
||||
Log.severe("Exception while calling TCPServerListener.onPacketReceive()", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -223,20 +247,25 @@ public class TCPServer extends Thread implements Closeable {
|
||||
|
||||
socket.close();
|
||||
isClosed.set(true);
|
||||
listener.onSocketClose(this);
|
||||
try {
|
||||
listener.onSocketClose(this);
|
||||
} catch(Exception e) {
|
||||
Log.severe("Exception while calling TCPServerListener.onSocketClose()", e);
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return isClosed.get() || socket.isClosed();
|
||||
}
|
||||
|
||||
|
||||
public static class InvalidClientMessage extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidClientMessage(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("thread", getName())
|
||||
.append("socket", socket).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user