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
 # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
17
 # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
18
 # gradle/wrapper/gradle-wrapper.properties
18
 # gradle/wrapper/gradle-wrapper.properties
19
 /out/
19
 /out/
20
+/clavardator_stored_files/

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

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

+ 1
- 1
client/config.json View File

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

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

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
 package fr.insa.clavardator.client.network;
1
 package fr.insa.clavardator.client.network;
2
 
2
 
3
-import fr.insa.clavardator.client.errors.UsernameTakenException;
4
 import fr.insa.clavardator.client.users.CurrentUser;
3
 import fr.insa.clavardator.client.users.CurrentUser;
4
+import fr.insa.clavardator.lib.errors.UsernameTakenException;
5
 import fr.insa.clavardator.lib.network.TcpConnection;
5
 import fr.insa.clavardator.lib.network.TcpConnection;
6
 import fr.insa.clavardator.lib.users.UserInformation;
6
 import fr.insa.clavardator.lib.users.UserInformation;
7
 import fr.insa.clavardator.lib.util.ErrorCallback;
7
 import fr.insa.clavardator.lib.util.ErrorCallback;
71
 
71
 
72
 	private void sendUsernameTaken(TcpConnection thisConnection) {
72
 	private void sendUsernameTaken(TcpConnection thisConnection) {
73
 		Log.v(this.getClass().getSimpleName(), "Received username request using current username");
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
 package fr.insa.clavardator.client.server;
1
 package fr.insa.clavardator.client.server;
2
 
2
 
3
-import fr.insa.clavardator.lib.network.TcpConnection;
4
 import fr.insa.clavardator.client.users.CurrentUser;
3
 import fr.insa.clavardator.client.users.CurrentUser;
5
 import fr.insa.clavardator.lib.message.Message;
4
 import fr.insa.clavardator.lib.message.Message;
5
+import fr.insa.clavardator.lib.network.TcpConnection;
6
 import fr.insa.clavardator.lib.users.UserInformation;
6
 import fr.insa.clavardator.lib.users.UserInformation;
7
 import fr.insa.clavardator.lib.util.ErrorCallback;
7
 import fr.insa.clavardator.lib.util.ErrorCallback;
8
 import fr.insa.clavardator.lib.util.Log;
8
 import fr.insa.clavardator.lib.util.Log;
83
 						final ArrayList<?> list = (ArrayList<?>) msg;
83
 						final ArrayList<?> list = (ArrayList<?>) msg;
84
 						for (Object obj : list) {
84
 						for (Object obj : list) {
85
 							if (obj instanceof UserInformation) {
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
 				}, errorCallback);
100
 				}, errorCallback);
96
 	}
101
 	}
133
 	 */
138
 	 */
134
 	private void connectToProxy(SimpleCallback callback, ErrorCallback errorCallback) {
139
 	private void connectToProxy(SimpleCallback callback, ErrorCallback errorCallback) {
135
 		try {
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
 						if (callback != null) {
143
 						if (callback != null) {
140
 							callback.call();
144
 							callback.call();
141
 						}
145
 						}
142
-					},
146
+					}, errorCallback),
143
 					errorCallback);
147
 					errorCallback);
144
 		} catch (UnknownHostException e) {
148
 		} catch (UnknownHostException e) {
145
 			Log.e(getClass().getSimpleName(), "Could not connect to presence proxy", e);
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
 package fr.insa.clavardator.client.users;
1
 package fr.insa.clavardator.client.users;
2
 
2
 
3
 import fr.insa.clavardator.client.chat.ChatHistory;
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
 import fr.insa.clavardator.lib.message.FileMessage;
6
 import fr.insa.clavardator.lib.message.FileMessage;
5
 import fr.insa.clavardator.lib.message.Message;
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
 import fr.insa.clavardator.lib.network.TcpConnection;
8
 import fr.insa.clavardator.lib.network.TcpConnection;
9
 import fr.insa.clavardator.lib.users.User;
9
 import fr.insa.clavardator.lib.users.User;
10
 import fr.insa.clavardator.lib.users.UserInformation;
10
 import fr.insa.clavardator.lib.users.UserInformation;
102
 
102
 
103
 	private void sendUsernameTaken(TcpConnection thisConnection) {
103
 	private void sendUsernameTaken(TcpConnection thisConnection) {
104
 		Log.v(this.getClass().getSimpleName(), "Received username request using current username");
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
 	public void init(TcpConnection connection, String id, String username, ErrorCallback errorCallback) {
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
 				if (savedUser.isActive()) {
54
 				if (savedUser.isActive()) {
55
 					Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
55
 					Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
56
 				} else {
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
 					savedUser.init(proxyConnection, userInfo.id, userInfo.getUsername(), null);
58
 					savedUser.init(proxyConnection, userInfo.id, userInfo.getUsername(), null);
59
 				}
59
 				}
60
 			} else {
60
 			} else {

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

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

+ 18
- 0
server/build.gradle View File

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

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

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

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
 rootProject.name = 'clavardator'
1
 rootProject.name = 'clavardator'
2
 include 'client'
2
 include 'client'
3
 include 'lib'
3
 include 'lib'
4
+include 'server'

Loading…
Cancel
Save