[WIP] Integrate server to the project
Many bugs are yet to fix
This commit is contained in:
parent
7bbaa4f8da
commit
32364461be
15 changed files with 257 additions and 30 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,3 +17,4 @@ gradle-app.setting
|
|||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
/out/
|
||||
/clavardator_stored_files/
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/client" />
|
||||
<option value="$PROJECT_DIR$/lib" />
|
||||
<option value="$PROJECT_DIR$/server" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"serveur": {
|
||||
"actif": 1,
|
||||
"uri": "test",
|
||||
"uri": "localhost",
|
||||
"type": "INSA",
|
||||
"ports": {
|
||||
"presence": 35650,
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package fr.insa.clavardator.client.errors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class UsernameTakenException extends Exception implements Serializable {
|
||||
public UsernameTakenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package fr.insa.clavardator.client.network;
|
||||
|
||||
import fr.insa.clavardator.client.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.client.users.CurrentUser;
|
||||
import fr.insa.clavardator.lib.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.lib.network.TcpConnection;
|
||||
import fr.insa.clavardator.lib.users.UserInformation;
|
||||
import fr.insa.clavardator.lib.util.ErrorCallback;
|
||||
|
@ -71,7 +71,7 @@ public class PeerHandshake {
|
|||
|
||||
private void sendUsernameTaken(TcpConnection thisConnection) {
|
||||
Log.v(this.getClass().getSimpleName(), "Received username request using current username");
|
||||
thisConnection.send(new UsernameTakenException("Username taken"), this::closeConnection, null);
|
||||
thisConnection.send(new UsernameTakenException("Username taken", userInformation.id), this::closeConnection, null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package fr.insa.clavardator.client.server;
|
||||
|
||||
import fr.insa.clavardator.lib.network.TcpConnection;
|
||||
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;
|
||||
|
@ -83,8 +83,7 @@ public class InsaPresence implements Presence {
|
|||
final ArrayList<?> list = (ArrayList<?>) msg;
|
||||
for (Object obj : list) {
|
||||
if (obj instanceof UserInformation) {
|
||||
userList.add((UserInformation)obj);
|
||||
}
|
||||
userList.add((UserInformation) obj);
|
||||
}
|
||||
}
|
||||
Log.v(getClass().getSimpleName(), "Receive subscribe response: " + msg);
|
||||
|
@ -92,6 +91,12 @@ public class InsaPresence implements Presence {
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -133,13 +138,12 @@ public class InsaPresence implements Presence {
|
|||
*/
|
||||
private void connectToProxy(SimpleCallback callback, ErrorCallback errorCallback) {
|
||||
try {
|
||||
proxyConnection = new TcpConnection(InetAddress.getByName(path),
|
||||
proxyPort,
|
||||
(newConnection) -> {
|
||||
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);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package fr.insa.clavardator.client.users;
|
||||
|
||||
import fr.insa.clavardator.client.chat.ChatHistory;
|
||||
import fr.insa.clavardator.client.db.DatabaseController;
|
||||
import fr.insa.clavardator.lib.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.lib.message.FileMessage;
|
||||
import fr.insa.clavardator.lib.message.Message;
|
||||
import fr.insa.clavardator.client.db.DatabaseController;
|
||||
import fr.insa.clavardator.client.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.lib.network.TcpConnection;
|
||||
import fr.insa.clavardator.lib.users.User;
|
||||
import fr.insa.clavardator.lib.users.UserInformation;
|
||||
|
@ -102,7 +102,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
|
||||
private void sendUsernameTaken(TcpConnection thisConnection) {
|
||||
Log.v(this.getClass().getSimpleName(), "Received username request using current username");
|
||||
thisConnection.send(new UsernameTakenException("Username taken"), this::disconnect, null);
|
||||
thisConnection.send(new UsernameTakenException("Username taken", getId()), this::disconnect, null);
|
||||
}
|
||||
|
||||
public void init(TcpConnection connection, String id, String username, ErrorCallback errorCallback) {
|
||||
|
|
|
@ -54,7 +54,7 @@ public class UserList {
|
|||
if (savedUser.isActive()) {
|
||||
Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
|
||||
} else {
|
||||
Log.v(getClass().getSimpleName(), "Received user from presence server already known and connected");
|
||||
Log.v(getClass().getSimpleName(), "Received user from presence server already known but not connected, connecting...");
|
||||
savedUser.init(proxyConnection, userInfo.id, userInfo.getUsername(), null);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package fr.insa.clavardator.lib.errors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class UsernameTakenException extends Exception implements Serializable {
|
||||
public final String recipient;
|
||||
|
||||
public UsernameTakenException(String message, String recipient) {
|
||||
super(message);
|
||||
this.recipient = recipient;
|
||||
}
|
||||
}
|
|
@ -10,10 +10,16 @@ import static fr.insa.clavardator.lib.network.TcpConnection.TCP_PORT;
|
|||
|
||||
public class TcpListener {
|
||||
Acceptor acceptor = null;
|
||||
int port = TCP_PORT;
|
||||
|
||||
public TcpListener() {
|
||||
}
|
||||
|
||||
public TcpListener(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start accepting incoming connections
|
||||
*
|
||||
|
@ -24,7 +30,7 @@ public class TcpListener {
|
|||
if (acceptor != null) {
|
||||
acceptor.stopAccepting();
|
||||
}
|
||||
acceptor = new Acceptor(callback, errorCallback);
|
||||
acceptor = new Acceptor(port, callback, errorCallback);
|
||||
acceptor.start();
|
||||
}
|
||||
|
||||
|
@ -43,8 +49,10 @@ public class TcpListener {
|
|||
private final NewConnectionCallback callback;
|
||||
private final ErrorCallback errorCallback;
|
||||
private ServerSocket server;
|
||||
private int port;
|
||||
|
||||
public Acceptor(NewConnectionCallback callback, ErrorCallback errorCallback) {
|
||||
public Acceptor(int port, NewConnectionCallback callback, ErrorCallback errorCallback) {
|
||||
this.port = port;
|
||||
this.callback = callback;
|
||||
this.errorCallback = errorCallback;
|
||||
}
|
||||
|
@ -52,7 +60,7 @@ public class TcpListener {
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
server = new ServerSocket(TCP_PORT);
|
||||
server = new ServerSocket(port);
|
||||
while (!shouldStop) {
|
||||
Socket clientSocket = server.accept();
|
||||
callback.onNewConnection(clientSocket);
|
||||
|
|
18
server/build.gradle
Normal file
18
server/build.gradle
Normal file
|
@ -0,0 +1,18 @@
|
|||
plugins {
|
||||
id 'application'
|
||||
id 'com.github.johnrengelman.shadow' version '6.1.0'
|
||||
}
|
||||
|
||||
group 'fr.insa.clavardator.server'
|
||||
version '0.0.1'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib')
|
||||
implementation 'org.jetbrains:annotations:20.1.0'
|
||||
}
|
||||
|
||||
mainClassName = 'fr.insa.clavardator.server.Main'
|
24
server/src/main/java/fr/insa/clavardator/server/Main.java
Normal file
24
server/src/main/java/fr/insa/clavardator/server/Main.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package fr.insa.clavardator.server;
|
||||
|
||||
import fr.insa.clavardator.lib.util.Log;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Log.v(Main.class.getSimpleName(), "Server started! You can stop it by typing stop");
|
||||
|
||||
Proxy proxy = new Proxy();
|
||||
Presence presence = new Presence();
|
||||
|
||||
String line;
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
do {
|
||||
line = scanner.nextLine();
|
||||
} while (!line.equals("stop"));
|
||||
|
||||
proxy.stop();
|
||||
presence.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fr.insa.clavardator.server;
|
||||
|
||||
import fr.insa.clavardator.lib.network.TcpConnection;
|
||||
import fr.insa.clavardator.lib.network.TcpListener;
|
||||
import fr.insa.clavardator.lib.users.UserInformation;
|
||||
import fr.insa.clavardator.lib.util.Log;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.Serializable;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Presence {
|
||||
private static final int PRESENCE_PORT = 35650;
|
||||
|
||||
private final Map<String, TcpConnection> subscribers = new HashMap<>();
|
||||
private final ArrayList<UserInformation> connectedUsers = new ArrayList<>();
|
||||
private final TcpListener presenceListener;
|
||||
|
||||
public Presence() {
|
||||
presenceListener = new TcpListener(PRESENCE_PORT);
|
||||
presenceListener.acceptConnection(this::subscribe,
|
||||
e -> Log.e(getClass().getSimpleName(), "Error while registering a user", e));
|
||||
}
|
||||
|
||||
public void publish(UserInformation info) {
|
||||
for (TcpConnection subscriber : subscribers.values()) {
|
||||
ArrayList<UserInformation> msg = new ArrayList<>(1);
|
||||
msg.add(info);
|
||||
subscriber.send(msg, null,
|
||||
e -> Log.e(getClass().getSimpleName(), "Error while publishing user information", e));
|
||||
}
|
||||
}
|
||||
|
||||
public void subscribe(Socket socket) {
|
||||
TcpConnection user = new TcpConnection(socket);
|
||||
|
||||
// Receive user information
|
||||
user.receiveOne(o -> {
|
||||
if (o instanceof UserInformation) {
|
||||
UserInformation userInformation = ((UserInformation) o);
|
||||
Log.v(getClass().getSimpleName(), "Registering user " + userInformation.id +
|
||||
" (" + userInformation.getUsername() + ")");
|
||||
|
||||
// publish new user info to all subscribers
|
||||
publish(userInformation);
|
||||
|
||||
// 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
|
||||
user.send((Serializable) connectedUsers.clone(), null,
|
||||
e -> Log.e(getClass().getSimpleName(), "Error while receiving user information", e));
|
||||
|
||||
subscribers.put(userInformation.id, user);
|
||||
connectedUsers.add(userInformation);
|
||||
|
||||
user.receive(msg -> Log.w(getClass().getSimpleName(), "Received an unexpected message " + msg),
|
||||
e -> {
|
||||
if (e instanceof EOFException) {
|
||||
unsubscribe(userInformation.id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.e(getClass().getSimpleName(), "Received unexpected message type: " + o.getClass().getSimpleName());
|
||||
}
|
||||
}, e -> {
|
||||
if (!(e instanceof EOFException)) {
|
||||
Log.e(getClass().getSimpleName(), "Error while receiving user information", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void unsubscribe(String id) {
|
||||
Log.v(getClass().getSimpleName(), "Unsubscribing user " + id);
|
||||
subscribers.get(id).close();
|
||||
subscribers.remove(id);
|
||||
connectedUsers.removeIf(userInformation -> userInformation.id.equals(id));
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
presenceListener.stopAccepting();
|
||||
for (TcpConnection connection : subscribers.values()) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
80
server/src/main/java/fr/insa/clavardator/server/Proxy.java
Normal file
80
server/src/main/java/fr/insa/clavardator/server/Proxy.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package fr.insa.clavardator.server;
|
||||
|
||||
import fr.insa.clavardator.lib.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.lib.message.Message;
|
||||
import fr.insa.clavardator.lib.network.TcpConnection;
|
||||
import fr.insa.clavardator.lib.network.TcpListener;
|
||||
import fr.insa.clavardator.lib.users.UserInformation;
|
||||
import fr.insa.clavardator.lib.util.Log;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Proxy {
|
||||
private static final int PROXY_PORT = 35750;
|
||||
private final HashMap<String, TcpConnection> users = new HashMap<>();
|
||||
private final TcpListener proxyListener;
|
||||
|
||||
public Proxy() {
|
||||
proxyListener = new TcpListener(PROXY_PORT);
|
||||
proxyListener.acceptConnection(clientSocket -> {
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Accepting a new user");
|
||||
TcpConnection connection = new TcpConnection(clientSocket);
|
||||
connection.receive(msg -> {
|
||||
|
||||
if (msg instanceof Message) {
|
||||
Log.v(getClass().getSimpleName(), "Transmitting message: " + msg);
|
||||
transmitMessage((Serializable) msg, ((Message) msg).getRecipient().id);
|
||||
|
||||
} else if (msg instanceof UsernameTakenException) {
|
||||
UsernameTakenException unameTaken = ((UsernameTakenException) msg);
|
||||
transmitMessage(unameTaken, unameTaken.recipient);
|
||||
|
||||
} else if (msg instanceof UserInformation) {
|
||||
Log.v(getClass().getSimpleName(), "Registering new user: " + msg);
|
||||
users.put(((UserInformation) msg).id, connection);
|
||||
for (String userId : users.keySet()) {
|
||||
UserInformation userInfo = ((UserInformation) msg);
|
||||
if (!userId.equals(userInfo.id)) {
|
||||
transmitMessage((Serializable) msg, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, e -> {
|
||||
if (e instanceof EOFException) {
|
||||
for (Map.Entry<String, TcpConnection> user : users.entrySet()) {
|
||||
if (user.getValue().equals(connection)) {
|
||||
Log.v(getClass().getSimpleName(), "Disconnecting user " + user.getKey());
|
||||
users.remove(user.getKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(getClass().getSimpleName(), "Error while receiving message to transmit", e);
|
||||
}
|
||||
});
|
||||
},
|
||||
e -> Log.e(getClass().getSimpleName(), "Error while accepting a user", e));
|
||||
}
|
||||
|
||||
|
||||
void transmitMessage(Serializable msg, String recipientId) {
|
||||
TcpConnection user = users.get(recipientId);
|
||||
if (user == null) {
|
||||
Log.e(getClass().getSimpleName(), "Cannot find the recipient in the connected users");
|
||||
} else {
|
||||
user.send(msg, null, e -> Log.e(getClass().getSimpleName(), "Error while sending message", e));
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
proxyListener.stopAccepting();
|
||||
for (TcpConnection connection : users.values()) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
rootProject.name = 'clavardator'
|
||||
include 'client'
|
||||
include 'lib'
|
||||
include 'server'
|
||||
|
|
Loading…
Reference in a new issue