123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- package fr.insa.clavardator.client.server;
-
- import fr.insa.clavardator.client.users.CurrentUser;
- import fr.insa.clavardator.lib.message.Message;
- import fr.insa.clavardator.lib.network.TcpConnection;
- import fr.insa.clavardator.lib.users.UserInformation;
- import fr.insa.clavardator.lib.util.ErrorCallback;
- import fr.insa.clavardator.lib.util.Log;
- import fr.insa.clavardator.lib.util.ParametrizedCallback;
- import fr.insa.clavardator.lib.util.SimpleCallback;
- import org.jetbrains.annotations.Nullable;
-
- import java.net.InetAddress;
- import java.net.UnknownHostException;
- import java.util.ArrayList;
- import java.util.Arrays;
-
- /**
- * Handles connection to the default INSA Clavardator presence server.
- * <br/>
- * This server does not uses HTTP, everything is done using sockets.
- * The presence server and the proxy each live on a different port.
- * <br/>
- * The client needs to initiate a TCP connection on each port.
- * <br/>
- * On the presence server port, the client will be able to send presence messages
- * such as subscribe, unsubscribe, publish, and receive notifications.
- * <br/>
- * On the proxy port, the client will be able to send regular
- * {@link Message messages} like on the local network.
- * The proxy will forward the message to the appropriate recipient using the provided id.
- */
- public class InsaPresence implements Presence {
-
- private final String path;
- private final int presencePort;
- private final int proxyPort;
-
- private TcpConnection presenceConnection;
- private TcpConnection proxyConnection;
-
-
- public InsaPresence(String path, int presencePort, int proxyPort) {
- this.path = path;
- this.presencePort = presencePort;
- this.proxyPort = proxyPort;
- }
-
- @Override
- public void subscribe(ParametrizedCallback<ArrayList<UserInformation>> callback, ErrorCallback errorCallback) {
- if (!isConnected()) {
- connectToPresence(
- () -> connectToProxy(() -> {
- sendSubscribeMessage(errorCallback);
- receiveSubscribeNotifications(callback, errorCallback);
- }, errorCallback),
- errorCallback);
- } else {
- Log.v(getClass().getSimpleName(), "Already subscribed to presence server");
- }
- }
-
- /**
- * 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
- *
- * @param callback Called when the message is successfully received
- * @param errorCallback Called on connection error
- */
- private void receiveSubscribeNotifications(ParametrizedCallback<ArrayList<UserInformation>> callback, @Nullable ErrorCallback errorCallback) {
- presenceConnection.receive(
- msg -> {
- final ArrayList<UserInformation> userList = new ArrayList<>();
- if (msg instanceof ArrayList<?>) {
- final ArrayList<?> list = (ArrayList<?>) msg;
- for (Object obj : list) {
- if (obj instanceof UserInformation) {
- userList.add((UserInformation) obj);
- }
- }
- Log.v(getClass().getSimpleName(), "Receive subscribe response: " + msg);
- Log.v(getClass().getSimpleName(), "Converted list: " + Arrays.toString(userList.toArray()));
- if (callback != null) {
- callback.call(userList);
- }
- } else {
- Log.e(getClass().getSimpleName(), "Unexpected object received: " + msg.getClass().getSimpleName());
- if (errorCallback != null) {
- errorCallback.onError(new RuntimeException("Unexpected object received"));
- }
- }
- }, errorCallback);
- }
-
- @Override
- public void unsubscribe(SimpleCallback callback, @Nullable ErrorCallback errorCallback) {
- if (isConnected()) {
- disconnect();
- } else {
- Log.v(getClass().getSimpleName(), "Not subscribed to presence server");
- }
- }
-
- /**
- * Connects to the presence server by TCP
- *
- * @param callback Called when connection is successful
- * @param errorCallback Called on connection error
- */
- private void connectToPresence(SimpleCallback callback, ErrorCallback errorCallback) {
- try {
- presenceConnection = new TcpConnection(InetAddress.getByName(path),
- presencePort,
- (newConnection) -> {
- if (callback != null) {
- callback.call();
- }
- },
- errorCallback);
- } catch (UnknownHostException e) {
- Log.e(getClass().getSimpleName(), "Could not connect to presence server", e);
- }
- }
-
- /**
- * Connects to the presence proxy by TCP
- *
- * @param callback Called when connection is successful
- * @param errorCallback Called on connection error
- */
- private void connectToProxy(SimpleCallback callback, ErrorCallback errorCallback) {
- try {
- proxyConnection = new TcpConnection(InetAddress.getByName(path), proxyPort,
- (newConnection) -> newConnection.send(new UserInformation(CurrentUser.getInstance()), () -> {
- if (callback != null) {
- callback.call();
- }
- }, errorCallback),
- errorCallback);
- } catch (UnknownHostException e) {
- Log.e(getClass().getSimpleName(), "Could not connect to presence proxy", e);
- }
- }
-
- /**
- * Closes the given connection
- */
- private void closeConnection(@Nullable TcpConnection c) {
- if (c != null && c.isOpen()) {
- c.close();
- }
- }
-
- /**
- * Checks if we are connected to the presence server and proxy
- *
- * @return True only if we are connected to both presence server and proxy
- */
- private boolean isConnected() {
- return presenceConnection != null &&
- presenceConnection.isOpen() &&
- proxyConnection != null &&
- proxyConnection.isOpen();
- }
-
- /**
- * Disconnects from both presence server and proxy
- */
- private void disconnect() {
- Log.v(this.getClass().getSimpleName(), "Disconnecting presence server");
- closeConnection(presenceConnection);
- closeConnection(proxyConnection);
- presenceConnection = null;
- proxyConnection = null;
- }
-
- @Override
- public TcpConnection getProxyConnection() {
- return proxyConnection;
- }
- }
|