use unique ID instead of ip
This commit is contained in:
parent
1ab27f4f87
commit
fcb678f4fe
12 changed files with 208 additions and 186 deletions
|
@ -48,7 +48,7 @@ public class Message implements Serializable {
|
|||
}
|
||||
|
||||
public UserInformation getCorrespondent() {
|
||||
if (CurrentUser.getInstance().isLocalId(sender.id)) {
|
||||
if (CurrentUser.getInstance().getId() != null && CurrentUser.getInstance().getId().equals(sender.id)) {
|
||||
return recipient;
|
||||
} else {
|
||||
return sender;
|
||||
|
|
|
@ -81,8 +81,8 @@ public class DatabaseController {
|
|||
@Language("SQL") String sql = "CREATE TABLE IF NOT EXISTS message " +
|
||||
"(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
|
||||
" timestamp DATETIME NOT NULL, " +
|
||||
" sender INTEGER UNSIGNED NOT NULL, " +
|
||||
" recipient INTEGER UNSIGNED NOT NULL, " +
|
||||
" sender TEXT NOT NULL, " +
|
||||
" recipient TEXT NOT NULL, " +
|
||||
" text TEXT, " +
|
||||
" file_path TEXT)";
|
||||
|
||||
|
@ -99,14 +99,30 @@ public class DatabaseController {
|
|||
*/
|
||||
private void createUserTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "CREATE TABLE IF NOT EXISTS user " +
|
||||
"(id INTEGER UNSIGNED PRIMARY KEY NOT NULL," +
|
||||
" username TINYTEXT NULLABLE )";
|
||||
"(id TEXT PRIMARY KEY NOT NULL," +
|
||||
" username TINYTEXT NULLABLE )";
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Creating table user...");
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the table used to store users
|
||||
*
|
||||
* @param callback The function to call on success
|
||||
* @param errorCallback The function to call on error
|
||||
*/
|
||||
private void createCurrentUserTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "CREATE TABLE IF NOT EXISTS current_user " +
|
||||
"(id TEXT PRIMARY KEY NOT NULL," +
|
||||
" username TINYTEXT NULLABLE )";
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Creating table current user...");
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates all needed tables if non-existent
|
||||
*
|
||||
|
@ -114,7 +130,7 @@ public class DatabaseController {
|
|||
* @param errorCallback The function to call on error
|
||||
*/
|
||||
public void initTables(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
createMessageTable(() -> createUserTable(callback, errorCallback), errorCallback);
|
||||
createMessageTable(() -> createCurrentUserTable(() -> createUserTable(callback, errorCallback), errorCallback), errorCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,6 +159,13 @@ public class DatabaseController {
|
|||
executor.start();
|
||||
}
|
||||
|
||||
private void dropCurrentUserTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "DROP TABLE IF EXISTS current_user";
|
||||
Log.v(getClass().getSimpleName(), "Dropping table current_user...");
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all tables
|
||||
*
|
||||
|
@ -150,7 +173,7 @@ public class DatabaseController {
|
|||
* @param errorCallback The function to call on error
|
||||
*/
|
||||
private void dropTables(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
dropMessageTable(() -> dropUserTable(callback, errorCallback), errorCallback);
|
||||
dropMessageTable(() -> dropUserTable(() -> dropCurrentUserTable(callback, errorCallback), errorCallback), errorCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,14 +194,14 @@ public class DatabaseController {
|
|||
* @param errorCallback The function to call on error
|
||||
*/
|
||||
public void getAllUsers(UsersCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "SELECT * FROM user WHERE id != " + CurrentUser.getInstance().getId();
|
||||
@Language("SQL") String sql = "SELECT * FROM user";
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Fetching users from db... ");
|
||||
|
||||
QueryExecutor executor = new QueryExecutor(sql, res -> {
|
||||
ArrayList<User> userList = new ArrayList<>();
|
||||
while (res.next()) {
|
||||
int id = res.getInt("id");
|
||||
String id = res.getString("id");
|
||||
String username = res.getString("username");
|
||||
userList.add(new User(id, username));
|
||||
}
|
||||
|
@ -189,6 +212,26 @@ public class DatabaseController {
|
|||
executor.start();
|
||||
}
|
||||
|
||||
public void getCurrentUser(CurrentUserCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "SELECT * FROM current_user ";
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Fetching current_user from db... ");
|
||||
|
||||
QueryExecutor executor = new QueryExecutor(sql, res -> {
|
||||
UserInformation user = null;
|
||||
int nbRows = 0;
|
||||
if (res.next()) {
|
||||
String id = res.getString("id");
|
||||
String username = res.getString("username");
|
||||
user = new UserInformation(id, username);
|
||||
nbRows = 1;
|
||||
}
|
||||
Log.v(getClass().getSimpleName(), nbRows + " users fetched");
|
||||
callback.onFetched(user);
|
||||
}, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a message to the database for this user.
|
||||
|
@ -200,9 +243,8 @@ public class DatabaseController {
|
|||
*/
|
||||
public void addMessage(Message message, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
// Insert the correspondent if not already in the database
|
||||
Log.v(getClass().getSimpleName(), "Inserting correpondent into db... ");
|
||||
Log.v(getClass().getSimpleName(), "Inserting correspondent into db... ");
|
||||
addUser(message.getCorrespondent(), () -> {
|
||||
|
||||
// Handle messages containing a file
|
||||
String filePath = "NULL";
|
||||
// TODO: Handle messages containing files:
|
||||
|
@ -212,24 +254,16 @@ public class DatabaseController {
|
|||
// filePath = ((FileMessage) message).getFileName();
|
||||
}
|
||||
|
||||
// TODO: do this in the construction of the message instead?
|
||||
int recipientId;
|
||||
int senderId;
|
||||
// if (CurrentUser.getInstance().isLocalId(message.getRecipient().id)) {
|
||||
// recipientId = CurrentUser.getInstance().getId();
|
||||
senderId = message.getSender().id;
|
||||
// } else {
|
||||
// senderId = CurrentUser.getInstance().getId();
|
||||
recipientId = message.getRecipient().id;
|
||||
// }
|
||||
String recipientId = message.getRecipient().id;
|
||||
String senderId = message.getSender().id;
|
||||
|
||||
// Insert the new message
|
||||
@Language("SQL") String sql = "INSERT INTO message " +
|
||||
"(timestamp, sender, recipient, text, file_path) " +
|
||||
"VALUES (" +
|
||||
message.getDate().getTime() + ", " +
|
||||
senderId + ", " +
|
||||
recipientId + ", " +
|
||||
"'" + senderId + "', " +
|
||||
"'" + recipientId + "', " +
|
||||
"\"" + message.getText() + "\", " +
|
||||
filePath +
|
||||
")";
|
||||
|
@ -251,10 +285,10 @@ public class DatabaseController {
|
|||
@Language("SQL") String sql;
|
||||
if (user.getUsername() != null) {
|
||||
sql = "INSERT OR IGNORE INTO user (id, username) " +
|
||||
"VALUES (" + user.id + ", \"" + user.getUsername() + "\")";
|
||||
"VALUES ('" + user.id + "', '" + user.getUsername() + "')";
|
||||
} else {
|
||||
sql = "INSERT OR IGNORE INTO user (id) " +
|
||||
"VALUES (" + user.id + ")";
|
||||
"VALUES ('" + user.id + "')";
|
||||
}
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername());
|
||||
|
@ -262,6 +296,21 @@ public class DatabaseController {
|
|||
executor.start();
|
||||
}
|
||||
|
||||
public void addCurrentUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql;
|
||||
if (user.getUsername() != null) {
|
||||
sql = "INSERT OR IGNORE INTO current_user (id, username) " +
|
||||
"VALUES ('" + user.id + "', '" + user.getUsername() + "')";
|
||||
} else {
|
||||
sql = "INSERT OR IGNORE INTO current_user (id) " +
|
||||
"VALUES ('" + user.id + "')";
|
||||
}
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Adding current_user to db: " + user.id + " / " + user.getUsername());
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chat history for a given time frame
|
||||
*
|
||||
|
@ -272,22 +321,24 @@ public class DatabaseController {
|
|||
* @param errorCallback The function to call on error
|
||||
*/
|
||||
public void getChatHistory(UserInformation user, Date from, Date to, HistoryCallback callback, ErrorCallback errorCallback) {
|
||||
// TODO update to search in current_user table as well
|
||||
@Language("SQL") String sql =
|
||||
"SELECT timestamp, s.id AS sender_id, s.username AS sender_username, " +
|
||||
"r.id AS recipient_id, r.username AS recipient_username, text, file_path " +
|
||||
"FROM message JOIN user AS s ON sender = s.id " +
|
||||
" JOIN user AS r ON recipient = r.id " +
|
||||
"WHERE (s.id = " + user.id + " OR r.id = " + user.id + ") AND " +
|
||||
"WHERE (s.id = '" + user.id + "' OR r.id = '" + user.id + "') AND " +
|
||||
"timestamp > " + from.getTime() + " AND timestamp < " + to.getTime() + " " +
|
||||
"ORDER BY timestamp";
|
||||
|
||||
System.out.println(sql);
|
||||
Log.v(getClass().getSimpleName(), "Fetching chat history from db... ");
|
||||
QueryExecutor executor = new QueryExecutor(sql, res -> {
|
||||
ArrayList<Message> chatHistory = new ArrayList<>();
|
||||
while (res.next()) {
|
||||
int sId = res.getInt("sender_id");
|
||||
String sId = res.getString("sender_id");
|
||||
String sUsername = res.getString("sender_username");
|
||||
int rId = res.getInt("recipient_id");
|
||||
String rId = res.getString("recipient_id");
|
||||
String rUsername = res.getString("recipient_username");
|
||||
Date date = new Date(res.getTimestamp("timestamp").getTime());
|
||||
String text = res.getString("text");
|
||||
|
@ -307,25 +358,14 @@ public class DatabaseController {
|
|||
}
|
||||
|
||||
public void updateUsername(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "UPDATE user SET username = '" + user.getUsername() + "' where id = " + user.id;
|
||||
@Language("SQL") String sql = "UPDATE user SET username = '" + user.getUsername() + "' where id = '" + user.id + "'";
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
public void getUsername(int id, UsernameCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "SELECT username from user where id =" + id;
|
||||
|
||||
Log.v(getClass().getSimpleName(), "Fetching username from db... ");
|
||||
QueryExecutor executor = new QueryExecutor(sql, res -> {
|
||||
String username = null;
|
||||
int nbRows = 0;
|
||||
if (res.next()) {
|
||||
username = res.getString("username");
|
||||
nbRows = 1;
|
||||
}
|
||||
Log.v(getClass().getSimpleName(), nbRows + " username fetched");
|
||||
callback.onUsernameFetched(username);
|
||||
}, errorCallback);
|
||||
public void updateCurrentUsername(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
|
||||
@Language("SQL") String sql = "UPDATE current_user SET username = '" + user.getUsername() + "' where id = '" + user.id + "'";
|
||||
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
|
@ -404,6 +444,10 @@ public class DatabaseController {
|
|||
void onUsersFetched(ArrayList<User> users);
|
||||
}
|
||||
|
||||
public interface CurrentUserCallback {
|
||||
void onFetched(UserInformation user);
|
||||
}
|
||||
|
||||
public interface UsernameCallback {
|
||||
void onUsernameFetched(String username);
|
||||
}
|
||||
|
|
|
@ -59,13 +59,4 @@ public class NetUtil {
|
|||
final List<InetAddress> list = listAllLocalAddresses();
|
||||
return list.stream().anyMatch((a) -> Arrays.equals(address.getAddress(), a.getAddress()));
|
||||
}
|
||||
|
||||
public static int getIdFromIp(InetAddress ipAddr) {
|
||||
byte[] addr = ipAddr.getAddress();
|
||||
int id = 0;
|
||||
for (byte b : addr) {
|
||||
id = (id << 8) + b;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,11 +46,9 @@ public class MainController implements Initializable {
|
|||
|
||||
private JFXSnackbar snackbar;
|
||||
private UserList userList;
|
||||
private boolean historyLoaded;
|
||||
private boolean online;
|
||||
|
||||
public MainController() {
|
||||
historyLoaded = false;
|
||||
online = false;
|
||||
currentUser = CurrentUser.getInstance();
|
||||
currentUser.addObserver(propertyChangeEvent -> {
|
||||
|
@ -65,13 +63,10 @@ public class MainController implements Initializable {
|
|||
* If the current user becomes valid, start the chat.
|
||||
* If it is invalid or not set, show the login screen.
|
||||
* <p>
|
||||
* If the history is not yet loaded or the user is not initialized, do nothing.
|
||||
*
|
||||
* @param newState The new user state
|
||||
*/
|
||||
private void onCurrentUserStateChange(CurrentUser.State newState) {
|
||||
// Only do an action if the history is loaded
|
||||
if (historyLoaded) {
|
||||
if (newState == CurrentUser.State.VALID)
|
||||
startChat();
|
||||
else if (newState != CurrentUser.State.UNINITIALIZED) {
|
||||
|
@ -81,18 +76,6 @@ public class MainController implements Initializable {
|
|||
}
|
||||
Platform.runLater(() -> showLogin(isError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the history loaded after the current user, fire the state change event again
|
||||
*/
|
||||
public void onHistoryLoaded() {
|
||||
historyLoaded = true;
|
||||
final CurrentUser.State userState = CurrentUser.getInstance().getState();
|
||||
if (userState != CurrentUser.State.UNINITIALIZED) {
|
||||
onCurrentUserStateChange(userState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,10 +255,10 @@ public class MainController implements Initializable {
|
|||
private void initDb() {
|
||||
final DatabaseController db = new DatabaseController();
|
||||
db.initTables(() -> {
|
||||
Log.v("INIT", "Current user: " + currentUser.getId());
|
||||
currentUser.init(() -> {
|
||||
userList.retrievedPreviousUsers(this::onHistoryLoaded, this::onInitError);
|
||||
}, this::onInitError);
|
||||
userList.retrievedPreviousUsers(
|
||||
() -> currentUser.init(this::onInitError),
|
||||
this::onInitError
|
||||
);
|
||||
}, this::onInitError);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fr.insa.clavardator.ui.chat;
|
||||
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ListCell;
|
||||
|
@ -29,8 +30,10 @@ public class MessageListItemCell extends ListCell<Message> {
|
|||
if (item == null || empty) {
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setGraphic(view);
|
||||
messageListItemController.setMessage(item);
|
||||
Platform.runLater(() -> {
|
||||
setGraphic(view);
|
||||
messageListItemController.setMessage(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ public class MessageListItemController implements Initializable {
|
|||
button.setText(message.getText());
|
||||
timestamp.setText(DateFormat.getTimeInstance().format(message.getDate()));
|
||||
clearBackground();
|
||||
if (CurrentUser.getInstance().isLocalId(message.getSender().id)) {
|
||||
if (CurrentUser.getInstance().getId().equals(message.getSender().id)) {
|
||||
container.setAlignment(Pos.CENTER_RIGHT);
|
||||
button.getStyleClass().add("message-self");
|
||||
} else {
|
||||
|
|
|
@ -1,29 +1,19 @@
|
|||
package fr.insa.clavardator.users;
|
||||
|
||||
import fr.insa.clavardator.db.DatabaseController;
|
||||
import fr.insa.clavardator.network.NetUtil;
|
||||
import fr.insa.clavardator.util.ErrorCallback;
|
||||
import fr.insa.clavardator.util.Log;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static fr.insa.clavardator.network.NetUtil.getIdFromIp;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CurrentUser extends User {
|
||||
private static CurrentUser instance = null;
|
||||
|
||||
private State state;
|
||||
|
||||
private ArrayList<Integer> validIds;
|
||||
|
||||
private CurrentUser() {
|
||||
super();
|
||||
state = State.UNINITIALIZED;
|
||||
validIds = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,48 +25,49 @@ public class CurrentUser extends User {
|
|||
return instance;
|
||||
}
|
||||
|
||||
public void init(@Nullable InitCallback callback, ErrorCallback errorCallback) {
|
||||
try {
|
||||
final List<InetAddress> addresses = NetUtil.listAllLocalAddresses();
|
||||
// Save all addresses for this user
|
||||
validIds = new ArrayList<>();
|
||||
addresses.forEach(address -> validIds.add(getIdFromIp(address)));
|
||||
if (validIds.size() > 0) {
|
||||
// Set the first id as the main one
|
||||
id = validIds.get(0);
|
||||
private static String generateUniqueId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public void init(ErrorCallback errorCallback) {
|
||||
final DatabaseController db = new DatabaseController();
|
||||
db.getCurrentUser((user) -> {
|
||||
if (user == null) {
|
||||
id = generateUniqueId();
|
||||
Log.v(getClass().getSimpleName(), "No previous user found, generating id: " + id);
|
||||
db.addCurrentUser(
|
||||
new UserInformation(this),
|
||||
() -> setState(State.NONE),
|
||||
errorCallback);
|
||||
} else {
|
||||
errorCallback.onError(new SocketException("No valid IP found"));
|
||||
return;
|
||||
id = user.id;
|
||||
if (user.getUsername() != null) {
|
||||
Log.v(getClass().getSimpleName(), "Last user found : " + id + " / " + getUsername());
|
||||
setUsername(user.getUsername());
|
||||
} else {
|
||||
Log.v(getClass().getSimpleName(), "No username found, asking user");
|
||||
setState(State.NONE);
|
||||
}
|
||||
}
|
||||
final DatabaseController db = new DatabaseController();
|
||||
// Make sure the user is in the db then set its username
|
||||
db.addUser(new UserInformation(this), () -> {
|
||||
db.getUsername(id, username -> {
|
||||
if (username != null) {
|
||||
Log.v(getClass().getSimpleName(), "Last username found : " + username);
|
||||
setUsername(username);
|
||||
} else {
|
||||
Log.v(getClass().getSimpleName(), "No last username found, asking user...");
|
||||
setState(State.NONE);
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onFinish();
|
||||
}
|
||||
}, errorCallback);
|
||||
}, errorCallback);
|
||||
} catch (SocketException e) {
|
||||
errorCallback.onError(e);
|
||||
}
|
||||
}, errorCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String newUsername) {
|
||||
Log.v(this.getClass().getSimpleName(),
|
||||
"Username changed from " + getUsername() + " to " + newUsername);
|
||||
super.setUsername(newUsername);
|
||||
final DatabaseController db = new DatabaseController();
|
||||
db.updateCurrentUsername(new UserInformation(this),
|
||||
null,
|
||||
e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
|
||||
Log.v(this.getClass().getSimpleName(),
|
||||
"Username changed to " + getUsername());
|
||||
setState(State.VALID);
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
Log.v(this.getClass().getSimpleName(),
|
||||
"State changed from " + this.state.toString() + " to " + state.toString());
|
||||
|
@ -84,14 +75,6 @@ public class CurrentUser extends User {
|
|||
this.state = state;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public boolean isLocalId(int id) {
|
||||
return validIds.contains(id);
|
||||
}
|
||||
|
||||
public enum State {
|
||||
UNINITIALIZED,
|
||||
VALID,
|
||||
|
|
|
@ -2,6 +2,7 @@ package fr.insa.clavardator.users;
|
|||
|
||||
import fr.insa.clavardator.chat.ChatHistory;
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import fr.insa.clavardator.db.DatabaseController;
|
||||
import fr.insa.clavardator.errors.UsernameTakenException;
|
||||
import fr.insa.clavardator.network.PeerConnection;
|
||||
import fr.insa.clavardator.util.ErrorCallback;
|
||||
|
@ -19,16 +20,21 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
private State state = State.DISCONNECTED;
|
||||
private transient PeerConnection connection;
|
||||
|
||||
public PeerUser(int id, String username) {
|
||||
public PeerUser(String id, String username) {
|
||||
super(id, username);
|
||||
history = new ChatHistory(this);
|
||||
}
|
||||
|
||||
public PeerUser(int id) {
|
||||
public PeerUser(String id) {
|
||||
super(id);
|
||||
history = new ChatHistory(this);
|
||||
}
|
||||
|
||||
public PeerUser() {
|
||||
super();
|
||||
history = new ChatHistory(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously connects to the user and receives its information (id, username)
|
||||
*
|
||||
|
@ -127,6 +133,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
UserInformation userInfo = (UserInformation) msg;
|
||||
final String receivedUsername = userInfo.getUsername();
|
||||
if (!receivedUsername.equals(CurrentUser.getInstance().getUsername())) {
|
||||
setId(userInfo.id);
|
||||
setUsername(receivedUsername);
|
||||
callback.onUserConnected();
|
||||
subscribeToMessages(e -> {
|
||||
|
@ -162,7 +169,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
msg -> {
|
||||
Log.v(this.getClass().getSimpleName(), "Received message from " + id);
|
||||
if (msg instanceof UserInformation) {
|
||||
assert ((UserInformation) msg).id == getId();
|
||||
assert ((UserInformation) msg).id.equals(getId());
|
||||
final String receivedUsername = ((UserInformation) msg).getUsername();
|
||||
Log.v(this.getClass().getSimpleName(), "Message username: " + receivedUsername);
|
||||
if (CurrentUser.getInstance().getUsername().equals(receivedUsername)) {
|
||||
|
@ -171,8 +178,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
setUsername(receivedUsername);
|
||||
}
|
||||
} else if (msg instanceof Message) {
|
||||
assert ((Message) msg).getRecipient().id != id;
|
||||
assert CurrentUser.getInstance().isLocalId(((Message) msg).getRecipient().id);
|
||||
assert !((Message) msg).getRecipient().id.equals(id);
|
||||
|
||||
Log.v(this.getClass().getSimpleName(), "Message text: " + ((Message) msg).getText());
|
||||
history.addMessage((Message) msg, errorCallback);
|
||||
|
@ -200,6 +206,15 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
setState(State.DISCONNECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUsername(String newUsername) {
|
||||
super.setUsername(newUsername);
|
||||
final DatabaseController db = new DatabaseController();
|
||||
db.updateUsername(new UserInformation(this),
|
||||
null,
|
||||
e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection to this user
|
||||
*/
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.io.Serializable;
|
|||
|
||||
public class User implements Serializable {
|
||||
private String username;
|
||||
protected int id;
|
||||
protected String id;
|
||||
|
||||
// Make this class observable
|
||||
protected final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||
|
@ -23,20 +23,24 @@ public class User implements Serializable {
|
|||
public User() {
|
||||
}
|
||||
|
||||
public User(int id) {
|
||||
public User(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public User(int id, String username) {
|
||||
public User(String id, String username) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
|
||||
public int getId() {
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
@ -44,8 +48,6 @@ public class User implements Serializable {
|
|||
protected void setUsername(String newUsername) {
|
||||
pcs.firePropertyChange("username", this.username, newUsername);
|
||||
this.username = newUsername;
|
||||
final DatabaseController db = new DatabaseController();
|
||||
db.updateUsername(new UserInformation(this), null, e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,10 +6,10 @@ import java.io.Serializable;
|
|||
* Class used to serialize useful user information
|
||||
*/
|
||||
public class UserInformation implements Serializable {
|
||||
public final int id;
|
||||
public final String id;
|
||||
private final String username;
|
||||
|
||||
public UserInformation(int id, String username) {
|
||||
public UserInformation(String id, String username) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
}
|
||||
|
|
|
@ -7,16 +7,17 @@ import fr.insa.clavardator.util.ErrorCallback;
|
|||
import fr.insa.clavardator.util.Log;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static fr.insa.clavardator.network.NetUtil.getIdFromIp;
|
||||
|
||||
public class UserList {
|
||||
|
||||
private final Map<Integer, PeerUser> inactiveUsers = new HashMap<>();
|
||||
private final Map<Integer, PeerUser> activeUsers = new HashMap<>();
|
||||
private final Map<String, PeerUser> inactiveUsers = new HashMap<>();
|
||||
private final Map<String, PeerUser> activeUsers = new HashMap<>();
|
||||
private final ArrayList<PeerUser> pendingUsers = new ArrayList<>();
|
||||
|
||||
private UserConnectionCallback newUsersObservers = null;
|
||||
|
||||
|
@ -57,9 +58,8 @@ public class UserList {
|
|||
*/
|
||||
public void discoverActiveUsers(ErrorCallback errorCallback) {
|
||||
netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
|
||||
int id = getIdFromIp(ipAddr);
|
||||
Log.v(this.getClass().getSimpleName(), "Discovered new user: " + id);
|
||||
final PeerUser user = createNewUser(id);
|
||||
Log.v(this.getClass().getSimpleName(), "Discovered new user: " + data);
|
||||
final PeerUser user = createNewPendingUser(data.trim());
|
||||
if (user != null) {
|
||||
user.createConnection(ipAddr, () -> onUserConnectionSuccess(user), errorCallback);
|
||||
}
|
||||
|
@ -72,14 +72,14 @@ public class UserList {
|
|||
*/
|
||||
public void startDiscoveryListening() {
|
||||
netDiscoverer.startDiscoveryListening(
|
||||
"CLAVARDATOR_RESPONSE",
|
||||
CurrentUser.getInstance().getId(),
|
||||
null,
|
||||
Throwable::printStackTrace);
|
||||
}
|
||||
|
||||
public void retrievedPreviousUsers(UserListLoadedCallback onFinish, ErrorCallback errorCallback) {
|
||||
db.getAllUsers(users -> {
|
||||
users.forEach(user -> createNewUser(user.id, user.getUsername()));
|
||||
users.forEach(user -> createNewInactiveUser(user.id, user.getUsername()));
|
||||
onFinish.onLoaded();
|
||||
}, errorCallback);
|
||||
}
|
||||
|
@ -92,9 +92,9 @@ public class UserList {
|
|||
public void startUserListening(ErrorCallback errorCallback) {
|
||||
connectionListener.acceptConnection(
|
||||
(clientSocket) -> {
|
||||
final int id = getIdFromIp(clientSocket.getInetAddress());
|
||||
Log.v(this.getClass().getSimpleName(), "new connection from user: " + id);
|
||||
final PeerUser user = createNewUser(id);
|
||||
Log.v(this.getClass().getSimpleName(),
|
||||
"new connection from user at address: " + clientSocket.getInetAddress().toString());
|
||||
final PeerUser user = createNewPendingUser();
|
||||
if (user != null) {
|
||||
user.acceptConnection(clientSocket, () ->
|
||||
onUserConnectionSuccess(user), errorCallback);
|
||||
|
@ -113,6 +113,12 @@ public class UserList {
|
|||
user.addObserver(evt -> userChangeObserver(user, evt));
|
||||
}
|
||||
|
||||
private PeerUser createNewPendingUser() {
|
||||
PeerUser user = new PeerUser();
|
||||
addUserToPendingList(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new user from its id and puts it in the inactive user list.
|
||||
* We first try to fetch it from active and inactive users to prevent duplicates.
|
||||
|
@ -121,7 +127,7 @@ public class UserList {
|
|||
* @param id The new user's id.
|
||||
* @return A new PeerUser, or null if the user is already connected
|
||||
*/
|
||||
private PeerUser createNewUser(int id) {
|
||||
private PeerUser createNewPendingUser(String id) {
|
||||
// If already connected, warn and return
|
||||
if (activeUsers.containsKey(id)) {
|
||||
Log.w(getClass().getSimpleName(),
|
||||
|
@ -135,7 +141,7 @@ public class UserList {
|
|||
if (user == null) {
|
||||
// Username is set on TCP connection start or db fetch
|
||||
user = new PeerUser(id);
|
||||
inactiveUsers.put(id, user);
|
||||
addUserToPendingList(user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
@ -147,15 +153,17 @@ public class UserList {
|
|||
*
|
||||
* @param id The new user's id.
|
||||
* @param username The new user's username.
|
||||
* @return A new PeerUser, or null if the user is already connected
|
||||
*/
|
||||
private PeerUser createNewUser(int id, String username) {
|
||||
final PeerUser user = createNewUser(id);
|
||||
if (user != null) {
|
||||
user.setUsername(username);
|
||||
notifyNewUserObservers(user);
|
||||
private void createNewInactiveUser(String id, String username) {
|
||||
final PeerUser user = new PeerUser(id, username);
|
||||
inactiveUsers.put(id, user);
|
||||
notifyNewUserObservers(user);
|
||||
}
|
||||
|
||||
private void addUserToPendingList(PeerUser user) {
|
||||
if (!pendingUsers.contains(user)) {
|
||||
pendingUsers.add(user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +172,7 @@ public class UserList {
|
|||
* @param user The user to move
|
||||
*/
|
||||
private void moveUserToActiveList(PeerUser user) {
|
||||
final int id = user.id;
|
||||
final String id = user.id;
|
||||
if (!inactiveUsers.containsKey(id)) {
|
||||
if (activeUsers.containsKey(id)) {
|
||||
Log.w(getClass().getSimpleName(), "Tried to set state " + PeerUser.State.CONNECTED + " on an already connected user: user id " + id);
|
||||
|
@ -183,7 +191,7 @@ public class UserList {
|
|||
* @param user The user to move
|
||||
*/
|
||||
private void moveUserToInactiveList(PeerUser user) {
|
||||
final int id = user.id;
|
||||
final String id = user.id;
|
||||
if (!activeUsers.containsKey(id)) {
|
||||
if (inactiveUsers.containsKey(id)) {
|
||||
Log.w(getClass().getSimpleName(), "Tried to set state " + PeerUser.State.DISCONNECTED + " on an already disconnected user: user id " + id);
|
||||
|
|
|
@ -28,53 +28,53 @@ public class DatabaseTest {
|
|||
latch2.countDown();
|
||||
}, Assertions::fail);
|
||||
|
||||
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
|
||||
db.getChatHistory(new UserInformation("1", "Yohan"), new Date(0), new Date(), history -> {
|
||||
assertEquals(history.size(), 0);
|
||||
latch2.countDown();
|
||||
}, Assertions::fail);
|
||||
latch2.await();
|
||||
|
||||
CountDownLatch latch8 = new CountDownLatch(1);
|
||||
db.addUser(new UserInformation(3, null), latch8::countDown, Assertions::fail);
|
||||
db.addUser(new UserInformation("3", null), latch8::countDown, Assertions::fail);
|
||||
latch8.await();
|
||||
|
||||
|
||||
CountDownLatch latch3 = new CountDownLatch(5);
|
||||
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
|
||||
db.addMessage(new Message(new UserInformation("1", "Yohan"), new UserInformation("2", "Arnaud"),
|
||||
new Date(1609843556860L), "Coucou Arnaud !"), latch3::countDown, Assertions::fail);
|
||||
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"),
|
||||
db.addMessage(new Message(new UserInformation("2", "Arnaud"), new UserInformation("1", "Yohan"),
|
||||
new Date(1609843556861L), "Coucou Yohan !"), latch3::countDown, Assertions::fail);
|
||||
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
|
||||
db.addMessage(new Message(new UserInformation("1", "Yohan"), new UserInformation("2", "Arnaud"),
|
||||
new Date(1609843556862L), "Ça va ?"), latch3::countDown, Assertions::fail);
|
||||
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"),
|
||||
db.addMessage(new Message(new UserInformation("2", "Arnaud"), new UserInformation("1", "Yohan"),
|
||||
new Date(1609843556863L), "Ouais et toi ?"), latch3::countDown, Assertions::fail);
|
||||
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
|
||||
db.addMessage(new Message(new UserInformation("1", "Yohan"), new UserInformation("2", "Arnaud"),
|
||||
new Date(1609843556864L), "Super !"), latch3::countDown, Assertions::fail);
|
||||
latch3.await();
|
||||
|
||||
CountDownLatch latch4 = new CountDownLatch(2);
|
||||
db.getAllUsers(users -> {
|
||||
assertEquals(3, users.size());
|
||||
assertEquals(3, users.get(0).getId());
|
||||
assertEquals(1, users.get(1).getId());
|
||||
assertEquals(2, users.get(2).getId());
|
||||
assertEquals("3", users.get(0).getId());
|
||||
assertEquals("1", users.get(1).getId());
|
||||
assertEquals("2", users.get(2).getId());
|
||||
assertNull(users.get(0).getUsername());
|
||||
assertEquals("Yohan", users.get(1).getUsername());
|
||||
assertEquals("Arnaud", users.get(2).getUsername());
|
||||
latch4.countDown();
|
||||
}, Assertions::fail);
|
||||
|
||||
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
|
||||
db.getChatHistory(new UserInformation("1", "Yohan"), new Date(0), new Date(), history -> {
|
||||
assertEquals(5, history.size());
|
||||
assertEquals("Coucou Arnaud !", history.get(0).getText());
|
||||
assertEquals(1, history.get(0).getSender().id);
|
||||
assertEquals(2, history.get(0).getRecipient().id);
|
||||
assertEquals("1", history.get(0).getSender().id);
|
||||
assertEquals("2", history.get(0).getRecipient().id);
|
||||
assertEquals("Yohan", history.get(0).getSender().getUsername());
|
||||
assertEquals("Arnaud", history.get(0).getRecipient().getUsername());
|
||||
|
||||
assertEquals("Ouais et toi ?", history.get(3).getText());
|
||||
assertEquals(2, history.get(3).getSender().id);
|
||||
assertEquals(1, history.get(3).getRecipient().id);
|
||||
assertEquals("2", history.get(3).getSender().id);
|
||||
assertEquals("1", history.get(3).getRecipient().id);
|
||||
assertEquals("Arnaud", history.get(3).getSender().getUsername());
|
||||
assertEquals("Yohan", history.get(3).getRecipient().getUsername());
|
||||
latch4.countDown();
|
||||
|
@ -82,16 +82,9 @@ public class DatabaseTest {
|
|||
latch4.await();
|
||||
|
||||
CountDownLatch latch5 = new CountDownLatch(1);
|
||||
db.updateUsername(new UserInformation(2, "Toto"), latch5::countDown, Assertions::fail);
|
||||
db.updateUsername(new UserInformation("2", "Toto"), latch5::countDown, Assertions::fail);
|
||||
latch5.await();
|
||||
|
||||
CountDownLatch latch6 = new CountDownLatch(1);
|
||||
db.getUsername(2, username -> {
|
||||
assertEquals("Toto", username);
|
||||
latch6.countDown();
|
||||
}, Assertions::fail);
|
||||
latch6.await();
|
||||
|
||||
CountDownLatch latch7 = new CountDownLatch(1);
|
||||
db.resetTables(latch7::countDown, Assertions::fail);
|
||||
latch7.await();
|
||||
|
|
Loading…
Reference in a new issue