Put id in User, async create and init ActiveUser, make CurrentUser singleton

This commit is contained in:
Yohan Simard 2020-12-05 00:30:30 +01:00
parent 2fe0289f9f
commit 0e8ded05c9
13 changed files with 328 additions and 152 deletions

View file

@ -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();
} }
} }

View file

@ -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();
} }

View file

@ -7,20 +7,34 @@ 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() {
if (acceptor != null)
acceptor.stopAccepting(); acceptor.stopAccepting();
} }
@ -39,13 +53,15 @@ 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) {
if (!shouldStop)
errorCallback.onError(e); errorCallback.onError(e);
} }
@ -61,7 +77,7 @@ public class ConnectionListener {
} }
interface NewConnectionCallback { public interface NewConnectionCallback {
void onNewConnection(ActiveUser user); void onNewConnection(ActiveUser user);
} }
} }

View file

@ -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,17 +59,59 @@ 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;
if (socket != null) {
try { try {
socket.close(); socket.close();
} catch (IOException ignored) { } 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);
}
}
}
private class Sender extends Thread { private class Sender extends Thread {
@ -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);
} }

View file

@ -3,7 +3,6 @@ package fr.insa.clavardator.ui;
import fr.insa.clavardator.ui.chat.ChatController; import fr.insa.clavardator.ui.chat.ChatController;
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.Initializable; import javafx.fxml.Initializable;
@ -19,7 +18,7 @@ public class MainController implements Initializable {
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
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");
}); });

View file

@ -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;
@ -53,24 +50,17 @@ public class UserListController implements Initializable {
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
ObservableList<PeerUser> activeList = null; ObservableList<PeerUser> activeList = FXCollections.observableArrayList(
try { new PeerUser(1, "Dodo0"),
activeList = FXCollections.observableArrayList( new PeerUser(2, "Dodo3"),
new PeerUser("Dodo0"), new PeerUser(3, "Dodo2"),
new PeerUser("Dodo3"), // new ActiveUser(4, "Coucou0", InetAddress.getLocalHost()),
new PeerUser("Dodo2"), // new ActiveUser(5, "Coucou1", InetAddress.getLocalHost()),
new ActiveUser("Coucou0", InetAddress.getLocalHost()), // new ActiveUser(6, "Coucou3", InetAddress.getLocalHost()),
new ActiveUser("Coucou1", InetAddress.getLocalHost()), new PeerUser(7, "Dodo1")
new ActiveUser("Coucou3", InetAddress.getLocalHost()), // new ActiveUser(8, "Coucou2", InetAddress.getLocalHost())
new PeerUser("Dodo1"),
new ActiveUser("Coucou2", InetAddress.getLocalHost())
); );
} catch (IOException e) {
e.printStackTrace();
}
if (activeList != null) {
activeList.sort(null); activeList.sort(null);
}
userList.setItems(activeList); userList.setItems(activeList);
userList.setCellFactory(listView -> { userList.setCellFactory(listView -> {
final UserListItemCell cell = new UserListItemCell(); final UserListItemCell cell = new UserListItemCell();

View file

@ -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,42 +12,61 @@ 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 message The message to send
* @param callback The function to call when the message is sent * @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
@ -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);
}
} }

View file

@ -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;
} }
} }

View file

@ -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
* *

View file

@ -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;
} }

View 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;
}
}

View file

@ -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);
} }
} }

View file

@ -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;
}
}