Make tcp handlers more generic

This commit is contained in:
Arnaud Vergnet 2021-01-07 15:35:05 +01:00
parent 7a36ef2c60
commit 1cf1ebec37
10 changed files with 91 additions and 47 deletions

View file

@ -11,14 +11,14 @@ import java.net.Socket;
public class PeerHandshake { public class PeerHandshake {
private PeerConnection connection; private TcpConnection connection;
private UserInformation userInformation; private UserInformation userInformation;
public void createConnection(InetAddress ipAddr, UserConnectedCallback callback, ErrorCallback errorCallback) { public void createConnection(InetAddress ipAddr, UserConnectedCallback callback, ErrorCallback errorCallback) {
closeConnection(); closeConnection();
Log.v(this.getClass().getSimpleName(), "Creating new TCP connection "); Log.v(this.getClass().getSimpleName(), "Creating new TCP connection ");
connection = new PeerConnection( connection = new TcpConnection(
ipAddr, ipAddr,
(thisConnection) -> init(thisConnection, (thisConnection) -> init(thisConnection,
false, false,
@ -33,11 +33,11 @@ public class PeerHandshake {
public void acceptConnection(Socket socket, UserConnectedCallback callback, ErrorCallback errorCallback) { public void acceptConnection(Socket socket, UserConnectedCallback callback, ErrorCallback errorCallback) {
closeConnection(); closeConnection();
connection = new PeerConnection(socket); connection = new TcpConnection(socket);
init(connection, true, callback, errorCallback); init(connection, true, callback, errorCallback);
} }
private void init(PeerConnection thisConnection, boolean isReceiving, UserConnectedCallback callback, ErrorCallback errorCallback) { private void init(TcpConnection thisConnection, boolean isReceiving, UserConnectedCallback callback, ErrorCallback errorCallback) {
// Send our username // Send our username
thisConnection.send(new UserInformation(CurrentUser.getInstance()), null, e -> { thisConnection.send(new UserInformation(CurrentUser.getInstance()), null, e -> {
closeConnection(); closeConnection();
@ -68,7 +68,7 @@ public class PeerHandshake {
}); });
} }
private void sendUsernameTaken(PeerConnection thisConnection) { private void sendUsernameTaken(TcpConnection thisConnection) {
Log.v(this.getClass().getSimpleName(), "Received username request using current username"); Log.v(this.getClass().getSimpleName(), "Received username request using current username");
thisConnection.send(new UsernameTakenException("Username taken"), this::closeConnection, null); thisConnection.send(new UsernameTakenException("Username taken"), this::closeConnection, null);
} }
@ -84,7 +84,7 @@ public class PeerHandshake {
} }
} }
public PeerConnection getConnection() { public TcpConnection getConnection() {
return connection; return connection;
} }

View file

@ -11,13 +11,14 @@ import java.io.Serializable;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
public class PeerConnection { public class TcpConnection {
public static final short TCP_PORT = 31598; public static final int TCP_PORT = 31598;
private Socket socket; private Socket socket;
private ObjectOutputStream outputStream; private ObjectOutputStream outputStream;
private ObjectInputStream inputStream; private ObjectInputStream inputStream;
private boolean shouldStop = false; private boolean shouldStop = false;
private final int port;
/** /**
* Creates a new connection, and connects to the peer * Creates a new connection, and connects to the peer
@ -26,7 +27,19 @@ public class PeerConnection {
* @param callback The function to call when connected * @param callback The function to call when connected
* @param errorCallback The function to call on error * @param errorCallback The function to call on error
*/ */
public PeerConnection(InetAddress ipAddr, SocketConnectedCallback callback, ErrorCallback errorCallback) { public TcpConnection(InetAddress ipAddr, SocketConnectedCallback callback, ErrorCallback errorCallback) {
this(ipAddr, TCP_PORT, callback, errorCallback);
}
/**
* Creates a new connection, and connects to the peer
*
* @param ipAddr The IP address of the peer
* @param callback The function to call when connected
* @param errorCallback The function to call on error
*/
public TcpConnection(InetAddress ipAddr, int port, SocketConnectedCallback callback, ErrorCallback errorCallback) {
this.port = port;
Connector connector = new Connector(ipAddr, callback, errorCallback); Connector connector = new Connector(ipAddr, callback, errorCallback);
connector.start(); connector.start();
} }
@ -36,7 +49,8 @@ public class PeerConnection {
* *
* @param socket A socket already connected to the host * @param socket A socket already connected to the host
*/ */
public PeerConnection(Socket socket) { public TcpConnection(Socket socket) {
this.port = socket.getPort();
this.socket = socket; this.socket = socket;
} }
@ -53,7 +67,7 @@ public class PeerConnection {
} }
/** /**
* Subscibe to all incoming messages from the peer * Subscribe to all incoming messages from the peer
* *
* @param callback The function to call when a message is received * @param callback The function to call when a message is received
* @param errorCallback The function to call on error * @param errorCallback The function to call on error
@ -112,8 +126,8 @@ public class PeerConnection {
if (socket != null) { if (socket != null) {
close(); close();
} }
socket = new Socket(ipAddr, TCP_PORT); socket = new Socket(ipAddr, port);
callback.onSocketConnected(PeerConnection.this); callback.onSocketConnected(TcpConnection.this);
} catch (IOException e) { } catch (IOException e) {
if (errorCallback != null) if (errorCallback != null)
errorCallback.onError(e); errorCallback.onError(e);
@ -130,12 +144,12 @@ public class PeerConnection {
/** /**
* Constructs a thread that sends a message using the socket of the outer class * Constructs a thread that sends a message using the socket of the outer class
* *
* @param messsage The message to send * @param message The message to send
* @param callback The function to call on success * @param callback The function to call on success
* @param errorCallback The function to call on error * @param errorCallback The function to call on error
*/ */
public Sender(Serializable messsage, @Nullable MessageSentCallback callback, @Nullable ErrorCallback errorCallback) { public Sender(Serializable message, @Nullable MessageSentCallback callback, @Nullable ErrorCallback errorCallback) {
this.message = messsage; this.message = message;
this.callback = callback; this.callback = callback;
this.errorCallback = errorCallback; this.errorCallback = errorCallback;
} }
@ -191,7 +205,7 @@ public class PeerConnection {
public interface SocketConnectedCallback { public interface SocketConnectedCallback {
void onSocketConnected(PeerConnection connection); void onSocketConnected(TcpConnection connection);
} }
public interface MessageReceivedCallback { public interface MessageReceivedCallback {

View file

@ -6,19 +6,19 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import static fr.insa.clavardator.network.PeerConnection.TCP_PORT; import static fr.insa.clavardator.network.TcpConnection.TCP_PORT;
public class ConnectionListener { public class TcpListener {
Acceptor acceptor = null; Acceptor acceptor = null;
public ConnectionListener() { public TcpListener() {
} }
/** /**
* Start accepting incoming connections * Start accepting incoming connections
* *
* @param callback The function to call when a user connects * @param callback The function to call when a user connects
* @param errorCallback The function to call on errror * @param errorCallback The function to call on error
*/ */
public void acceptConnection(NewConnectionCallback callback, ErrorCallback errorCallback) { public void acceptConnection(NewConnectionCallback callback, ErrorCallback errorCallback) {
if (acceptor != null) { if (acceptor != null) {

View file

@ -1,8 +1,11 @@
package fr.insa.clavardator.server; package fr.insa.clavardator.server;
import fr.insa.clavardator.network.PeerConnection; import fr.insa.clavardator.network.TcpConnection;
import fr.insa.clavardator.users.UserInformation;
import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.ParametrizedCallback;
import fr.insa.clavardator.util.SimpleCallback;
import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
@ -33,22 +36,22 @@ public class InsaPresence implements Presence {
} }
@Override @Override
public ArrayList<String> subscribe() { public void subscribe(ParametrizedCallback<ArrayList<UserInformation>> callback, ErrorCallback errorCallback) {
return null;
}
@Override
public void unsubscribe() {
} }
@Override @Override
public void publish(boolean connected) { public void unsubscribe(SimpleCallback callback, ErrorCallback errorCallback) {
} }
@Override @Override
public PeerConnection getProxyConnection() { public void publish(boolean connected, SimpleCallback callback, ErrorCallback errorCallback) {
}
@Override
public TcpConnection getProxyConnection() {
return null; return null;
} }
} }

View file

@ -1,24 +1,38 @@
package fr.insa.clavardator.server; package fr.insa.clavardator.server;
import fr.insa.clavardator.network.PeerConnection; import fr.insa.clavardator.network.TcpConnection;
import fr.insa.clavardator.users.UserInformation;
import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.ParametrizedCallback;
import fr.insa.clavardator.util.SimpleCallback;
import java.util.ArrayList; import java.util.ArrayList;
/**
* Interface exposing public methods necessary for any presence server.
*
* @implNote Implement this interface when creating your own presence server class,
* then update the {@link fr.insa.clavardator.server.PresenceFactory factory}
* to add your new implementation.
*/
public interface Presence { public interface Presence {
/** /**
* Subscribes to this presence server notifications. * Subscribes to this presence server notifications.
* A list of Ids representing the current active users is returned. * A list of Ids representing the current active users is returned.
* *
* @return The list of connected user's Ids * @param callback Called when subscription completes
*/ */
ArrayList<String> subscribe(); void subscribe(ParametrizedCallback<ArrayList<UserInformation>> callback, ErrorCallback errorCallback);
/** /**
* Stops subscription to the presence server. * Stops subscription to the presence server by closing TCP connections.
* This will stop notifications. * This will stop notifications.
*
* @implNote Call this before exiting the app.
* If not, the presence server will wait for a tcp timeout before marking this user as disconnected.
*/ */
void unsubscribe(); void unsubscribe(SimpleCallback callback, ErrorCallback errorCallback);
/** /**
* Updates the current user state on the server. * Updates the current user state on the server.
@ -27,7 +41,7 @@ public interface Presence {
* *
* @param connected The new user state * @param connected The new user state
*/ */
void publish(boolean connected); void publish(boolean connected, SimpleCallback callback, ErrorCallback errorCallback);
/** /**
@ -38,5 +52,5 @@ public interface Presence {
* *
* @return The server address * @return The server address
*/ */
PeerConnection getProxyConnection(); TcpConnection getProxyConnection();
} }

View file

@ -1,5 +1,8 @@
package fr.insa.clavardator.server; package fr.insa.clavardator.server;
/**
* Static factory class used to create concrete presence server implementations.
*/
public class PresenceFactory { public class PresenceFactory {
public static Presence create(PresenceType type, String uri, int serverPort, int proxyPort) throws UnknownPresenceException { public static Presence create(PresenceType type, String uri, int serverPort, int proxyPort) throws UnknownPresenceException {
switch (type) { switch (type) {

View file

@ -5,7 +5,7 @@ import fr.insa.clavardator.chat.FileMessage;
import fr.insa.clavardator.chat.Message; import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.errors.UsernameTakenException; import fr.insa.clavardator.errors.UsernameTakenException;
import fr.insa.clavardator.network.PeerConnection; import fr.insa.clavardator.network.TcpConnection;
import fr.insa.clavardator.util.ErrorCallback; import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.Log; import fr.insa.clavardator.util.Log;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -19,7 +19,7 @@ import java.util.Date;
public class PeerUser extends User implements Comparable<PeerUser> { public class PeerUser extends User implements Comparable<PeerUser> {
protected transient ChatHistory history; protected transient ChatHistory history;
private State state = State.DISCONNECTED; private State state = State.DISCONNECTED;
private transient PeerConnection connection; private transient TcpConnection connection;
public PeerUser(String id, String username) { public PeerUser(String id, String username) {
super(id, username); super(id, username);
@ -98,12 +98,12 @@ public class PeerUser extends User implements Comparable<PeerUser> {
} }
} }
private void sendUsernameTaken(PeerConnection thisConnection) { private void sendUsernameTaken(TcpConnection thisConnection) {
Log.v(this.getClass().getSimpleName(), "Received username request using current username"); Log.v(this.getClass().getSimpleName(), "Received username request using current username");
thisConnection.send(new UsernameTakenException("Username taken"), this::disconnect, null); thisConnection.send(new UsernameTakenException("Username taken"), this::disconnect, null);
} }
public void init(PeerConnection connection, String id, String username, ErrorCallback errorCallback) { public void init(TcpConnection connection, String id, String username, ErrorCallback errorCallback) {
this.connection = connection; this.connection = connection;
this.id = id; this.id = id;
setUsername(username); setUsername(username);

View file

@ -2,7 +2,7 @@ package fr.insa.clavardator.users;
import fr.insa.clavardator.config.Config; import fr.insa.clavardator.config.Config;
import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.network.ConnectionListener; import fr.insa.clavardator.network.TcpListener;
import fr.insa.clavardator.network.NetDiscoverer; import fr.insa.clavardator.network.NetDiscoverer;
import fr.insa.clavardator.network.PeerHandshake; import fr.insa.clavardator.network.PeerHandshake;
import fr.insa.clavardator.server.Presence; import fr.insa.clavardator.server.Presence;
@ -27,7 +27,7 @@ public class UserList {
private final ObservableList<PeerUser> userObservableList = FXCollections.observableArrayList(); private final ObservableList<PeerUser> userObservableList = FXCollections.observableArrayList();
private final DatabaseController db = new DatabaseController(); private final DatabaseController db = new DatabaseController();
private final NetDiscoverer netDiscoverer = new NetDiscoverer(); private final NetDiscoverer netDiscoverer = new NetDiscoverer();
private final ConnectionListener connectionListener = new ConnectionListener(); private final TcpListener tcpListener = new TcpListener();
private Presence presenceServer; private Presence presenceServer;
@ -74,7 +74,7 @@ public class UserList {
* @param errorCallback Callback on error * @param errorCallback Callback on error
*/ */
public void startUserListening(ErrorCallback errorCallback) { public void startUserListening(ErrorCallback errorCallback) {
connectionListener.acceptConnection( tcpListener.acceptConnection(
(clientSocket) -> { (clientSocket) -> {
Log.v(this.getClass().getSimpleName(), Log.v(this.getClass().getSimpleName(),
"new connection from user at address: " + clientSocket.getInetAddress().toString()); "new connection from user at address: " + clientSocket.getInetAddress().toString());
@ -162,7 +162,7 @@ public class UserList {
*/ */
public void destroy() { public void destroy() {
netDiscoverer.stopDiscovery(); netDiscoverer.stopDiscovery();
connectionListener.stopAccepting(); tcpListener.stopAccepting();
db.close(); db.close();
for (PeerUser user : userHashmap.values()) { for (PeerUser user : userHashmap.values()) {
user.disconnect(); user.disconnect();

View file

@ -0,0 +1,5 @@
package fr.insa.clavardator.util;
public interface ParametrizedCallback<T> {
void call(T param);
}

View file

@ -0,0 +1,5 @@
package fr.insa.clavardator.util;
public interface SimpleCallback {
void call();
}