Add support for file
This commit is contained in:
parent
97c0d34159
commit
ad48bfa05f
10 changed files with 176 additions and 72 deletions
|
@ -1,42 +1,95 @@
|
|||
package fr.insa.clavardator.chat;
|
||||
|
||||
import fr.insa.clavardator.users.User;
|
||||
import fr.insa.clavardator.users.UserInformation;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileMessage extends Message {
|
||||
public static final long MAX_FILE_SIZE = 20 * 1024 * 1024; // 20 Mo
|
||||
public static final String STORED_FILES_FOLDER = "clavardator_stored_files";
|
||||
|
||||
private final byte[] rawFile;
|
||||
private final String fileName;
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Constructs a FileMessage
|
||||
*
|
||||
* @param sender The sender of the message
|
||||
* @param recipient The recipient of the message
|
||||
* @param date The sending date of the message
|
||||
* @param text The text of the message
|
||||
* @param filePath The path to the file
|
||||
* @throws IOException If the file does not exist, is not readable, is not a file, or is too large
|
||||
*/
|
||||
public FileMessage(UserInformation sender, UserInformation recipient, Date date, String text, String filePath) throws IOException {
|
||||
super(sender, recipient, date, text);
|
||||
|
||||
File file = new File(filePath);
|
||||
if (!file.exists())
|
||||
throw new IOException("The file does not exist");
|
||||
throw new IOException("The file " + filePath + " does not exist");
|
||||
if (!file.canRead())
|
||||
throw new IOException("The file is not readable");
|
||||
throw new IOException("The file " + filePath + " is not readable");
|
||||
if (!file.isFile())
|
||||
throw new IOException("The path does not lead to a file");
|
||||
throw new IOException("The path " + filePath + " does not lead to a file");
|
||||
if (file.length() > MAX_FILE_SIZE)
|
||||
throw new IOException("The file is too large");
|
||||
throw new IOException("The file " + filePath + " is too large");
|
||||
|
||||
fileName = file.getName();
|
||||
|
||||
FileInputStream stream = new FileInputStream(file);
|
||||
rawFile = stream.readAllBytes();
|
||||
path = filePath;
|
||||
}
|
||||
|
||||
public byte[] getRawFile() {
|
||||
return rawFile;
|
||||
public FileMessage(User sender, User recipient, Date date, String text, String filePath) throws IOException {
|
||||
this(new UserInformation(sender), new UserInformation(recipient), date, text, filePath);
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the file in the clavardator directory.
|
||||
* The field {@code path} is then updated to point to the new location.
|
||||
*
|
||||
* @return the path to the file
|
||||
*/
|
||||
public String storeFile() throws IOException {
|
||||
path = STORED_FILES_FOLDER + File.separatorChar + fileName;
|
||||
|
||||
// Create directory
|
||||
File dir = new File(STORED_FILES_FOLDER);
|
||||
dir.mkdirs();
|
||||
|
||||
// Create new file
|
||||
int extensionBeginning = fileName.lastIndexOf('.');
|
||||
String name = fileName;
|
||||
String extension = "";
|
||||
if (extensionBeginning != -1) {
|
||||
name = fileName.substring(0, extensionBeginning);
|
||||
extension = fileName.substring(extensionBeginning);
|
||||
}
|
||||
File file = new File(path);
|
||||
int suffix = 1;
|
||||
while (!file.createNewFile()) {
|
||||
path = STORED_FILES_FOLDER + File.separatorChar + name + "_" + suffix++ + extension;
|
||||
file = new File(path);
|
||||
}
|
||||
|
||||
// write to the file
|
||||
FileInputStream stream = new FileInputStream(fileName);
|
||||
byte[] rawFile = stream.readAllBytes();
|
||||
|
||||
FileOutputStream ostream = new FileOutputStream(file);
|
||||
ostream.write(rawFile);
|
||||
ostream.close();
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,12 @@
|
|||
package fr.insa.clavardator.chat;
|
||||
|
||||
import fr.insa.clavardator.users.User;
|
||||
import fr.insa.clavardator.users.UserInformation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public class ImageMessage extends Message {
|
||||
public ImageMessage(User sender, User recipient, Date date) {
|
||||
super(sender, recipient, date);
|
||||
}
|
||||
|
||||
public ImageMessage(User sender, User recipient, Date date, String text) {
|
||||
super(sender, recipient, date, text);
|
||||
public class ImageMessage extends FileMessage {
|
||||
public ImageMessage(UserInformation sender, UserInformation recipient, Date date, String text, String filePath) throws IOException {
|
||||
super(sender, recipient, date, text, filePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import fr.insa.clavardator.util.Log;
|
|||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -246,11 +247,14 @@ public class DatabaseController {
|
|||
addUser(message.getCorrespondent(), () -> {
|
||||
// Handle messages containing a file
|
||||
String filePath = "NULL";
|
||||
// TODO: Handle messages containing files:
|
||||
// store file in file system and put the path in filePath
|
||||
if (message instanceof FileMessage) {
|
||||
Log.w(getClass().getSimpleName(), "Functionality not implemented: file has not been saved");
|
||||
// filePath = ((FileMessage) message).getFileName();
|
||||
try {
|
||||
filePath = "'" + ((FileMessage) message).storeFile() + "'";
|
||||
} catch (IOException e) {
|
||||
Log.e(getClass().getSimpleName(), "Error while saving the file", e);
|
||||
errorCallback.onError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String recipientId = message.getRecipient().id;
|
||||
|
@ -263,7 +267,7 @@ public class DatabaseController {
|
|||
message.getDate().getTime() + ", " +
|
||||
"'" + senderId + "', " +
|
||||
"'" + recipientId + "', " +
|
||||
"\"" + message.getText() + "\", " +
|
||||
"'" + message.getText() + "', " +
|
||||
filePath +
|
||||
")";
|
||||
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
|
||||
|
@ -356,8 +360,13 @@ public class DatabaseController {
|
|||
if (filePath == null) {
|
||||
chatHistory.add(new Message(sender, recipient, date, text));
|
||||
} else {
|
||||
// TODO
|
||||
// chatHistory.add(new FileMessage(new UserInformation(sId, sUsername), new UserInformation(rId, rUsername), date, text, filePath));
|
||||
try {
|
||||
chatHistory.add(new FileMessage(sender, recipient, date, text, filePath));
|
||||
} catch (IOException e) {
|
||||
Log.e(getClass().getSimpleName(), "Error while opening the file", e);
|
||||
errorCallback.onError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.v(getClass().getSimpleName(), chatHistory.size() + " messages fetched");
|
||||
|
|
|
@ -238,7 +238,7 @@ public class MainController implements Initializable {
|
|||
snackbar = new JFXSnackbar(root);
|
||||
|
||||
listController.setUserSelectedListener((user) -> chatController.setRemoteUser(user));
|
||||
chatController.setAttachmentListener(() -> System.out.println("attach event"));
|
||||
// chatController.setAttachmentListener(() -> System.out.println("attach event"));
|
||||
chatController.setSendErrorListener((e) -> showSnackbarEvent("Erreur: Message non envoyé", SnackbarController.Mode.ERROR));
|
||||
toolbarController.setEditListener(() -> openEditUsernameDialog(EditUsernameDialogController.Mode.EDIT));
|
||||
toolbarController.setAboutListener(this::openAboutDialog);
|
||||
|
|
|
@ -2,7 +2,6 @@ package fr.insa.clavardator.ui.chat;
|
|||
|
||||
import fr.insa.clavardator.chat.ChatHistory;
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||
import fr.insa.clavardator.ui.LoadingScreenController;
|
||||
import fr.insa.clavardator.ui.NoSelectionModel;
|
||||
import fr.insa.clavardator.users.PeerUser;
|
||||
|
@ -37,12 +36,12 @@ public class ChatController implements Initializable {
|
|||
private VBox emptyContainer;
|
||||
private PeerUser remoteUser;
|
||||
|
||||
public void setAttachmentListener(ButtonPressEvent listener) {
|
||||
chatFooterController.setAttachmentListener(listener);
|
||||
}
|
||||
public void setSendErrorListener(ErrorCallback listener) {
|
||||
chatFooterController.setSendErrorListener(listener);
|
||||
}
|
||||
// public void setAttachmentListener(ButtonPressEvent listener) {
|
||||
// chatFooterController.setAttachmentListener(listener);
|
||||
// }
|
||||
public void setSendErrorListener(ErrorCallback listener) {
|
||||
chatFooterController.setSendErrorListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the user that finished loading is the right one then set the chat state to done
|
||||
|
|
|
@ -2,7 +2,6 @@ package fr.insa.clavardator.ui.chat;
|
|||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import fr.insa.clavardator.ui.ButtonPressEvent;
|
||||
import fr.insa.clavardator.users.PeerUser;
|
||||
import fr.insa.clavardator.util.ErrorCallback;
|
||||
import fr.insa.clavardator.util.Log;
|
||||
|
@ -12,8 +11,10 @@ import javafx.fxml.FXML;
|
|||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -30,26 +31,31 @@ public class ChatFooterController implements Initializable {
|
|||
@FXML
|
||||
private JFXButton sendButton;
|
||||
|
||||
private ButtonPressEvent attachmentListeners;
|
||||
// private ButtonPressEvent attachmentListeners;
|
||||
private ErrorCallback sendErrorListeners;
|
||||
|
||||
private PeerUser remoteUser;
|
||||
private HashMap<PeerUser, String> savedText;
|
||||
|
||||
public void setAttachmentListener(ButtonPressEvent listener) {
|
||||
attachmentListeners = listener;
|
||||
}
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File attachedFile;
|
||||
|
||||
// public void setAttachmentListener(ButtonPressEvent listener) {
|
||||
// attachmentListeners = listener;
|
||||
// }
|
||||
|
||||
public void setSendErrorListener(ErrorCallback listener) {
|
||||
sendErrorListeners = listener;
|
||||
}
|
||||
|
||||
public void onAttachmentPress() {
|
||||
if (attachmentListeners != null) {
|
||||
attachmentListeners.onPress();
|
||||
}
|
||||
// if (attachmentListeners != null) {
|
||||
// attachmentListeners.onPress();
|
||||
// }
|
||||
attachedFile = fileChooser.showOpenDialog(container.getScene().getWindow());
|
||||
}
|
||||
|
||||
|
||||
public void onSendError(Exception e) {
|
||||
Log.e(this.getClass().getSimpleName(), "Error: Could not send message", e);
|
||||
if (sendErrorListeners != null) {
|
||||
|
@ -63,7 +69,12 @@ public class ChatFooterController implements Initializable {
|
|||
public void onSend() {
|
||||
if (!isTextFieldEmpty()) {
|
||||
if (remoteUser != null) {
|
||||
remoteUser.sendTextMessage(textField.getText(), this::onSendError);
|
||||
if (attachedFile == null) {
|
||||
remoteUser.sendTextMessage(textField.getText(), this::onSendError);
|
||||
} else {
|
||||
remoteUser.sendFileMessage(textField.getText(), attachedFile, this::onSendError);
|
||||
attachedFile = null;
|
||||
}
|
||||
} else {
|
||||
Log.e(this.getClass().getSimpleName(), "Error: remote user not set");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fr.insa.clavardator.ui.chat;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import fr.insa.clavardator.chat.FileMessage;
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import fr.insa.clavardator.users.CurrentUser;
|
||||
import javafx.fxml.FXML;
|
||||
|
@ -9,6 +10,9 @@ import javafx.geometry.Pos;
|
|||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -32,7 +36,20 @@ public class MessageListItemController implements Initializable {
|
|||
public void setMessage(Message message) {
|
||||
if (!message.equals(currentMessage)) {
|
||||
currentMessage = message;
|
||||
button.setText(message.getText());
|
||||
String text = message.getText();
|
||||
if (message instanceof FileMessage) {
|
||||
FileMessage fileMessage = ((FileMessage) message);
|
||||
text += "\n<" + fileMessage.getFileName() + ">";
|
||||
button.setOnMouseClicked(event -> {
|
||||
Desktop desktop = Desktop.getDesktop();
|
||||
try {
|
||||
desktop.open(new File(fileMessage.getPath()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
button.setText(text);
|
||||
timestamp.setText(DateFormat.getTimeInstance().format(message.getDate()));
|
||||
clearBackground();
|
||||
if (CurrentUser.getInstance().getId().equals(message.getSender().id)) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fr.insa.clavardator.users;
|
||||
|
||||
import fr.insa.clavardator.chat.ChatHistory;
|
||||
import fr.insa.clavardator.chat.FileMessage;
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import fr.insa.clavardator.db.DatabaseController;
|
||||
import fr.insa.clavardator.errors.UsernameTakenException;
|
||||
|
@ -11,6 +12,8 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public class PeerUser extends User implements Comparable<PeerUser> {
|
||||
|
@ -51,6 +54,30 @@ public class PeerUser extends User implements Comparable<PeerUser> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message containing a file to this user
|
||||
*
|
||||
* @param msg The text message to send
|
||||
* @param errorCallback Callback on error
|
||||
*/
|
||||
public void sendFileMessage(String msg, File file, @Nullable ErrorCallback errorCallback) {
|
||||
if (connection != null) {
|
||||
Log.v(this.getClass().getSimpleName(),
|
||||
"Sending file message to " + this.getUsername() + " / " + this.getId() + ": " + msg);
|
||||
try {
|
||||
final FileMessage message = new FileMessage(CurrentUser.getInstance(), this, new Date(), msg, file.getPath());
|
||||
connection.send(message, () -> history.addMessage(message, errorCallback), errorCallback);
|
||||
} catch (IOException e) {
|
||||
Log.e(this.getClass().getSimpleName(), "Could not send message: error while opening file", e);
|
||||
if (errorCallback != null) {
|
||||
errorCallback.onError(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(this.getClass().getSimpleName(), "Could not send message: connection is not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends current user information to this user
|
||||
*
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package fr.insa.clavardator;
|
||||
|
||||
import fr.insa.clavardator.chat.FileMessage;
|
||||
import fr.insa.clavardator.chat.Message;
|
||||
import fr.insa.clavardator.db.DatabaseController;
|
||||
import fr.insa.clavardator.users.UserInformation;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -49,8 +51,8 @@ public class DatabaseTest {
|
|||
new Date(1609843556862L), "Ça va ?"), latch3::countDown, Assertions::fail);
|
||||
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"),
|
||||
new Date(1609843556864L), "Super !"), latch3::countDown, Assertions::fail);
|
||||
db.addMessage(new FileMessage(new UserInformation("1", "Yohan"), new UserInformation("2", "Arnaud"),
|
||||
new Date(1609843556864L), "Super !", "clavardator_test.db"), latch3::countDown, Assertions::fail);
|
||||
latch3.await();
|
||||
|
||||
CountDownLatch latch4 = new CountDownLatch(2);
|
||||
|
@ -69,18 +71,23 @@ public class DatabaseTest {
|
|||
new UserInformation("2", "Arnaud"), 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("Yohan", history.get(0).getSender().getUsername());
|
||||
assertEquals("Arnaud", history.get(0).getRecipient().getUsername());
|
||||
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("Arnaud", history.get(3).getSender().getUsername());
|
||||
assertEquals("Yohan", history.get(3).getRecipient().getUsername());
|
||||
latch4.countDown();
|
||||
}, Assertions::fail);
|
||||
assertEquals("Ouais et toi ?", history.get(3).getText());
|
||||
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());
|
||||
|
||||
String path = FileMessage.STORED_FILES_FOLDER + File.separatorChar + ((FileMessage) history.get(4)).getFileName();
|
||||
File file = new File(path);
|
||||
assertTrue(file.exists());
|
||||
file.delete();
|
||||
latch4.countDown();
|
||||
}, Assertions::fail);
|
||||
latch4.await();
|
||||
|
||||
CountDownLatch latch5 = new CountDownLatch(1);
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package fr.insa.clavardator;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
// See here: https://junit.org/junit5/docs/current/user-guide/#overview
|
||||
|
||||
public class FirstTest {
|
||||
private final TestClass t = new TestClass();
|
||||
|
||||
@Test
|
||||
void addition() {
|
||||
assertEquals(2, t.test(2));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue