improve database compatibility with UI

This commit is contained in:
Arnaud Vergnet 2021-01-04 20:51:05 +01:00
parent 3d6d1b7a15
commit a3873394be
8 changed files with 165 additions and 56 deletions

View file

@ -53,7 +53,10 @@ public class ChatHistory {
* Loads history from database * Loads history from database
*/ */
public void load() { public void load() {
db.getChatHistory(new UserInformation(user), new Date(), new Date(), this::onLoaded); final Date from = new Date();
// Load whole history
from.setTime(0);
db.getChatHistory(new UserInformation(user), from, new Date(), this::onLoaded);
} }
/** /**

View file

@ -1,5 +1,6 @@
package fr.insa.clavardator.chat; package fr.insa.clavardator.chat;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.User; import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.UserInformation; import fr.insa.clavardator.users.UserInformation;
@ -46,6 +47,14 @@ public class Message implements Serializable {
return recipient; return recipient;
} }
public UserInformation getCorrespondent() {
if (CurrentUser.getInstance().isLocalId(sender.id)) {
return recipient;
} else {
return sender;
}
}
public Date getDate() { public Date getDate() {
return date; return date;
} }

View file

@ -2,10 +2,12 @@ package fr.insa.clavardator.db;
import fr.insa.clavardator.chat.FileMessage; import fr.insa.clavardator.chat.FileMessage;
import fr.insa.clavardator.chat.Message; import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.User; import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.UserInformation; import fr.insa.clavardator.users.UserInformation;
import fr.insa.clavardator.util.Log; import fr.insa.clavardator.util.Log;
import org.intellij.lang.annotations.Language; import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Nullable;
import java.sql.*; import java.sql.*;
import java.util.ArrayList; import java.util.ArrayList;
@ -31,7 +33,6 @@ public class DatabaseController {
*/ */
public void connect() { public void connect() {
connectToDatabase("clavardator"); connectToDatabase("clavardator");
initTables();
} }
/** /**
@ -103,16 +104,19 @@ public class DatabaseController {
Log.v(getClass().getSimpleName(), "Creating table user..."); Log.v(getClass().getSimpleName(), "Creating table user...");
executeUpdate("CREATE TABLE IF NOT EXISTS user " + executeUpdate("CREATE TABLE IF NOT EXISTS user " +
"(id INTEGER UNSIGNED PRIMARY KEY NOT NULL," + "(id INTEGER UNSIGNED PRIMARY KEY NOT NULL," +
" username TINYTEXT NOT NULL)"); " username TINYTEXT NULLABLE )");
} }
/** /**
* Creates all needed tables if non-existent * Creates all needed tables if non-existent
*/ */
private void initTables() { public void init(@Nullable FinishCallback callback) {
try { try {
createMessageTable(); createMessageTable();
createUserTable(); createUserTable();
if (callback != null) {
callback.onFinish();
}
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -153,7 +157,7 @@ public class DatabaseController {
*/ */
public void resetTables() { public void resetTables() {
dropTables(); dropTables();
initTables(); init(null);
} }
@ -165,7 +169,7 @@ public class DatabaseController {
public void getAllUsers(UsersCallback callback) { public void getAllUsers(UsersCallback callback) {
try { try {
Statement stmt = connection.createStatement(); Statement stmt = connection.createStatement();
String sql = "SELECT * FROM user"; String sql = "SELECT * FROM user WHERE id != " + CurrentUser.getInstance().getId();
Log.v(getClass().getSimpleName(), "Fetching users from db... "); Log.v(getClass().getSimpleName(), "Fetching users from db... ");
ResultSet res = stmt.executeQuery(sql); ResultSet res = stmt.executeQuery(sql);
@ -196,7 +200,7 @@ public class DatabaseController {
* @param message The message to add to the database * @param message The message to add to the database
* @param callback Function called when the request is done * @param callback Function called when the request is done
*/ */
public void addMessage(Message message, MessageCallback callback) { public void addMessage(Message message, FinishCallback callback) {
try { try {
// TODO: Handle messages containing files: // TODO: Handle messages containing files:
// store file in file system and put the path in filePath // store file in file system and put the path in filePath
@ -208,42 +212,67 @@ public class DatabaseController {
// Insert the new message // Insert the new message
Log.v(getClass().getSimpleName(), "Inserting message into db... "); Log.v(getClass().getSimpleName(), "Inserting message into db... ");
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;
}
executeUpdate("INSERT INTO message " + executeUpdate("INSERT INTO message " +
"(timestamp, sender, recipient, text, file_path) " + "(timestamp, sender, recipient, text, file_path) " +
"VALUES (" + "VALUES (" +
message.getDate().getTime() + ", " + message.getDate().getTime() + ", " +
message.getSender().id + ", " + senderId + ", " +
message.getRecipient().id + ", " + recipientId + ", " +
"\"" + message.getText() + "\", " + "\"" + message.getText() + "\", " +
filePath + filePath +
")"); ")");
// Insert the sender Log.v(getClass().getSimpleName(), "Inserting correspondent into db... ");
Log.v(getClass().getSimpleName(), "Inserting sender into db... "); addUser(message.getCorrespondent());
addUser(message.getSender());
// Insert the recipient
Log.v(getClass().getSimpleName(), "Inserting recipient into db... ");
addUser(message.getRecipient());
if (callback != null) { if (callback != null) {
callback.onMessageSaved(); callback.onFinish();
} }
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public void addUser(UserInformation user) {
addUser(user, null);
}
/** /**
* Inserts the given user if not existing * Inserts the given user if not existing
* *
* @param user The user information to store * @param user The user information to store
* @throws SQLException SQL error
*/ */
private void addUser(UserInformation user) throws SQLException { public void addUser(UserInformation user, @Nullable FinishCallback callback) {
executeUpdate("INSERT OR IGNORE INTO user " + try {
"(id, username) " + Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername());
"VALUES (" + user.id + ", \"" + user.getUsername() + "\")"); if (user.getUsername() != null) {
executeUpdate("INSERT OR IGNORE INTO user " +
"(id, username) " +
"VALUES (" + user.id + ", \"" + user.getUsername() + "\")");
} else {
executeUpdate("INSERT OR IGNORE INTO user " +
"(id) " +
"VALUES (" + user.id + ")");
}
if (callback != null) {
callback.onFinish();
}
} catch (SQLException e) {
e.printStackTrace();
}
} }
/** /**
@ -296,16 +325,51 @@ public class DatabaseController {
} }
} }
public void updateUsername(UserInformation user) {
try {
executeUpdate("UPDATE user SET " +
"username = '" + user.getUsername() + "' where id = " + user.id);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void getUsername(int id, UsernameCallback callback) {
try {
Statement statement = connection.createStatement();
String sql = "SELECT username from user where id =" + id;
Log.v(getClass().getSimpleName(), "Fetching users from db... ");
ResultSet res = statement.executeQuery(sql);
String username = null;
if (res.next()) {
username = res.getString("username");
}
Log.v(getClass().getSimpleName(), res.getFetchSize() + " rows fetched");
res.close();
statement.close();
if (callback != null) {
callback.onUsernameFetched(username);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public interface UsersCallback { public interface UsersCallback {
void onUsersFetched(ArrayList<User> users); void onUsersFetched(ArrayList<User> users);
} }
public interface UsernameCallback {
void onUsernameFetched(String username);
}
public interface HistoryCallback { public interface HistoryCallback {
void onHistoryFetched(ArrayList<Message> history); void onHistoryFetched(ArrayList<Message> history);
} }
public interface MessageCallback { public interface FinishCallback {
void onMessageSaved(); void onFinish();
} }
} }

View file

@ -1,6 +1,7 @@
package fr.insa.clavardator.ui; package fr.insa.clavardator.ui;
import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.controls.JFXSnackbar;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.ui.chat.ChatController; import fr.insa.clavardator.ui.chat.ChatController;
import fr.insa.clavardator.ui.dialogs.AboutDialogController; import fr.insa.clavardator.ui.dialogs.AboutDialogController;
import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController; import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController;
@ -64,7 +65,7 @@ public class MainController implements Initializable {
if (historyLoaded) { if (historyLoaded) {
if (newState == CurrentUser.State.VALID) if (newState == CurrentUser.State.VALID)
startChat(); startChat();
else if (newState != CurrentUser.State.NONE) { else if (newState != CurrentUser.State.UNINITIALIZED) {
final boolean isError = newState == CurrentUser.State.INVALID; final boolean isError = newState == CurrentUser.State.INVALID;
if (isError) { if (isError) {
endChat(); endChat();
@ -78,7 +79,7 @@ public class MainController implements Initializable {
historyLoaded = true; historyLoaded = true;
final CurrentUser.State userState = CurrentUser.getInstance().getState(); final CurrentUser.State userState = CurrentUser.getInstance().getState();
// If the history loaded after the current user, fire the state change event again // If the history loaded after the current user, fire the state change event again
if (userState != CurrentUser.State.NONE) { if (userState != CurrentUser.State.UNINITIALIZED) {
onCurrentUserStateChange(userState); onCurrentUserStateChange(userState);
} }
} }
@ -191,14 +192,6 @@ public class MainController implements Initializable {
loadingController.show("Initialisation de Clavardator..."); loadingController.show("Initialisation de Clavardator...");
snackbar = new JFXSnackbar(root); snackbar = new JFXSnackbar(root);
try {
currentUser.init();
Log.v("INIT", "Current user: " + currentUser.getId());
} catch (SocketException e) {
Log.e("INIT", "Could not init user", e);
showError();
}
listController.setUserSelectedListener((user) -> chatController.setRemoteUser(user)); listController.setUserSelectedListener((user) -> chatController.setRemoteUser(user));
chatController.addAttachmentListener(() -> System.out.println("attach event")); chatController.addAttachmentListener(() -> System.out.println("attach event"));
chatController.addSendErrorListener((e) -> showSnackbarEvent("Erreur: Message non envoyé", SnackbarController.Mode.ERROR)); chatController.addSendErrorListener((e) -> showSnackbarEvent("Erreur: Message non envoyé", SnackbarController.Mode.ERROR));
@ -206,11 +199,24 @@ public class MainController implements Initializable {
toolbarController.addAboutListener(this::openAboutDialog); toolbarController.addAboutListener(this::openAboutDialog);
} }
private void initDb() {
final DatabaseController db = new DatabaseController();
db.init(() -> {
try {
Log.v("INIT", "Current user: " + currentUser.getId());
currentUser.init(() -> userList.retrievedPreviousUsers(this::onHistoryLoaded));
} catch (SocketException e) {
Log.e("INIT", "Could not init user", e);
showError();
}
});
}
public void setUserList(UserList userList) { public void setUserList(UserList userList) {
this.userList = userList; this.userList = userList;
userList.retrievedPreviousUsers(this::onHistoryLoaded);
listController.setUserList(userList); listController.setUserList(userList);
listController.setRefreshUserListener(this::discoverActiveUsers); listController.setRefreshUserListener(this::discoverActiveUsers);
editUserDialogController.setUserList(userList); editUserDialogController.setUserList(userList);
initDb();
} }
} }

View file

@ -34,7 +34,7 @@ public class MessageListItemController implements Initializable {
currentMessage = message; currentMessage = message;
button.setText(message.getText()); button.setText(message.getText());
timestamp.setText(DateFormat.getTimeInstance().format(message.getDate())); timestamp.setText(DateFormat.getTimeInstance().format(message.getDate()));
if (message.getSender().id == CurrentUser.getInstance().getId()) { if (CurrentUser.getInstance().isLocalId(message.getSender().id)) {
container.setAlignment(Pos.CENTER_RIGHT); container.setAlignment(Pos.CENTER_RIGHT);
button.getStyleClass().remove("message-other"); button.getStyleClass().remove("message-other");
button.getStyleClass().add("message-self"); button.getStyleClass().add("message-self");

View file

@ -55,12 +55,14 @@ public class UserListController implements Initializable {
} }
private void onUserConnected(PeerUser user) { private void onUserConnected(PeerUser user) {
if (!peerUserListView.getItems().contains(user)) { Platform.runLater(() -> {
Log.v(this.getClass().getSimpleName(), "Add user to UI"); if (!peerUserListView.getItems().contains(user)) {
Platform.runLater(() -> peerUserListView.getItems().add(user)); Log.v(this.getClass().getSimpleName(), "Add user to UI");
} else { peerUserListView.getItems().add(user);
Log.w(this.getClass().getSimpleName(), "User already added to ui, skipping..."); } else {
} Log.w(this.getClass().getSimpleName(), "User already added to ui, skipping...");
}
});
} }
public void setUserList(UserList userList) { public void setUserList(UserList userList) {

View file

@ -1,14 +1,13 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.network.NetUtil; import fr.insa.clavardator.network.NetUtil;
import fr.insa.clavardator.util.Log; import fr.insa.clavardator.util.Log;
import javafx.application.Platform;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.SocketException; import java.net.SocketException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import static fr.insa.clavardator.network.NetUtil.getIdFromIp; import static fr.insa.clavardator.network.NetUtil.getIdFromIp;
@ -17,9 +16,12 @@ public class CurrentUser extends User {
private State state; private State state;
private ArrayList<Integer> validIds;
private CurrentUser() { private CurrentUser() {
super(); super();
state = State.UNINITIALIZED; state = State.UNINITIALIZED;
validIds = new ArrayList<>();
} }
/** /**
@ -31,22 +33,33 @@ public class CurrentUser extends User {
return instance; return instance;
} }
public void init() throws SocketException { public void init(InitCallback callback) throws SocketException {
final List<InetAddress> addresses = NetUtil.listAllLocalAddresses(); final List<InetAddress> addresses = NetUtil.listAllLocalAddresses();
if (addresses.size() > 0) { // Save all addresses for this user
id = getIdFromIp(addresses.get(0)); 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);
} else { } else {
throw new SocketException(); throw new SocketException();
} }
// TODO replace by db username fetching final DatabaseController db = new DatabaseController();
Timer t = new Timer(); // Make sure the user is in the db then set its username
t.schedule(new TimerTask() { db.addUser(new UserInformation(this), () -> {
@Override db.getUsername(id, username -> {
public void run() { if (username != null) {
setState(State.NONE); Log.v(getClass().getSimpleName(), "Last username found : " + username);
t.cancel(); setUsername(username);
} } else {
}, 500); Log.v(getClass().getSimpleName(), "No last username found, asking user...");
setState(State.NONE);
}
if (callback != null) {
callback.onFinish();
}
});
});
} }
@Override @Override
@ -68,10 +81,18 @@ public class CurrentUser extends User {
return state; return state;
} }
public boolean isLocalId(int id) {
return validIds.contains(id);
}
public enum State { public enum State {
UNINITIALIZED, UNINITIALIZED,
VALID, VALID,
INVALID, INVALID,
NONE NONE
} }
public interface InitCallback {
void onFinish();
}
} }

View file

@ -1,5 +1,7 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
import fr.insa.clavardator.db.DatabaseController;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeSupport;
import java.io.Serializable; import java.io.Serializable;
@ -41,6 +43,8 @@ public class User implements Serializable {
protected void setUsername(String newUsername) { protected void setUsername(String newUsername) {
pcs.firePropertyChange("username", this.username, newUsername); pcs.firePropertyChange("username", this.username, newUsername);
this.username = newUsername; this.username = newUsername;
final DatabaseController db = new DatabaseController();
db.updateUsername(new UserInformation(this));
} }
@Override @Override