Merge remote-tracking branch 'origin/master'
# Conflicts: # src/main/java/fr/insa/clavardator/ui/MainController.java # src/main/java/fr/insa/clavardator/ui/users/UserListController.java
This commit is contained in:
commit
0e00cbb782
13 changed files with 317 additions and 134 deletions
|
@ -1,18 +1,24 @@
|
||||||
package fr.insa.clavardator;
|
package fr.insa.clavardator;
|
||||||
|
|
||||||
|
import fr.insa.clavardator.network.ConnectionListener;
|
||||||
import fr.insa.clavardator.network.NetDiscoverer;
|
import fr.insa.clavardator.network.NetDiscoverer;
|
||||||
import fr.insa.clavardator.ui.MainController;
|
import fr.insa.clavardator.ui.MainController;
|
||||||
|
import fr.insa.clavardator.users.ActiveUser;
|
||||||
|
import fr.insa.clavardator.users.CurrentUser;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
// See here : https://github.com/jfoenixadmin/JFoenix/blob/master/demo/src/main/java/demos/components/DrawerDemo.java
|
// See here : https://github.com/jfoenixadmin/JFoenix/blob/master/demo/src/main/java/demos/components/DrawerDemo.java
|
||||||
|
|
||||||
public class MainApp extends Application {
|
public class MainApp extends Application {
|
||||||
|
|
||||||
NetDiscoverer netDiscoverer;
|
NetDiscoverer netDiscoverer;
|
||||||
|
private ConnectionListener connectionListener;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
|
@ -20,8 +26,9 @@ public class MainApp extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws Exception {
|
public void start(Stage stage) throws Exception {
|
||||||
// String javaVersion = System.getProperty("java.version");
|
|
||||||
// String javafxVersion = System.getProperty("javafx.version");
|
// Find a place to call this init function
|
||||||
|
CurrentUser.initCurrentUser(1, "Moi");
|
||||||
|
|
||||||
final FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("ui/scene.fxml"));
|
final FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("ui/scene.fxml"));
|
||||||
final MainController main = mainLoader.getController();
|
final MainController main = mainLoader.getController();
|
||||||
|
@ -39,15 +46,33 @@ public class MainApp extends Application {
|
||||||
netDiscoverer = new NetDiscoverer();
|
netDiscoverer = new NetDiscoverer();
|
||||||
|
|
||||||
// Network discovery test
|
// Network discovery test
|
||||||
|
netDiscoverer.startDiscoveryListening("Yohan", null, Throwable::printStackTrace);
|
||||||
netDiscoverer.discoverActiveUsers("Broadcast",
|
netDiscoverer.discoverActiveUsers("Broadcast",
|
||||||
(ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString()),
|
(ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString()),
|
||||||
Throwable::printStackTrace);
|
Throwable::printStackTrace);
|
||||||
netDiscoverer.startDiscoveryListening("Yohan", null, Throwable::printStackTrace);
|
|
||||||
|
// TCP communnication tests
|
||||||
|
connectionListener = new ConnectionListener();
|
||||||
|
connectionListener.acceptConnection(user -> {
|
||||||
|
}, e -> {
|
||||||
|
if (e instanceof java.io.EOFException) {
|
||||||
|
System.out.println("Connexion terminée");
|
||||||
|
} else {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ActiveUser.create(InetAddress.getLocalHost(), user -> {
|
||||||
|
System.out.println("Connexion établie !");
|
||||||
|
user.destroy();
|
||||||
|
},
|
||||||
|
Throwable::printStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
netDiscoverer.stopDiscovery();
|
netDiscoverer.stopDiscovery();
|
||||||
|
connectionListener.stopAccepting();
|
||||||
super.stop();
|
super.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@ package fr.insa.clavardator.chat;
|
||||||
import fr.insa.clavardator.db.DatabaseController;
|
import fr.insa.clavardator.db.DatabaseController;
|
||||||
import fr.insa.clavardator.users.CurrentUser;
|
import fr.insa.clavardator.users.CurrentUser;
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import fr.insa.clavardator.users.UserList;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@ -40,21 +39,19 @@ public class ChatHistory {
|
||||||
public void load() {
|
public void load() {
|
||||||
if (history == null) {
|
if (history == null) {
|
||||||
// TODO remove after tests
|
// TODO remove after tests
|
||||||
CurrentUser currentUser = new CurrentUser("Moi", new UserList());
|
CurrentUser currentUser = CurrentUser.getInstance();
|
||||||
history = new ArrayList<>();
|
history = new ArrayList<>();
|
||||||
history.add(new Message(user, currentUser, "Coucou toi"));
|
history.add(new Message(user, currentUser, "Coucou toi"));
|
||||||
history.add(new Message(currentUser, user, "Coucou " + user.getUsername()));
|
history.add(new Message(currentUser, user, "Coucou " + user.getUsername()));
|
||||||
history.add(new Message(user, currentUser, "oui"));
|
history.add(new Message(user, currentUser, "oui"));
|
||||||
history.add(new Message(currentUser, user, "merci"));
|
history.add(new Message(currentUser, user, "merci"));
|
||||||
notifyHistoryLoaded();
|
|
||||||
// db.getChatHistory(new Date(), new Date(), // TODO: put actual date
|
// db.getChatHistory(new Date(), new Date(), // TODO: put actual date
|
||||||
// newHistory -> {
|
// newHistory -> {
|
||||||
// history = newHistory;
|
// history = newHistory;
|
||||||
// notifyHistoryLoaded();
|
// notifyHistoryLoaded();
|
||||||
// });
|
// });
|
||||||
} else {
|
|
||||||
notifyHistoryLoaded();
|
|
||||||
}
|
}
|
||||||
|
notifyHistoryLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,35 @@ 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;
|
||||||
|
|
||||||
public class ConnectionListener {
|
public class ConnectionListener {
|
||||||
Acceptor acceptor = null;
|
Acceptor acceptor = null;
|
||||||
|
|
||||||
ConnectionListener() {
|
public ConnectionListener() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start accepting incoming connections
|
||||||
|
*
|
||||||
|
* @param callback The function to call when a user connects
|
||||||
|
* @param errorCallback The function to call on errror
|
||||||
|
*/
|
||||||
public void acceptConnection(NewConnectionCallback callback, ErrorCallback errorCallback) {
|
public void acceptConnection(NewConnectionCallback callback, ErrorCallback errorCallback) {
|
||||||
if (acceptor != null) {
|
if (acceptor != null) {
|
||||||
acceptor.stopAccepting();
|
acceptor.stopAccepting();
|
||||||
}
|
}
|
||||||
acceptor = new Acceptor(callback, errorCallback);
|
acceptor = new Acceptor(callback, errorCallback);
|
||||||
|
acceptor.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop accepting incoming connexions.
|
||||||
|
* Must be called before exiting the app.
|
||||||
|
*/
|
||||||
public void stopAccepting() {
|
public void stopAccepting() {
|
||||||
acceptor.stopAccepting();
|
if (acceptor != null)
|
||||||
|
acceptor.stopAccepting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,14 +53,16 @@ public class ConnectionListener {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
server = new ServerSocket(PeerConnection.TCP_PORT);
|
server = new ServerSocket(TCP_PORT);
|
||||||
while (!shouldStop) {
|
while (!shouldStop) {
|
||||||
|
System.out.println("Accepting...");
|
||||||
Socket clientSocket = server.accept();
|
Socket clientSocket = server.accept();
|
||||||
ActiveUser newUser = new ActiveUser(clientSocket);
|
System.out.println("New connection from " + clientSocket.getRemoteSocketAddress());
|
||||||
callback.onNewConnection(newUser);
|
ActiveUser.create(clientSocket, callback::onNewConnection, errorCallback);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
errorCallback.onError(e);
|
if (!shouldStop)
|
||||||
|
errorCallback.onError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +77,7 @@ public class ConnectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface NewConnectionCallback {
|
public interface NewConnectionCallback {
|
||||||
void onNewConnection(ActiveUser user);
|
void onNewConnection(ActiveUser user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,21 +14,30 @@ import java.net.Socket;
|
||||||
public class PeerConnection {
|
public class PeerConnection {
|
||||||
public static final short TCP_PORT = 31598;
|
public static final short TCP_PORT = 31598;
|
||||||
|
|
||||||
Socket socket;
|
private Socket socket;
|
||||||
private final ObjectOutputStream outputStream;
|
private ObjectOutputStream outputStream;
|
||||||
private final ObjectInputStream inputStream;
|
private ObjectInputStream inputStream;
|
||||||
private boolean shouldStop = false;
|
private boolean shouldStop = false;
|
||||||
|
|
||||||
public PeerConnection(InetAddress ipAddr) throws IOException {
|
/**
|
||||||
socket = new Socket(ipAddr, TCP_PORT);
|
* Creates a new connection, and connects to the peer
|
||||||
outputStream = new ObjectOutputStream(socket.getOutputStream());
|
*
|
||||||
inputStream = new ObjectInputStream(socket.getInputStream());
|
* @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 PeerConnection(InetAddress ipAddr, SocketConnectedCallback callback, ErrorCallback errorCallback) {
|
||||||
|
Connector connector = new Connector(ipAddr, callback, errorCallback);
|
||||||
|
connector.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeerConnection(Socket socket) throws IOException {
|
/**
|
||||||
|
* Creates a new connection using an already connected socket
|
||||||
|
*
|
||||||
|
* @param socket A socket already connected to the host
|
||||||
|
*/
|
||||||
|
public PeerConnection(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
outputStream = new ObjectOutputStream(socket.getOutputStream());
|
|
||||||
inputStream = new ObjectInputStream(socket.getInputStream());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +47,7 @@ public class PeerConnection {
|
||||||
* @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 void send(Serializable message, MessageSentCallback callback, ErrorCallback errorCallback) {
|
public void send(Serializable message, @Nullable MessageSentCallback callback, @Nullable ErrorCallback errorCallback) {
|
||||||
Sender sender = new Sender(message, callback, errorCallback);
|
Sender sender = new Sender(message, callback, errorCallback);
|
||||||
sender.start();
|
sender.start();
|
||||||
}
|
}
|
||||||
|
@ -50,15 +59,57 @@ public class PeerConnection {
|
||||||
* @param errorCallback The function to call on error
|
* @param errorCallback The function to call on error
|
||||||
*/
|
*/
|
||||||
public void receive(MessageReceivedCallback callback, ErrorCallback errorCallback) {
|
public void receive(MessageReceivedCallback callback, ErrorCallback errorCallback) {
|
||||||
Receiver receiver = new Receiver(callback, errorCallback);
|
Receiver receiver = new Receiver(callback, errorCallback, true);
|
||||||
receiver.start();
|
receiver.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscibe to all incoming messages from the peer
|
||||||
|
*
|
||||||
|
* @param callback The function to call when a message is received
|
||||||
|
* @param errorCallback The function to call on error
|
||||||
|
*/
|
||||||
|
public void receiveOne(MessageReceivedCallback callback, ErrorCallback errorCallback) {
|
||||||
|
Receiver receiver = new Receiver(callback, errorCallback, false);
|
||||||
|
receiver.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the socket, and silently cancel all running send and receive operations.
|
||||||
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
shouldStop = true;
|
shouldStop = true;
|
||||||
try {
|
if (socket != null) {
|
||||||
socket.close();
|
try {
|
||||||
} catch (IOException ignored) {
|
socket.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Connector extends Thread {
|
||||||
|
private final InetAddress ipAddr;
|
||||||
|
private final SocketConnectedCallback callback;
|
||||||
|
private final ErrorCallback errorCallback;
|
||||||
|
|
||||||
|
public Connector(InetAddress ipAddr, SocketConnectedCallback callback, @Nullable ErrorCallback errorCallback) {
|
||||||
|
this.ipAddr = ipAddr;
|
||||||
|
this.callback = callback;
|
||||||
|
this.errorCallback = errorCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (socket != null) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
socket = new Socket(ipAddr, TCP_PORT);
|
||||||
|
callback.onSocketConnected(PeerConnection.this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (errorCallback != null)
|
||||||
|
errorCallback.onError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +135,9 @@ public class PeerConnection {
|
||||||
@Override
|
@Override
|
||||||
synchronized public void run() {
|
synchronized public void run() {
|
||||||
try {
|
try {
|
||||||
|
if (outputStream == null) {
|
||||||
|
outputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||||
|
}
|
||||||
outputStream.writeObject(message);
|
outputStream.writeObject(message);
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
callback.onMessageSent();
|
callback.onMessageSent();
|
||||||
|
@ -97,7 +151,7 @@ public class PeerConnection {
|
||||||
private class Receiver extends Thread {
|
private class Receiver extends Thread {
|
||||||
private final MessageReceivedCallback callback;
|
private final MessageReceivedCallback callback;
|
||||||
private final ErrorCallback errorCallback;
|
private final ErrorCallback errorCallback;
|
||||||
|
private final boolean loop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a thread that receives a message using the socket of the outer class
|
* Constructs a thread that receives a message using the socket of the outer class
|
||||||
|
@ -105,17 +159,21 @@ public class PeerConnection {
|
||||||
* @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 Receiver(@NotNull MessageReceivedCallback callback, @Nullable ErrorCallback errorCallback) {
|
public Receiver(@NotNull MessageReceivedCallback callback, @Nullable ErrorCallback errorCallback, boolean loop) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.errorCallback = errorCallback;
|
this.errorCallback = errorCallback;
|
||||||
|
this.loop = loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
while(!shouldStop) {
|
if (inputStream == null) {
|
||||||
callback.onMessageReceived(inputStream.readObject());
|
inputStream = new ObjectInputStream(socket.getInputStream());
|
||||||
}
|
}
|
||||||
|
do {
|
||||||
|
callback.onMessageReceived(inputStream.readObject());
|
||||||
|
} while (!shouldStop && loop);
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
if (errorCallback != null && !shouldStop)
|
if (errorCallback != null && !shouldStop)
|
||||||
errorCallback.onError(e);
|
errorCallback.onError(e);
|
||||||
|
@ -124,6 +182,10 @@ public class PeerConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface SocketConnectedCallback {
|
||||||
|
void onSocketConnected(PeerConnection connection);
|
||||||
|
}
|
||||||
|
|
||||||
public interface MessageReceivedCallback {
|
public interface MessageReceivedCallback {
|
||||||
void onMessageReceived(Object msg);
|
void onMessageReceived(Object msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController;
|
||||||
import fr.insa.clavardator.ui.dialogs.SnackbarController;
|
import fr.insa.clavardator.ui.dialogs.SnackbarController;
|
||||||
import fr.insa.clavardator.ui.users.UserListController;
|
import fr.insa.clavardator.ui.users.UserListController;
|
||||||
import fr.insa.clavardator.users.CurrentUser;
|
import fr.insa.clavardator.users.CurrentUser;
|
||||||
import fr.insa.clavardator.users.UserList;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
@ -53,7 +52,7 @@ public class MainController implements Initializable {
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
public void initialize(URL url, ResourceBundle rb) {
|
||||||
snackbar = new JFXSnackbar(root);
|
snackbar = new JFXSnackbar(root);
|
||||||
chatController.setCurrentUser(new CurrentUser("Moi", new UserList()));
|
chatController.setCurrentUser(CurrentUser.getInstance());
|
||||||
userListController.addRefreshUserListener(() -> {
|
userListController.addRefreshUserListener(() -> {
|
||||||
System.out.println("refresh event");
|
System.out.println("refresh event");
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,6 @@ package fr.insa.clavardator.ui.users;
|
||||||
|
|
||||||
import fr.insa.clavardator.ui.ButtonPressEvent;
|
import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||||
import fr.insa.clavardator.ui.UserSelectedEvent;
|
import fr.insa.clavardator.ui.UserSelectedEvent;
|
||||||
import fr.insa.clavardator.users.ActiveUser;
|
|
||||||
import fr.insa.clavardator.users.PeerUser;
|
import fr.insa.clavardator.users.PeerUser;
|
||||||
import fr.insa.clavardator.users.User;
|
import fr.insa.clavardator.users.User;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -11,8 +10,6 @@ import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import fr.insa.clavardator.chat.Message;
|
||||||
import fr.insa.clavardator.network.PeerConnection;
|
import fr.insa.clavardator.network.PeerConnection;
|
||||||
import fr.insa.clavardator.util.ErrorCallback;
|
import fr.insa.clavardator.util.ErrorCallback;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
|
@ -13,44 +12,63 @@ public class ActiveUser extends PeerUser {
|
||||||
|
|
||||||
private final transient PeerConnection connection;
|
private final transient PeerConnection connection;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an active user and connects to him/her
|
* Asynchronously creates a new ActiveUser by receiving information (id, username)
|
||||||
* @param username The username of the new user
|
*
|
||||||
* @param ipAddr The IP address of the new user
|
* @param ipAddr The IP address of the new user
|
||||||
* @throws IOException when an error occurs during the connection
|
* @param callback The function to call on success, with the new ActiveUser as parameter
|
||||||
|
* @param errorCallback The function to call on socket error
|
||||||
*/
|
*/
|
||||||
public ActiveUser(String username, InetAddress ipAddr) throws IOException {
|
public static void create(InetAddress ipAddr, UserCreatedCallback callback, ErrorCallback errorCallback) {
|
||||||
super(username);
|
// Connect to the peer
|
||||||
connection = new PeerConnection(ipAddr);
|
new PeerConnection(ipAddr, (thisConnection) -> {
|
||||||
subscibeToMessages();
|
|
||||||
connection.send(new UsernameChange("", "currentUser.username"), null, null); // TODO: get currentUser + error handling
|
// Send our username
|
||||||
|
String currentUserUsername = CurrentUser.getInstance().getUsername();
|
||||||
|
int currentUserId = CurrentUser.getInstance().getId();
|
||||||
|
thisConnection.send(new UserInformation(currentUserId, currentUserUsername), null, errorCallback);
|
||||||
|
|
||||||
|
// Receive peer's username
|
||||||
|
thisConnection.receiveOne(msg -> {
|
||||||
|
assert msg instanceof UserInformation;
|
||||||
|
UserInformation userInfo = (UserInformation) msg;
|
||||||
|
ActiveUser user = new ActiveUser(userInfo.getId(), userInfo.getUsername(), thisConnection, errorCallback);
|
||||||
|
callback.onUserCreated(user);
|
||||||
|
|
||||||
|
}, errorCallback);
|
||||||
|
}, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActiveUser(Socket socket) throws IOException {
|
/**
|
||||||
super("");
|
* Asynchronously creates a new ActiveUser by receiving information (id, username)
|
||||||
connection = new PeerConnection(socket);
|
*
|
||||||
subscibeToMessages();
|
* @param socket A socket already connected to the user
|
||||||
}
|
* @param callback The function to call on success, with the new ActiveUser as parameter
|
||||||
|
* @param errorCallback The function to call on socket error
|
||||||
|
*/
|
||||||
|
public static void create(Socket socket, UserCreatedCallback callback, ErrorCallback errorCallback) {
|
||||||
|
PeerConnection connection = new PeerConnection(socket);
|
||||||
|
|
||||||
private void subscibeToMessages() {
|
// Send our username
|
||||||
connection.receive(
|
String currentUserUsername = CurrentUser.getInstance().getUsername();
|
||||||
msg -> {
|
int currentUserId = CurrentUser.getInstance().getId();
|
||||||
if (msg.getClass().isInstance(UsernameChange.class)) {
|
connection.send(new UserInformation(currentUserId, currentUserUsername), null, errorCallback);
|
||||||
setUsername(((UsernameChange)msg).getNewUsername());
|
|
||||||
|
|
||||||
} else if (msg.getClass().isInstance(Message.class)) {
|
// Receive peer's username
|
||||||
// TODO
|
connection.receiveOne(msg -> {
|
||||||
}
|
assert msg instanceof UserInformation;
|
||||||
},
|
UserInformation userInfo = (UserInformation) msg;
|
||||||
error -> {
|
ActiveUser user = new ActiveUser(userInfo.getId(), userInfo.getUsername(), connection, errorCallback);
|
||||||
// TODO
|
callback.onUserCreated(user);
|
||||||
});
|
}, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to this peer
|
* Sends a message to this peer
|
||||||
* @param message The message to send
|
*
|
||||||
* @param callback The function to call when the message is sent
|
* @param message The message to send
|
||||||
|
* @param callback The function to call when the message is sent
|
||||||
* @param errorCallback The function to call on error
|
* @param errorCallback The function to call on error
|
||||||
*/
|
*/
|
||||||
public void sendMessage(Message message, PeerConnection.MessageSentCallback callback, ErrorCallback errorCallback) {
|
public void sendMessage(Message message, PeerConnection.MessageSentCallback callback, ErrorCallback errorCallback) {
|
||||||
|
@ -65,4 +83,30 @@ public class ActiveUser extends PeerUser {
|
||||||
connection.close();
|
connection.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ActiveUser(int id, String username, PeerConnection connection, ErrorCallback errorCallback) {
|
||||||
|
super(id, username);
|
||||||
|
this.connection = connection;
|
||||||
|
subscribeToMessages(errorCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void subscribeToMessages(ErrorCallback errorCallback) {
|
||||||
|
connection.receive(
|
||||||
|
msg -> {
|
||||||
|
if (msg.getClass().isInstance(UserInformation.class)) {
|
||||||
|
assert ((UserInformation) msg).getId() == getId();
|
||||||
|
setUsername(((UserInformation) msg).getUsername());
|
||||||
|
|
||||||
|
} else if (msg.getClass().isInstance(Message.class)) {
|
||||||
|
assert ((Message) msg).getRecipient() != this;
|
||||||
|
history.addMessage((Message) msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface UserCreatedCallback {
|
||||||
|
void onUserCreated(ActiveUser user);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,30 @@
|
||||||
package fr.insa.clavardator.users;
|
package fr.insa.clavardator.users;
|
||||||
|
|
||||||
public class CurrentUser extends User {
|
public class CurrentUser extends User {
|
||||||
public CurrentUser(String username, UserList userList) {
|
private static CurrentUser instance = null;
|
||||||
super(username);
|
|
||||||
|
private CurrentUser(int uniqueId, String username) {
|
||||||
|
super(uniqueId, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and returns the current user.
|
||||||
|
*
|
||||||
|
* @param uniqueId the unique id of the current user
|
||||||
|
* @param username The username of the current user
|
||||||
|
*/
|
||||||
|
public static CurrentUser initCurrentUser(int uniqueId, String username) {
|
||||||
|
assert (instance == null);
|
||||||
|
instance = new CurrentUser(uniqueId, username);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current user or null if it has not been initialized yet.
|
||||||
|
*
|
||||||
|
* @see CurrentUser#initCurrentUser(int uniqueId, String username)
|
||||||
|
*/
|
||||||
|
public static CurrentUser getInstance() {
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ public class PeerUser extends User {
|
||||||
|
|
||||||
protected transient ChatHistory history;
|
protected transient ChatHistory history;
|
||||||
|
|
||||||
public PeerUser(String username) {
|
public PeerUser(int id, String username) {
|
||||||
super(username);
|
super(id, username);
|
||||||
history = new ChatHistory(this);
|
history = new ChatHistory(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of history
|
* Get the value of history
|
||||||
*
|
*
|
||||||
|
|
|
@ -7,7 +7,8 @@ import java.beans.PropertyChangeSupport;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class User implements Serializable, Comparable<User> {
|
public class User implements Serializable, Comparable<User> {
|
||||||
protected String username;
|
private String username;
|
||||||
|
public final int id;
|
||||||
|
|
||||||
// Make this class observable
|
// Make this class observable
|
||||||
protected final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
protected final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
@ -18,11 +19,16 @@ public class User implements Serializable, Comparable<User> {
|
||||||
pcs.removePropertyChangeListener(listener);
|
pcs.removePropertyChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User(String username) {
|
public User(int id, String username) {
|
||||||
|
this.id = id;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
21
src/main/java/fr/insa/clavardator/users/UserInformation.java
Normal file
21
src/main/java/fr/insa/clavardator/users/UserInformation.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package fr.insa.clavardator.users;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class UserInformation implements Serializable {
|
||||||
|
private final int id;
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
public UserInformation(int id, String username) {
|
||||||
|
this.id = id;
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,6 @@ import fr.insa.clavardator.db.DatabaseController;
|
||||||
import fr.insa.clavardator.network.NetDiscoverer;
|
import fr.insa.clavardator.network.NetDiscoverer;
|
||||||
import fr.insa.clavardator.util.ErrorCallback;
|
import fr.insa.clavardator.util.ErrorCallback;
|
||||||
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.beans.PropertyChangeSupport;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@ -14,19 +11,57 @@ public class UserList {
|
||||||
|
|
||||||
private ArrayList<ActiveUser> activeUsers;
|
private ArrayList<ActiveUser> activeUsers;
|
||||||
private ArrayList<PeerUser> inactiveUsers;
|
private ArrayList<PeerUser> inactiveUsers;
|
||||||
|
|
||||||
|
private final ArrayList<UserConnectionCallback> activeUsersObservers = new ArrayList<>();
|
||||||
|
|
||||||
private final DatabaseController db = new DatabaseController();
|
private final DatabaseController db = new DatabaseController();
|
||||||
private final NetDiscoverer netDiscoverer = new NetDiscoverer();
|
private final NetDiscoverer netDiscoverer = new NetDiscoverer();
|
||||||
|
|
||||||
// Make this class observable
|
public UserList() {
|
||||||
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
|
||||||
public void addObserver(PropertyChangeListener listener) {
|
|
||||||
pcs.addPropertyChangeListener(listener);
|
|
||||||
}
|
|
||||||
public void removeObserver(PropertyChangeListener listener) {
|
|
||||||
pcs.removePropertyChangeListener(listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserList() {
|
/**
|
||||||
|
* Discover all active users over the network. Observers are notified for each user discovered.
|
||||||
|
*
|
||||||
|
* @param errorCallback The function to call on error
|
||||||
|
* @see UserList#addActiveUserConnectedObserver(UserConnectionCallback)
|
||||||
|
*/
|
||||||
|
public void discoverActiveUsers(ErrorCallback errorCallback) {
|
||||||
|
netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
|
||||||
|
ActiveUser.create(ipAddr, user -> {
|
||||||
|
activeUsers.add(user);
|
||||||
|
notifyObservers(user);
|
||||||
|
}, errorCallback);
|
||||||
|
}, errorCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addActiveUserConnectedObserver(UserConnectionCallback callback) {
|
||||||
|
activeUsersObservers.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyObservers(ActiveUser user) {
|
||||||
|
activeUsersObservers.forEach(callback -> callback.onUserConnected(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests locally if a username is available
|
||||||
|
*
|
||||||
|
* @param username The username to test
|
||||||
|
* @return True if the username is available
|
||||||
|
*/
|
||||||
|
public boolean isUsernameAvailable(String username) {
|
||||||
|
Predicate<User> usernameEqual = user -> user.getUsername().equals(username);
|
||||||
|
return activeUsers.stream().noneMatch(usernameEqual) &&
|
||||||
|
inactiveUsers.stream().noneMatch(usernameEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell all active users that our username changed
|
||||||
|
*
|
||||||
|
* @param username The new username
|
||||||
|
*/
|
||||||
|
public void propagateUsernameChange(String username) {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,38 +76,16 @@ public class UserList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public ArrayList<ActiveUser> getActiveUsers() {
|
||||||
* @param username
|
return activeUsers;
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public boolean isUsernameAvailable(String username) {
|
|
||||||
Predicate<User> usernameEqual = user -> user.username.equals(username);
|
|
||||||
return activeUsers.stream().noneMatch(usernameEqual) &&
|
|
||||||
inactiveUsers.stream().noneMatch(usernameEqual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<PeerUser> getInactiveUsers() {
|
||||||
/**
|
return inactiveUsers;
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
public void propagateUsernameChange(String username) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UserConnectionCallback {
|
||||||
/**
|
void onUserConnected(ActiveUser user);
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void discoverActiveUsers(ErrorCallback errorCallback) {
|
|
||||||
netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
|
|
||||||
ActiveUser newUser = null;
|
|
||||||
try {
|
|
||||||
newUser = new ActiveUser("", ipAddr); // TODO find username
|
|
||||||
} catch (IOException e) {
|
|
||||||
errorCallback.onError(e);
|
|
||||||
}
|
|
||||||
activeUsers.add(newUser);
|
|
||||||
pcs.firePropertyChange("activeUsers", null, newUser);
|
|
||||||
}, errorCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package fr.insa.clavardator.users;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class UsernameChange implements Serializable {
|
|
||||||
private final String prevUsername; // Not sure if this is useful
|
|
||||||
private final String newUsername;
|
|
||||||
|
|
||||||
public UsernameChange(String previousUsername, String newUsername) {
|
|
||||||
this.prevUsername = previousUsername;
|
|
||||||
this.newUsername = newUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPreviousUsername() {
|
|
||||||
return prevUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNewUsername() {
|
|
||||||
return newUsername;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue