Merge branch 'develop' into f/system_commands
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>envoy-client</name>
|
||||
<name>client</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
@ -1,3 +0,0 @@
|
||||
default.configuration=
|
||||
eclipse.preferences.version=1
|
||||
hibernate3.enabled=false
|
@ -5,10 +5,8 @@ import static java.util.function.Function.identity;
|
||||
import java.io.File;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import envoy.client.ui.Startup;
|
||||
import envoy.data.Config;
|
||||
import envoy.data.ConfigItem;
|
||||
import envoy.data.LoginCredentials;
|
||||
|
||||
/**
|
||||
* Implements a configuration specific to the Envoy Client with default values
|
||||
@ -40,8 +38,8 @@ public class ClientConfig extends Config {
|
||||
items.put("localDB", new ConfigItem<>("localDB", "db", File::new, new File("localDB"), true));
|
||||
items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", Boolean::parseBoolean, false, false));
|
||||
items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", File::new, new File(System.getProperty("user.home"), ".envoy"), true));
|
||||
items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.CONFIG, true));
|
||||
items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.FINEST, true));
|
||||
items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.OFF, true));
|
||||
items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.OFF, true));
|
||||
items.put("user", new ConfigItem<>("user", "u", identity()));
|
||||
items.put("password", new ConfigItem<>("password", "pw", identity()));
|
||||
}
|
||||
@ -105,11 +103,4 @@ public class ClientConfig extends Config {
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; }
|
||||
|
||||
/**
|
||||
* @return login credentials for the specified user name and password, without
|
||||
* the registration option
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public LoginCredentials getLoginCredentials() { return new LoginCredentials(getUser(), getPassword(), false, Startup.VERSION); }
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package envoy.client.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Instant;
|
||||
|
||||
import envoy.client.net.WriteProxy;
|
||||
import envoy.data.Contact;
|
||||
@ -46,7 +46,7 @@ public class GroupChat extends Chat {
|
||||
else {
|
||||
gmsg.getMemberStatuses().replace(sender.getID(), MessageStatus.READ);
|
||||
writeProxy
|
||||
.writeMessageStatusChange(new GroupMessageStatusChange(gmsg.getID(), MessageStatus.READ, LocalDateTime.now(), sender.getID()));
|
||||
.writeMessageStatusChange(new GroupMessageStatusChange(gmsg.getID(), MessageStatus.READ, Instant.now(), sender.getID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package envoy.client.data;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
import envoy.data.*;
|
||||
@ -20,11 +21,12 @@ import envoy.event.NameChange;
|
||||
*/
|
||||
public abstract class LocalDB {
|
||||
|
||||
protected User user;
|
||||
protected Map<String, Contact> users = new HashMap<>();
|
||||
protected List<Chat> chats = new ArrayList<>();
|
||||
protected IDGenerator idGenerator;
|
||||
protected CacheMap cacheMap = new CacheMap();
|
||||
protected User user;
|
||||
protected Map<String, User> users = new HashMap<>();
|
||||
protected List<Chat> chats = new ArrayList<>();
|
||||
protected IDGenerator idGenerator;
|
||||
protected CacheMap cacheMap = new CacheMap();
|
||||
protected Instant lastSync = Instant.EPOCH;
|
||||
|
||||
{
|
||||
cacheMap.put(Message.class, new Cache<>());
|
||||
@ -42,10 +44,11 @@ public abstract class LocalDB {
|
||||
* Stores all users. If the client user is specified, their chats will be stored
|
||||
* as well. The message id generator will also be saved if present.
|
||||
*
|
||||
* @param isOnline determines which {@code lastSync} time stamp is saved
|
||||
* @throws Exception if the saving process failed
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void save() throws Exception {}
|
||||
public void save(boolean isOnline) throws Exception {}
|
||||
|
||||
/**
|
||||
* Loads all user data.
|
||||
@ -77,7 +80,7 @@ public abstract class LocalDB {
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void synchronize() {
|
||||
user.getContacts().stream().filter(u -> u instanceof User && !users.containsKey(u.getName())).forEach(u -> users.put(u.getName(), u));
|
||||
user.getContacts().stream().filter(u -> u instanceof User && !users.containsKey(u.getName())).forEach(u -> users.put(u.getName(), (User) u));
|
||||
users.put(user.getName(), user);
|
||||
|
||||
// Synchronize user status data
|
||||
@ -98,7 +101,7 @@ public abstract class LocalDB {
|
||||
* user names as keys
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Map<String, Contact> getUsers() { return users; }
|
||||
public Map<String, User> getUsers() { return users; }
|
||||
|
||||
/**
|
||||
* @return all saved {@link Chat} objects that list the client user as the
|
||||
@ -148,6 +151,12 @@ public abstract class LocalDB {
|
||||
*/
|
||||
public CacheMap getCacheMap() { return cacheMap; }
|
||||
|
||||
/**
|
||||
* @return the time stamp when the database was last saved
|
||||
* @since Envoy Client v0.2-beta
|
||||
*/
|
||||
public Instant getLastSync() { return lastSync; }
|
||||
|
||||
/**
|
||||
* Searches for a message by ID.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
package envoy.client.data;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -26,7 +27,7 @@ public final class PersistentLocalDB extends LocalDB {
|
||||
/**
|
||||
* Constructs an empty local database. To serialize any user-specific data to
|
||||
* the file system, call {@link PersistentLocalDB#initializeUserStorage()} first
|
||||
* and then {@link PersistentLocalDB#save()}.
|
||||
* and then {@link PersistentLocalDB#save(boolean)}.
|
||||
*
|
||||
* @param dbDir the directory in which to persist data
|
||||
* @throws IOException if {@code dbDir} is a file (and not a directory)
|
||||
@ -57,12 +58,12 @@ public final class PersistentLocalDB extends LocalDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws IOException {
|
||||
public void save(boolean isOnline) throws IOException {
|
||||
// Save users
|
||||
SerializationUtils.write(usersFile, users);
|
||||
|
||||
// Save user data
|
||||
if (user != null) SerializationUtils.write(userFile, chats, cacheMap);
|
||||
// Save user data and last sync time stamp
|
||||
if (user != null) SerializationUtils.write(userFile, chats, cacheMap, isOnline ? Instant.now() : lastSync);
|
||||
|
||||
// Save id generator
|
||||
if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
|
||||
@ -76,6 +77,7 @@ public final class PersistentLocalDB extends LocalDB {
|
||||
try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
|
||||
chats = (ArrayList<Chat>) in.readObject();
|
||||
cacheMap = (CacheMap) in.readObject();
|
||||
lastSync = (Instant) in.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
package envoy.client.net;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import envoy.client.event.MessageCreationEvent;
|
||||
import envoy.data.Message;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
import envoy.event.EventBus;
|
||||
import envoy.util.EnvoyLog;
|
||||
|
||||
/**
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
@ -20,17 +17,12 @@ import envoy.util.EnvoyLog;
|
||||
*/
|
||||
public class ReceivedMessageProcessor implements Consumer<Message> {
|
||||
|
||||
private static final Logger logger = EnvoyLog.getLogger(ReceivedMessageProcessor.class);
|
||||
|
||||
@Override
|
||||
public void accept(Message message) {
|
||||
if (message.getStatus() != MessageStatus.SENT) logger.log(Level.WARNING, "The message has the unexpected status " + message.getStatus());
|
||||
else {
|
||||
// Update status to RECEIVED
|
||||
message.nextStatus();
|
||||
// Update status to RECEIVED
|
||||
if (message.getStatus() == MessageStatus.SENT) message.nextStatus();
|
||||
|
||||
// Dispatch event
|
||||
EventBus.getInstance().dispatch(new MessageCreationEvent(message));
|
||||
}
|
||||
// Dispatch event
|
||||
EventBus.getInstance().dispatch(new MessageCreationEvent(message));
|
||||
}
|
||||
}
|
||||
|
@ -121,12 +121,13 @@ public final class Startup extends Application {
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
logger.log(Level.INFO, "Saving local database and settings...");
|
||||
localDB.save(client.isOnline());
|
||||
Settings.getInstance().save();
|
||||
|
||||
logger.log(Level.INFO, "Closing connection...");
|
||||
client.close();
|
||||
|
||||
logger.log(Level.INFO, "Saving local database and settings...");
|
||||
localDB.save();
|
||||
Settings.getInstance().save();
|
||||
logger.log(Level.INFO, "Envoy was terminated by its user");
|
||||
} catch (final Exception e) {
|
||||
logger.log(Level.SEVERE, "Unable to save local files: ", e);
|
||||
|
@ -1,5 +1,7 @@
|
||||
package envoy.client.ui.controller;
|
||||
|
||||
import static envoy.data.Message.MessageStatus.RECEIVED;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -134,7 +136,13 @@ public final class ChatScene implements Restorable {
|
||||
// Listen to received messages
|
||||
eventBus.register(MessageCreationEvent.class, e -> {
|
||||
final var message = e.get();
|
||||
localDB.getChat(message instanceof GroupMessage ? message.getRecipientID() : message.getSenderID()).ifPresent(chat -> {
|
||||
|
||||
// The sender of the message is the recipient of the chat
|
||||
// Exceptions: this user is the sender (sync) or group message (group is
|
||||
// recipient)
|
||||
final long recipientID = message instanceof GroupMessage || message.getSenderID() == localDB.getUser().getID() ? message.getRecipientID()
|
||||
: message.getSenderID();
|
||||
localDB.getChat(recipientID).ifPresent(chat -> {
|
||||
chat.insert(message);
|
||||
if (chat.equals(currentChat)) {
|
||||
try {
|
||||
@ -143,8 +151,10 @@ public final class ChatScene implements Restorable {
|
||||
logger.log(Level.WARNING, "Could not read current chat: ", e1);
|
||||
}
|
||||
Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); });
|
||||
} else chat.incrementUnreadAmount();
|
||||
// Moving chat with most recent unreadMessages to the top
|
||||
// TODO: Increment unread counter for group messages with status < RECEIVED
|
||||
} else if (message.getSenderID() != localDB.getUser().getID() && message.getStatus() == RECEIVED) chat.incrementUnreadAmount();
|
||||
|
||||
// Move chat with most recent unread messages to the top
|
||||
Platform.runLater(() -> {
|
||||
chatList.getItems().remove(chat);
|
||||
chatList.getItems().add(0, chat);
|
||||
@ -182,12 +192,11 @@ public final class ChatScene implements Restorable {
|
||||
final var contact = e.get();
|
||||
switch (e.getOperationType()) {
|
||||
case ADD:
|
||||
localDB.getUsers().put(contact.getName(), contact);
|
||||
final Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
|
||||
if (contact instanceof User) localDB.getUsers().put(contact.getName(), (User) contact);
|
||||
Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
|
||||
Platform.runLater(() -> chatList.getItems().add(chat));
|
||||
break;
|
||||
case REMOVE:
|
||||
localDB.getUsers().remove(contact.getName());
|
||||
Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().equals(contact)));
|
||||
break;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package envoy.client.ui.controller;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -94,7 +95,8 @@ public final class LoginScene {
|
||||
userTextField.requestFocus();
|
||||
|
||||
// Perform automatic login if configured
|
||||
if (config.hasLoginCredentials()) performHandshake(config.getLoginCredentials());
|
||||
if (config.hasLoginCredentials())
|
||||
performHandshake(new LoginCredentials(config.getUser(), config.getPassword(), false, Startup.VERSION, loadLastSync(config.getUser())));
|
||||
}
|
||||
|
||||
@FXML
|
||||
@ -108,12 +110,13 @@ public final class LoginScene {
|
||||
new Alert(AlertType.ERROR, "The entered user name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
|
||||
userTextField.getTextField().clear();
|
||||
} else performHandshake(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), registerCheckBox.isSelected(),
|
||||
Startup.VERSION));
|
||||
Startup.VERSION, loadLastSync(userTextField.getTextField().getText())));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void offlineModeButtonPressed() {
|
||||
attemptOfflineMode(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), false, Startup.VERSION));
|
||||
attemptOfflineMode(
|
||||
new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), false, Startup.VERSION, localDB.getLastSync()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
@ -130,6 +133,18 @@ public final class LoginScene {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private Instant loadLastSync(String identifier) {
|
||||
try {
|
||||
localDB.loadUsers();
|
||||
localDB.setUser(localDB.getUsers().get(identifier));
|
||||
localDB.initializeUserStorage();
|
||||
localDB.loadUserData();
|
||||
} catch (Exception e) {
|
||||
// User storage empty, wrong user name etc. -> default lastSync
|
||||
}
|
||||
return localDB.getLastSync();
|
||||
}
|
||||
|
||||
private void performHandshake(LoginCredentials credentials) {
|
||||
try {
|
||||
client.performHandshake(credentials, cacheMap);
|
||||
|
@ -3,6 +3,7 @@ package envoy.client.ui.listcell;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
@ -35,11 +36,12 @@ import envoy.util.EnvoyLog;
|
||||
*/
|
||||
public class MessageControl extends Label {
|
||||
|
||||
private static User client;
|
||||
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
|
||||
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
|
||||
private static User client;
|
||||
|
||||
private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
|
||||
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
|
||||
.withZone(ZoneId.systemDefault());
|
||||
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
|
||||
private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
|
||||
|
||||
/**
|
||||
*
|
||||
@ -68,7 +70,8 @@ public class MessageControl extends Label {
|
||||
if (message.hasAttachment()) {
|
||||
switch (message.getAttachment().getType()) {
|
||||
case PICTURE:
|
||||
vbox.getChildren().add(new ImageView(new Image(new ByteArrayInputStream(message.getAttachment().getData()), 256, 256, true, true)));
|
||||
vbox.getChildren()
|
||||
.add(new ImageView(new Image(new ByteArrayInputStream(message.getAttachment().getData()), 256, 256, true, true)));
|
||||
break;
|
||||
case VIDEO:
|
||||
break;
|
||||
|
@ -1,3 +1,4 @@
|
||||
server=localhost
|
||||
port=8080
|
||||
localDB=.\\localDB
|
||||
localDB=localDB
|
||||
consoleLevelBarrier=FINER
|
||||
|
Reference in New Issue
Block a user