Browse Source

[WIP] Integrate server to the project

Many bugs are yet to fix
Yohan Simard 3 years ago
parent
commit
32364461be

+ 1
- 0
.gitignore View File

@@ -17,3 +17,4 @@ gradle-app.setting
17 17
 # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
18 18
 # gradle/wrapper/gradle-wrapper.properties
19 19
 /out/
20
+/clavardator_stored_files/

+ 1
- 0
.idea/gradle.xml View File

@@ -11,6 +11,7 @@
11 11
             <option value="$PROJECT_DIR$" />
12 12
             <option value="$PROJECT_DIR$/client" />
13 13
             <option value="$PROJECT_DIR$/lib" />
14
+            <option value="$PROJECT_DIR$/server" />
14 15
           </set>
15 16
         </option>
16 17
       </GradleProjectSettings>

+ 1
- 1
client/config.json View File

@@ -1,7 +1,7 @@
1 1
 {
2 2
   "serveur": {
3 3
     "actif": 1,
4
-    "uri": "test",
4
+    "uri": "localhost",
5 5
     "type": "INSA",
6 6
     "ports": {
7 7
       "presence": 35650,

+ 0
- 9
client/src/main/java/fr/insa/clavardator/client/errors/UsernameTakenException.java View File

@@ -1,9 +0,0 @@
1
-package fr.insa.clavardator.client.errors;
2
-
3
-import java.io.Serializable;
4
-
5
-public class UsernameTakenException extends Exception implements Serializable {
6
-	public UsernameTakenException(String message) {
7
-		super(message);
8
-	}
9
-}

+ 2
- 2
client/src/main/java/fr/insa/clavardator/client/network/PeerHandshake.java View File

@@ -1,7 +1,7 @@
1 1
 package fr.insa.clavardator.client.network;
2 2
 
3
-import fr.insa.clavardator.client.errors.UsernameTakenException;
4 3
 import fr.insa.clavardator.client.users.CurrentUser;
4
+import fr.insa.clavardator.lib.errors.UsernameTakenException;
5 5
 import fr.insa.clavardator.lib.network.TcpConnection;
6 6
 import fr.insa.clavardator.lib.users.UserInformation;
7 7
 import fr.insa.clavardator.lib.util.ErrorCallback;
@@ -71,7 +71,7 @@ public class PeerHandshake {
71 71
 
72 72
 	private void sendUsernameTaken(TcpConnection thisConnection) {
73 73
 		Log.v(this.getClass().getSimpleName(), "Received username request using current username");
74
-		thisConnection.send(new UsernameTakenException("Username taken"), this::closeConnection, null);
74
+		thisConnection.send(new UsernameTakenException("Username taken", userInformation.id), this::closeConnection, null);
75 75
 	}
76 76
 
77 77
 

+ 15
- 11
client/src/main/java/fr/insa/clavardator/client/server/InsaPresence.java View File

@@ -1,8 +1,8 @@
1 1
 package fr.insa.clavardator.client.server;
2 2
 
3
-import fr.insa.clavardator.lib.network.TcpConnection;
4 3
 import fr.insa.clavardator.client.users.CurrentUser;
5 4
 import fr.insa.clavardator.lib.message.Message;
5
+import fr.insa.clavardator.lib.network.TcpConnection;
6 6
 import fr.insa.clavardator.lib.users.UserInformation;
7 7
 import fr.insa.clavardator.lib.util.ErrorCallback;
8 8
 import fr.insa.clavardator.lib.util.Log;
@@ -83,14 +83,19 @@ public class InsaPresence implements Presence {
83 83
 						final ArrayList<?> list = (ArrayList<?>) msg;
84 84
 						for (Object obj : list) {
85 85
 							if (obj instanceof UserInformation) {
86
-								userList.add((UserInformation)obj);
86
+								userList.add((UserInformation) obj);
87 87
 							}
88 88
 						}
89
-					}
90
-					Log.v(getClass().getSimpleName(), "Receive subscribe response: " + msg);
91
-					Log.v(getClass().getSimpleName(), "Converted list: " + Arrays.toString(userList.toArray()));
92
-					if (callback != null) {
93
-						callback.call(userList);
89
+						Log.v(getClass().getSimpleName(), "Receive subscribe response: " + msg);
90
+						Log.v(getClass().getSimpleName(), "Converted list: " + Arrays.toString(userList.toArray()));
91
+						if (callback != null) {
92
+							callback.call(userList);
93
+						}
94
+					} else {
95
+						Log.e(getClass().getSimpleName(), "Unexpected object received: " + msg.getClass().getSimpleName());
96
+						if (errorCallback != null) {
97
+							errorCallback.onError(new RuntimeException("Unexpected object received"));
98
+						}
94 99
 					}
95 100
 				}, errorCallback);
96 101
 	}
@@ -133,13 +138,12 @@ public class InsaPresence implements Presence {
133 138
 	 */
134 139
 	private void connectToProxy(SimpleCallback callback, ErrorCallback errorCallback) {
135 140
 		try {
136
-			proxyConnection = new TcpConnection(InetAddress.getByName(path),
137
-					proxyPort,
138
-					(newConnection) -> {
141
+			proxyConnection = new TcpConnection(InetAddress.getByName(path), proxyPort,
142
+					(newConnection) -> newConnection.send(new UserInformation(CurrentUser.getInstance()), () -> {
139 143
 						if (callback != null) {
140 144
 							callback.call();
141 145
 						}
142
-					},
146
+					}, errorCallback),
143 147
 					errorCallback);
144 148
 		} catch (UnknownHostException e) {
145 149
 			Log.e(getClass().getSimpleName(), "Could not connect to presence proxy", e);

+ 3
- 3
client/src/main/java/fr/insa/clavardator/client/users/PeerUser.java View File

@@ -1,10 +1,10 @@
1 1
 package fr.insa.clavardator.client.users;
2 2
 
3 3
 import fr.insa.clavardator.client.chat.ChatHistory;
4
+import fr.insa.clavardator.client.db.DatabaseController;
5
+import fr.insa.clavardator.lib.errors.UsernameTakenException;
4 6
 import fr.insa.clavardator.lib.message.FileMessage;
5 7
 import fr.insa.clavardator.lib.message.Message;
6
-import fr.insa.clavardator.client.db.DatabaseController;
7
-import fr.insa.clavardator.client.errors.UsernameTakenException;
8 8
 import fr.insa.clavardator.lib.network.TcpConnection;
9 9
 import fr.insa.clavardator.lib.users.User;
10 10
 import fr.insa.clavardator.lib.users.UserInformation;
@@ -102,7 +102,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
102 102
 
103 103
 	private void sendUsernameTaken(TcpConnection thisConnection) {
104 104
 		Log.v(this.getClass().getSimpleName(), "Received username request using current username");
105
-		thisConnection.send(new UsernameTakenException("Username taken"), this::disconnect, null);
105
+		thisConnection.send(new UsernameTakenException("Username taken", getId()), this::disconnect, null);
106 106
 	}
107 107
 
108 108
 	public void init(TcpConnection connection, String id, String username, ErrorCallback errorCallback) {

+ 1
- 1
client/src/main/java/fr/insa/clavardator/client/users/UserList.java View File

@@ -54,7 +54,7 @@ public class UserList {
54 54
 				if (savedUser.isActive()) {
55 55
 					Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
56 56
 				} else {
57
-					Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
57
+					Log.v(getClass().getSimpleName(), "Received user from presence server already known but not connected, connecting...");
58 58
 					savedUser.init(proxyConnection, userInfo.id, userInfo.getUsername(), null);
59 59
 				}
60 60
 			} else {

+ 12
- 0
lib/src/main/java/fr/insa/clavardator/lib/errors/UsernameTakenException.java View File

@@ -0,0 +1,12 @@
1
+package fr.insa.clavardator.lib.errors;
2
+
3
+import java.io.Serializable;
4
+
5
+public class UsernameTakenException extends Exception implements Serializable {
6
+	public final String recipient;
7
+
8
+	public UsernameTakenException(String message, String recipient) {
9
+		super(message);
10
+		this.recipient = recipient;
11
+	}
12
+}

+ 11
- 3
lib/src/main/java/fr/insa/clavardator/lib/network/TcpListener.java View File

@@ -10,10 +10,16 @@ import static fr.insa.clavardator.lib.network.TcpConnection.TCP_PORT;
10 10
 
11 11
 public class TcpListener {
12 12
 	Acceptor acceptor = null;
13
+	int port = TCP_PORT;
13 14
 
14 15
 	public TcpListener() {
15 16
 	}
16 17
 
18
+	public TcpListener(int port) {
19
+		this.port = port;
20
+	}
21
+
22
+
17 23
 	/**
18 24
 	 * Start accepting incoming connections
19 25
 	 *
@@ -24,7 +30,7 @@ public class TcpListener {
24 30
 		if (acceptor != null) {
25 31
 			acceptor.stopAccepting();
26 32
 		}
27
-		acceptor = new Acceptor(callback, errorCallback);
33
+		acceptor = new Acceptor(port, callback, errorCallback);
28 34
 		acceptor.start();
29 35
 	}
30 36
 
@@ -43,8 +49,10 @@ public class TcpListener {
43 49
 		private final NewConnectionCallback callback;
44 50
 		private final ErrorCallback errorCallback;
45 51
 		private ServerSocket server;
52
+		private int port;
46 53
 
47
-		public Acceptor(NewConnectionCallback callback, ErrorCallback errorCallback) {
54
+		public Acceptor(int port, NewConnectionCallback callback, ErrorCallback errorCallback) {
55
+			this.port = port;
48 56
 			this.callback = callback;
49 57
 			this.errorCallback = errorCallback;
50 58
 		}
@@ -52,7 +60,7 @@ public class TcpListener {
52 60
 		@Override
53 61
 		public void run() {
54 62
 			try {
55
-				server = new ServerSocket(TCP_PORT);
63
+				server = new ServerSocket(port);
56 64
 				while (!shouldStop) {
57 65
 					Socket clientSocket = server.accept();
58 66
 					callback.onNewConnection(clientSocket);

+ 18
- 0
server/build.gradle View File

@@ -0,0 +1,18 @@
1
+plugins {
2
+    id 'application'
3
+    id 'com.github.johnrengelman.shadow' version '6.1.0'
4
+}
5
+
6
+group 'fr.insa.clavardator.server'
7
+version '0.0.1'
8
+
9
+repositories {
10
+    mavenCentral()
11
+}
12
+
13
+dependencies {
14
+    implementation project(':lib')
15
+    implementation 'org.jetbrains:annotations:20.1.0'
16
+}
17
+
18
+mainClassName = 'fr.insa.clavardator.server.Main'

+ 24
- 0
server/src/main/java/fr/insa/clavardator/server/Main.java View File

@@ -0,0 +1,24 @@
1
+package fr.insa.clavardator.server;
2
+
3
+import fr.insa.clavardator.lib.util.Log;
4
+
5
+import java.util.Scanner;
6
+
7
+public class Main {
8
+
9
+	public static void main(String[] args) {
10
+		Log.v(Main.class.getSimpleName(), "Server started! You can stop it by typing stop");
11
+
12
+		Proxy proxy = new Proxy();
13
+		Presence presence = new Presence();
14
+
15
+		String line;
16
+		Scanner scanner = new Scanner(System.in);
17
+		do {
18
+			line = scanner.nextLine();
19
+		} while (!line.equals("stop"));
20
+
21
+		proxy.stop();
22
+		presence.stop();
23
+	}
24
+}

+ 87
- 0
server/src/main/java/fr/insa/clavardator/server/Presence.java View File

@@ -0,0 +1,87 @@
1
+package fr.insa.clavardator.server;
2
+
3
+import fr.insa.clavardator.lib.network.TcpConnection;
4
+import fr.insa.clavardator.lib.network.TcpListener;
5
+import fr.insa.clavardator.lib.users.UserInformation;
6
+import fr.insa.clavardator.lib.util.Log;
7
+
8
+import java.io.EOFException;
9
+import java.io.Serializable;
10
+import java.net.Socket;
11
+import java.util.ArrayList;
12
+import java.util.HashMap;
13
+import java.util.Map;
14
+
15
+public class Presence {
16
+	private static final int PRESENCE_PORT = 35650;
17
+
18
+	private final Map<String, TcpConnection> subscribers = new HashMap<>();
19
+	private final ArrayList<UserInformation> connectedUsers = new ArrayList<>();
20
+	private final TcpListener presenceListener;
21
+
22
+	public Presence() {
23
+		presenceListener = new TcpListener(PRESENCE_PORT);
24
+		presenceListener.acceptConnection(this::subscribe,
25
+				e -> Log.e(getClass().getSimpleName(), "Error while registering a user", e));
26
+	}
27
+
28
+	public void publish(UserInformation info) {
29
+		for (TcpConnection subscriber : subscribers.values()) {
30
+			ArrayList<UserInformation> msg = new ArrayList<>(1);
31
+			msg.add(info);
32
+			subscriber.send(msg, null,
33
+					e -> Log.e(getClass().getSimpleName(), "Error while publishing user information", e));
34
+		}
35
+	}
36
+
37
+	public void subscribe(Socket socket) {
38
+		TcpConnection user = new TcpConnection(socket);
39
+
40
+		// Receive user information
41
+		user.receiveOne(o -> {
42
+			if (o instanceof UserInformation) {
43
+				UserInformation userInformation = ((UserInformation) o);
44
+				Log.v(getClass().getSimpleName(), "Registering user " + userInformation.id +
45
+						" (" + userInformation.getUsername() + ")");
46
+
47
+				// publish new user info to all subscribers
48
+				publish(userInformation);
49
+
50
+				// Send the list of connected users to the new subscriber. We're cloning it because we're modifying it
51
+				// just after this call, while the sender thread might not have send it yet
52
+				user.send((Serializable) connectedUsers.clone(), null,
53
+						e -> Log.e(getClass().getSimpleName(), "Error while receiving user information", e));
54
+
55
+				subscribers.put(userInformation.id, user);
56
+				connectedUsers.add(userInformation);
57
+
58
+				user.receive(msg -> Log.w(getClass().getSimpleName(), "Received an unexpected message " + msg),
59
+						e -> {
60
+							if (e instanceof EOFException) {
61
+								unsubscribe(userInformation.id);
62
+							}
63
+						});
64
+			} else {
65
+				Log.e(getClass().getSimpleName(), "Received unexpected message type: " + o.getClass().getSimpleName());
66
+			}
67
+		}, e -> {
68
+			if (!(e instanceof EOFException)) {
69
+				Log.e(getClass().getSimpleName(), "Error while receiving user information", e);
70
+			}
71
+		});
72
+	}
73
+
74
+	public void unsubscribe(String id) {
75
+		Log.v(getClass().getSimpleName(), "Unsubscribing user " + id);
76
+		subscribers.get(id).close();
77
+		subscribers.remove(id);
78
+		connectedUsers.removeIf(userInformation -> userInformation.id.equals(id));
79
+	}
80
+
81
+	public void stop() {
82
+		presenceListener.stopAccepting();
83
+		for (TcpConnection connection : subscribers.values()) {
84
+			connection.close();
85
+		}
86
+	}
87
+}

+ 80
- 0
server/src/main/java/fr/insa/clavardator/server/Proxy.java View File

@@ -0,0 +1,80 @@
1
+package fr.insa.clavardator.server;
2
+
3
+import fr.insa.clavardator.lib.errors.UsernameTakenException;
4
+import fr.insa.clavardator.lib.message.Message;
5
+import fr.insa.clavardator.lib.network.TcpConnection;
6
+import fr.insa.clavardator.lib.network.TcpListener;
7
+import fr.insa.clavardator.lib.users.UserInformation;
8
+import fr.insa.clavardator.lib.util.Log;
9
+
10
+import java.io.EOFException;
11
+import java.io.Serializable;
12
+import java.util.HashMap;
13
+import java.util.Map;
14
+
15
+public class Proxy {
16
+	private static final int PROXY_PORT = 35750;
17
+	private final HashMap<String, TcpConnection> users = new HashMap<>();
18
+	private final TcpListener proxyListener;
19
+
20
+	public Proxy() {
21
+		proxyListener = new TcpListener(PROXY_PORT);
22
+		proxyListener.acceptConnection(clientSocket -> {
23
+
24
+					Log.v(getClass().getSimpleName(), "Accepting a new user");
25
+					TcpConnection connection = new TcpConnection(clientSocket);
26
+					connection.receive(msg -> {
27
+
28
+						if (msg instanceof Message) {
29
+							Log.v(getClass().getSimpleName(), "Transmitting message: " + msg);
30
+							transmitMessage((Serializable) msg, ((Message) msg).getRecipient().id);
31
+
32
+						} else if (msg instanceof UsernameTakenException) {
33
+							UsernameTakenException unameTaken = ((UsernameTakenException) msg);
34
+							transmitMessage(unameTaken, unameTaken.recipient);
35
+
36
+						} else if (msg instanceof UserInformation) {
37
+							Log.v(getClass().getSimpleName(), "Registering new user: " + msg);
38
+							users.put(((UserInformation) msg).id, connection);
39
+							for (String userId : users.keySet()) {
40
+								UserInformation userInfo = ((UserInformation) msg);
41
+								if (!userId.equals(userInfo.id)) {
42
+									transmitMessage((Serializable) msg, userId);
43
+								}
44
+							}
45
+						}
46
+
47
+					}, e -> {
48
+						if (e instanceof EOFException) {
49
+							for (Map.Entry<String, TcpConnection> user : users.entrySet()) {
50
+								if (user.getValue().equals(connection)) {
51
+									Log.v(getClass().getSimpleName(), "Disconnecting user " + user.getKey());
52
+									users.remove(user.getKey());
53
+									break;
54
+								}
55
+							}
56
+						} else {
57
+							Log.e(getClass().getSimpleName(), "Error while receiving message to transmit", e);
58
+						}
59
+					});
60
+				},
61
+				e -> Log.e(getClass().getSimpleName(), "Error while accepting a user", e));
62
+	}
63
+
64
+
65
+	void transmitMessage(Serializable msg, String recipientId) {
66
+		TcpConnection user = users.get(recipientId);
67
+		if (user == null) {
68
+			Log.e(getClass().getSimpleName(), "Cannot find the recipient in the connected users");
69
+		} else {
70
+			user.send(msg, null, e -> Log.e(getClass().getSimpleName(), "Error while sending message", e));
71
+		}
72
+	}
73
+
74
+	public void stop() {
75
+		proxyListener.stopAccepting();
76
+		for (TcpConnection connection : users.values()) {
77
+			connection.close();
78
+		}
79
+	}
80
+}

+ 1
- 0
settings.gradle View File

@@ -1,3 +1,4 @@
1 1
 rootProject.name = 'clavardator'
2 2
 include 'client'
3 3
 include 'lib'
4
+include 'server'

Loading…
Cancel
Save