Allow sending username updates

This commit is contained in:
Arnaud Vergnet 2021-01-27 10:13:13 +01:00
parent d51cbc6d75
commit 60fa5adfe4
6 changed files with 76 additions and 30 deletions

View file

@ -44,11 +44,11 @@ public class InsaPresence implements Presence {
} }
@Override @Override
public void subscribe(ParametrizedCallback<ArrayList<UserInformation>> callback, ErrorCallback errorCallback) { public void subscribe(UserInformation userInformation, ParametrizedCallback<ArrayList<UserInformation>> callback, ErrorCallback errorCallback) {
if (!isConnected()) { if (!isConnected()) {
connectToPresence( connectToPresence(
() -> proxy.connect(() -> { () -> proxy.connect(() -> {
sendSubscribeMessage(errorCallback); notify(userInformation, null, errorCallback);
receiveSubscribeNotifications(callback, errorCallback); receiveSubscribeNotifications(callback, errorCallback);
}, errorCallback), }, errorCallback),
errorCallback); errorCallback);
@ -57,15 +57,6 @@ public class InsaPresence implements Presence {
} }
} }
/**
* Send current user information to tell the server who is subscribing
*
* @param errorCallback Called on connection error
*/
private void sendSubscribeMessage(ErrorCallback errorCallback) {
presenceConnection.send(new UserInformation(CurrentUser.getInstance()), null, errorCallback);
}
/** /**
* Waits for presence server response to the subscribe request * Waits for presence server response to the subscribe request
* *
@ -106,6 +97,11 @@ public class InsaPresence implements Presence {
} }
} }
@Override
public void notify(UserInformation newInformation, @Nullable SimpleCallback callback, @Nullable ErrorCallback errorCallback) {
presenceConnection.send(newInformation, callback, errorCallback);
}
/** /**
* Connects to the presence server by TCP * Connects to the presence server by TCP
* *

View file

@ -18,12 +18,12 @@ import java.util.ArrayList;
public interface Presence { public interface Presence {
/** /**
* Subscribes to this presence server notifications. * Subscribes to this presence server notifications and publish current status.
* A list of Ids representing the current active users is returned. * A list of Ids representing the current active users is returned.
* *
* @param callback Called when subscription completes * @param callback Called when subscription completes
*/ */
void subscribe(ParametrizedCallback<ArrayList<UserInformation>> callback, @Nullable ErrorCallback errorCallback); void subscribe(UserInformation userInformation, ParametrizedCallback<ArrayList<UserInformation>> callback, @Nullable ErrorCallback errorCallback);
/** /**
* Stops subscription to the presence server by closing TCP connections. * Stops subscription to the presence server by closing TCP connections.
@ -34,6 +34,14 @@ public interface Presence {
*/ */
void unsubscribe(SimpleCallback callback, @Nullable ErrorCallback errorCallback); void unsubscribe(SimpleCallback callback, @Nullable ErrorCallback errorCallback);
/**
* Notifies the presence server of any changes to the current user
*
* @param newInformation The new information to send
* @param callback Called when notify completes
*/
void notify(UserInformation newInformation, @Nullable SimpleCallback callback, @Nullable ErrorCallback errorCallback);
/** /**
* Gets the proxy. * Gets the proxy.
* This can be used to initialize a * This can be used to initialize a

View file

@ -15,6 +15,7 @@ import fr.insa.clavardator.client.ui.dialogs.SnackbarController;
import fr.insa.clavardator.client.ui.users.UserListController; import fr.insa.clavardator.client.ui.users.UserListController;
import fr.insa.clavardator.client.users.CurrentUser; import fr.insa.clavardator.client.users.CurrentUser;
import fr.insa.clavardator.client.users.UserList; import fr.insa.clavardator.client.users.UserList;
import fr.insa.clavardator.lib.users.UserInformation;
import fr.insa.clavardator.lib.util.Log; import fr.insa.clavardator.lib.util.Log;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -59,13 +60,31 @@ public class MainController implements Initializable {
online = false; online = false;
currentUser = CurrentUser.getInstance(); currentUser = CurrentUser.getInstance();
currentUser.addObserver(propertyChangeEvent -> { currentUser.addObserver(propertyChangeEvent -> {
if (propertyChangeEvent.getPropertyName().equals("state")) { final String propertyName = propertyChangeEvent.getPropertyName();
if (propertyName.equals("state")) {
final CurrentUser.State newState = (CurrentUser.State) propertyChangeEvent.getNewValue(); final CurrentUser.State newState = (CurrentUser.State) propertyChangeEvent.getNewValue();
onCurrentUserStateChange(newState); onCurrentUserStateChange(newState);
} else if (propertyName.equals("username")) {
final String newUsername = (String) propertyChangeEvent.getNewValue();
onCurrentUserNameChange(newUsername);
} }
}); });
} }
private void onCurrentUserNameChange(String newUsername) {
if (online) {
if (userList != null) {
userList.propagateUsernameChange();
}
if (presenceServer != null) {
presenceServer.notify(
new UserInformation(CurrentUser.getInstance().getId(), newUsername),
null,
null);
}
}
}
/** /**
* If the current user becomes valid, start the chat. * If the current user becomes valid, start the chat.
* If it is invalid or not set, show the login screen. * If it is invalid or not set, show the login screen.
@ -286,6 +305,7 @@ public class MainController implements Initializable {
private void subscribeToPresenceServer() { private void subscribeToPresenceServer() {
if (presenceServer != null && online) { if (presenceServer != null && online) {
presenceServer.subscribe( presenceServer.subscribe(
new UserInformation(CurrentUser.getInstance()),
param -> userList.onReceivePresenceNotification( param -> userList.onReceivePresenceNotification(
param, param,
presenceServer.getProxy()), presenceServer.getProxy()),

View file

@ -7,6 +7,8 @@ import com.jfoenix.validation.base.ValidatorBase;
import fr.insa.clavardator.client.ui.ButtonPressEvent; import fr.insa.clavardator.client.ui.ButtonPressEvent;
import fr.insa.clavardator.client.users.CurrentUser; import fr.insa.clavardator.client.users.CurrentUser;
import fr.insa.clavardator.client.users.UserList; import fr.insa.clavardator.client.users.UserList;
import fr.insa.clavardator.lib.util.ParametrizedCallback;
import fr.insa.clavardator.lib.util.SimpleCallback;
import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -179,9 +181,6 @@ public class EditUsernameDialogController implements Initializable {
if (successListener != null) { if (successListener != null) {
successListener.onPress(); successListener.onPress();
} }
if (userList != null) {
userList.propagateUsernameChange();
}
} }
/** /**

View file

@ -54,18 +54,20 @@ public class UserList {
if (savedUser != null) { if (savedUser != null) {
if (savedUser.isActive()) { if (savedUser.isActive()) {
if (userInfo.getState() == UserState.DISCONNECTED) { if (userInfo.getState() == UserState.DISCONNECTED) {
Log.v(getClass().getSimpleName(), "Received disconnected user from presence server already known and connected, disconnecting..."); Log.v(getClass().getSimpleName(), "Received disconnected user from presence server was already known and connected, disconnecting...");
savedUser.disconnect(); savedUser.disconnect();
} else { } else {
Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected"); Log.v(getClass().getSimpleName(), "Received user from presence server was already known and connected, updating info...");
savedUser.setState(userInfo.getState());
savedUser.setUsername(userInfo.getUsername());
} }
} else { } else {
if (userInfo.getState() == UserState.CONNECTED) { if (userInfo.getState() == UserState.CONNECTED) {
Log.v(getClass().getSimpleName(), "Received user from presence server already known but not connected, connecting..."); Log.v(getClass().getSimpleName(), "Received user from presence server was already known but not connected, connecting...");
savedUser.init(proxy, userInfo.id, userInfo.getUsername(), savedUser.init(proxy, userInfo.id, userInfo.getUsername(),
e -> Log.e(getClass().getSimpleName(), "Error with user " + userInfo.getUsername(), e)); e -> Log.e(getClass().getSimpleName(), "Error with user " + userInfo.getUsername(), e));
} else { } else {
Log.v(getClass().getSimpleName(), "Received disconnected user from presence server already known and not connected."); Log.v(getClass().getSimpleName(), "Received disconnected user from presence server was already known and disconnected.");
} }
} }
} else { } else {

View file

@ -12,6 +12,7 @@ import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
public class Presence { public class Presence {
private static final int PRESENCE_PORT = 35650; private static final int PRESENCE_PORT = 35650;
@ -29,17 +30,30 @@ public class Presence {
public void publish(UserInformation info) { public void publish(UserInformation info) {
ArrayList<UserInformation> msg = new ArrayList<>(1); ArrayList<UserInformation> msg = new ArrayList<>(1);
msg.add(info); msg.add(info);
for (TcpConnection subscriber : subscribers.values()) { for (Map.Entry<String,TcpConnection> entry : subscribers.entrySet()) {
subscriber.send(msg, null, // Do not send update to self
e -> Log.e(getClass().getSimpleName(), "Error while publishing user information", e)); if (!entry.getKey().equals(info.id)) {
entry.getValue().send(msg, null,
e -> Log.e(getClass().getSimpleName(), "Error while publishing user information", e));
}
} }
} }
private void updateUser(UserInformation userInformation) {
connectedUsers.removeIf(ui -> userInformation.id.equals(ui.id));
connectedUsers.add(userInformation);
}
private void adduser(UserInformation userInformation, TcpConnection userConnection) {
subscribers.put(userInformation.id, userConnection);
connectedUsers.add(userInformation);
}
public void subscribe(Socket socket) { public void subscribe(Socket socket) {
TcpConnection user = new TcpConnection(socket); TcpConnection userConnection = new TcpConnection(socket);
// Receive user information // Receive user information
user.receiveOne(o -> { userConnection.receiveOne(o -> {
if (o instanceof UserInformation) { if (o instanceof UserInformation) {
UserInformation userInformation = ((UserInformation) o); UserInformation userInformation = ((UserInformation) o);
Log.v(getClass().getSimpleName(), "Registering user " + userInformation.id + Log.v(getClass().getSimpleName(), "Registering user " + userInformation.id +
@ -50,13 +64,20 @@ public class Presence {
// Send the list of connected users to the new subscriber. We're cloning it because we're modifying it // Send the list of connected users to the new subscriber. We're cloning it because we're modifying it
// just after this call, while the sender thread might not have send it yet // just after this call, while the sender thread might not have send it yet
user.send((Serializable) connectedUsers.clone(), null, userConnection.send((Serializable) connectedUsers.clone(), null,
e -> Log.e(getClass().getSimpleName(), "Error while receiving user information", e)); e -> Log.e(getClass().getSimpleName(), "Error while receiving user information", e));
subscribers.put(userInformation.id, user); adduser(userInformation, userConnection);
connectedUsers.add(userInformation);
user.receive(msg -> Log.w(getClass().getSimpleName(), "Received an unexpected message " + msg), userConnection.receive(msg -> {
if (msg instanceof UserInformation) {
UserInformation newUserInformation = ((UserInformation) msg);
Log.v(getClass().getSimpleName(), "Receiving user status update " + newUserInformation.id +
" (" + newUserInformation.getUsername() + ")");
updateUser(newUserInformation);
publish(newUserInformation);
}
},
e -> { e -> {
if (e instanceof EOFException) { if (e instanceof EOFException) {
unsubscribe(userInformation); unsubscribe(userInformation);