Browse Source

Merge branch 'develop' into b/ui-fixes

pull/115/head
kske 7 months ago
parent
commit
05ed5da41b
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
  1. 37
      Jenkinsfile
  2. 4
      README.md
  3. 52
      client/src/main/java/envoy/client/data/LocalDB.java
  4. 7
      client/src/main/java/envoy/client/data/Settings.java
  5. 2
      client/src/main/java/envoy/client/helper/ShutdownHelper.java
  6. 52
      client/src/main/java/envoy/client/net/Client.java
  7. 20
      client/src/main/java/envoy/client/net/Receiver.java
  8. 10
      client/src/main/java/envoy/client/ui/SceneContext.java
  9. 15
      client/src/main/java/envoy/client/ui/Startup.java
  10. 8
      client/src/main/java/envoy/client/ui/StatusTrayIcon.java
  11. 30
      client/src/main/java/envoy/client/ui/controller/ChatScene.java
  12. 4
      client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java
  13. 6
      client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java
  14. 4
      client/src/main/java/envoy/client/ui/controller/LoginScene.java
  15. 2
      client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java
  16. 2
      client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java
  17. 2
      client/src/main/java/envoy/client/util/MessageUtil.java
  18. 2
      client/src/main/java/envoy/client/util/UserUtil.java
  19. 11
      client/src/main/java/module-info.java
  20. 11
      common/pom.xml
  21. 4
      common/src/main/java/envoy/data/IDGenerator.java
  22. 4
      common/src/main/java/envoy/data/Message.java
  23. 9
      common/src/main/java/envoy/event/Event.java
  24. 2
      common/src/main/java/module-info.java
  25. 4
      common/src/test/java/envoy/data/UserTest.java
  26. 7
      pom.xml
  27. 31
      server/src/main/java/envoy/server/processors/LoginCredentialProcessor.java

37
Jenkinsfile vendored

@ -0,0 +1,37 @@
pipeline {
agent any
options {
ansiColor('xterm')
}
stages {
stage('Build') {
steps {
sh 'mvn -DskipTests clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit '*/target/surefire-reports/*.xml'
}
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('KSKE SonarQube') {
sh 'mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.1.2184:sonar'
}
}
}
}
post {
success {
archiveArtifacts artifacts: 'client/target/envoy-client-*-shaded.jar, server/target/envoy-server-jar-with-dependencies.jar'
}
}
}

4
README.md

@ -17,6 +17,8 @@ If you want to transfer a file to another user, you can attach it to a message.
On the settings page some convenience features can be configured, as well as the color theme.
Additional info on how to use Envoy can be found [here](https://git.kske.dev/zdm/envoy/wiki) in the client section.
### System requirements
To run Envoy, you have to install a Java Runtime Environment (JRE) of at least version 11.
@ -29,7 +31,7 @@ Most major Linux distributions like Debian, Arch and Gentoo have a Noto emoji pa
To set up an Envoy server, download the package from the release page.
Because the project lacks external documentation for the moment, please refer to the Javadoc inside the source code to configure your Envoy instance.
To configure the behavior of Envoy Server, please have a look at the [documentation](https://git.kske.dev/zdm/envoy/wiki), specifically the server part.
### System requirements

52
client/src/main/java/envoy/client/data/LocalDB.java

@ -13,9 +13,8 @@ import java.util.stream.Stream;
import javafx.application.Platform;
import javafx.collections.*;
import dev.kske.eventbus.Event;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.EventListener;
import dev.kske.eventbus.core.*;
import dev.kske.eventbus.core.Event;
import envoy.data.*;
import envoy.data.Message.MessageStatus;
@ -35,7 +34,7 @@ import envoy.client.event.*;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.3-alpha
*/
public final class LocalDB implements EventListener {
public final class LocalDB {
// Data
private User user;
@ -246,7 +245,8 @@ public final class LocalDB implements EventListener {
* @throws IOException if the saving process failed
* @since Envoy Client v0.3-alpha
*/
@Event(eventType = EnvoyCloseEvent.class, priority = 500)
@Event(EnvoyCloseEvent.class)
@Priority(500)
private synchronized void save() {
// Stop saving if this account has been deleted
@ -300,37 +300,43 @@ public final class LocalDB implements EventListener {
onLogout();
}
@Event(priority = 500)
@Event
@Priority(500)
private void onMessage(Message msg) {
if (msg.getStatus() == MessageStatus.SENT)
msg.nextStatus();
}
@Event(priority = 500)
@Event
@Priority(500)
private void onGroupMessage(GroupMessage msg) {
// TODO: Cancel event once EventBus is updated
if (msg.getStatus() == MessageStatus.WAITING || msg.getStatus() == MessageStatus.READ)
logger.warning("The groupMessage has the unexpected status " + msg.getStatus());
}
@Event(priority = 500)
@Event
@Priority(500)
private void onMessageStatusChange(MessageStatusChange evt) {
getMessage(evt.getID()).ifPresent(msg -> msg.setStatus(evt.get()));
}
@Event(priority = 500)
@Event
@Priority(500)
private void onGroupMessageStatusChange(GroupMessageStatusChange evt) {
this.<GroupMessage>getMessage(evt.getID())
.ifPresent(msg -> msg.getMemberStatuses().replace(evt.getMemberID(), evt.get()));
}
@Event(priority = 500)
@Event
@Priority(500)
private void onUserStatusChange(UserStatusChange evt) {
getChat(evt.getID()).map(Chat::getRecipient).map(User.class::cast)
.ifPresent(u -> u.setStatus(evt.get()));
}
@Event(priority = 500)
@Event
@Priority(500)
private void onUserOperation(UserOperation operation) {
final var eventUser = operation.get();
switch (operation.getOperationType()) {
@ -356,13 +362,15 @@ public final class LocalDB implements EventListener {
Platform.runLater(() -> chats.add(new GroupChat(user, newGroup)));
}
@Event(priority = 500)
@Event
@Priority(500)
private void onGroupResize(GroupResize evt) {
getChat(evt.getGroupID()).map(Chat::getRecipient).map(Group.class::cast)
.ifPresent(evt::apply);
}
@Event(priority = 500)
@Event
@Priority(500)
private void onNameChange(NameChange evt) {
chats.stream().map(Chat::getRecipient).filter(c -> c.getID() == evt.getID()).findAny()
.ifPresent(c -> c.setName(evt.get()));
@ -384,7 +392,8 @@ public final class LocalDB implements EventListener {
*
* @since Envoy Client v0.2-beta
*/
@Event(eventType = Logout.class, priority = 50)
@Event(Logout.class)
@Priority(50)
private void onLogout() {
autoSaver.cancel();
autoSaveRestart = true;
@ -416,22 +425,26 @@ public final class LocalDB implements EventListener {
});
}
@Event(priority = 500)
@Event
@Priority(500)
private void onOwnStatusChange(OwnStatusChange statusChange) {
user.setStatus(statusChange.get());
}
@Event(eventType = ContactsChangedSinceLastLogin.class, priority = 500)
@Event(ContactsChangedSinceLastLogin.class)
@Priority(500)
private void onContactsChangedSinceLastLogin() {
contactsChanged = true;
}
@Event(priority = 500)
@Event
@Priority(500)
private void onContactDisabled(ContactDisabled event) {
getChat(event.get().getID()).ifPresent(chat -> chat.setDisabled(true));
}
@Event(priority = 500)
@Event
@Priority(500)
private void onAccountDeletion(AccountDeletion deletion) {
if (user.getID() == deletion.get())
logger.log(Level.WARNING,
@ -496,7 +509,8 @@ public final class LocalDB implements EventListener {
* @param idGenerator the message ID generator to set
* @since Envoy Client v0.3-alpha
*/
@Event(priority = 150)
@Event
@Priority(150)
public void setIDGenerator(IDGenerator idGenerator) { this.idGenerator = idGenerator; }
/**

7
client/src/main/java/envoy/client/data/Settings.java

@ -5,8 +5,7 @@ import java.util.*;
import java.util.logging.Level;
import java.util.prefs.Preferences;
import dev.kske.eventbus.*;
import dev.kske.eventbus.EventListener;
import dev.kske.eventbus.core.*;
import envoy.util.*;
@ -21,7 +20,7 @@ import envoy.client.event.EnvoyCloseEvent;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.2-alpha
*/
public final class Settings implements EventListener {
public final class Settings {
// Actual settings accessible by the rest of the application
private Map<String, SettingsItem<?>> items;
@ -69,7 +68,7 @@ public final class Settings implements EventListener {
* @throws IOException if an error occurs while saving the themes
* @since Envoy Client v0.2-alpha
*/
@Event(eventType = EnvoyCloseEvent.class)
@Event(EnvoyCloseEvent.class)
private void save() {
EnvoyLog.getLogger(Settings.class).log(Level.INFO, "Saving settings...");

2
client/src/main/java/envoy/client/helper/ShutdownHelper.java

@ -1,6 +1,6 @@
package envoy.client.helper;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.core.EventBus;
import envoy.client.data.*;
import envoy.client.event.EnvoyCloseEvent;

52
client/src/main/java/envoy/client/net/Client.java

@ -5,14 +5,14 @@ import java.net.Socket;
import java.util.concurrent.TimeoutException;
import java.util.logging.*;
import dev.kske.eventbus.*;
import dev.kske.eventbus.Event;
import dev.kske.eventbus.core.*;
import dev.kske.eventbus.core.Event;
import envoy.data.*;
import envoy.event.*;
import envoy.util.*;
import envoy.client.data.*;
import envoy.client.data.ClientConfig;
import envoy.client.event.EnvoyCloseEvent;
/**
@ -24,7 +24,7 @@ import envoy.client.event.EnvoyCloseEvent;
* @author Leon Hofmeister
* @since Envoy Client v0.1-alpha
*/
public final class Client implements EventListener, Closeable {
public final class Client implements Closeable {
// Connection handling
private Socket socket;
@ -55,13 +55,12 @@ public final class Client implements EventListener, Closeable {
* the handshake does exceed this time limit, an exception is thrown.
*
* @param credentials the login credentials of the user
* @param cacheMap the map of all caches needed
* @throws TimeoutException if the server could not be reached
* @throws IOException if the login credentials could not be written
* @throws InterruptedException if the current thread is interrupted while waiting for the
* handshake response
*/
public void performHandshake(LoginCredentials credentials, CacheMap cacheMap)
public void performHandshake(LoginCredentials credentials)
throws TimeoutException, IOException, InterruptedException {
if (online)
throw new IllegalStateException("Handshake has already been performed successfully");
@ -79,7 +78,6 @@ public final class Client implements EventListener, Closeable {
// Register user creation processor, contact list processor, message cache and
// authentication token
receiver.registerProcessor(User.class, sender -> this.sender = sender);
receiver.registerProcessors(cacheMap.getMap());
// Start receiver
receiver.start();
@ -101,42 +99,18 @@ public final class Client implements EventListener, Closeable {
if (System.currentTimeMillis() - start > 5000) {
rejected = true;
socket.close();
receiver.removeAllProcessors();
throw new TimeoutException("Did not log in after 5 seconds");
}
Thread.sleep(500);
}
online = true;
logger.log(Level.INFO, "Handshake completed.");
}
/**
* Initializes the {@link Receiver} used to process data sent from the server to this client.
*
* @param localDB the local database used to persist the current {@link IDGenerator}
* @param cacheMap the map of all caches needed
* @throws IOException if no {@link IDGenerator} is present and none could be requested from the
* server
* @since Envoy Client v0.2-alpha
*/
public void initReceiver(LocalDB localDB, CacheMap cacheMap) throws IOException {
checkOnline();
// Remove all processors as they are only used during the handshake
// Remove handshake specific processors
receiver.removeAllProcessors();
// Relay cached messages and message status changes
cacheMap.get(Message.class).setProcessor(eventBus::dispatch);
cacheMap.get(GroupMessage.class).setProcessor(eventBus::dispatch);
cacheMap.get(MessageStatusChange.class).setProcessor(eventBus::dispatch);
cacheMap.get(GroupMessageStatusChange.class).setProcessor(eventBus::dispatch);
// Request a generator if none is present or the existing one is consumed
if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext())
requestIDGenerator();
// Relay caches
cacheMap.getMap().values().forEach(Cache::relay);
online = true;
logger.log(Level.INFO, "Handshake completed.");
}
/**
@ -179,13 +153,15 @@ public final class Client implements EventListener, Closeable {
send(new IDGeneratorRequest());
}
@Event(eventType = HandshakeRejection.class, priority = 1000)
@Event(HandshakeRejection.class)
@Priority(1000)
private void onHandshakeRejection() {
rejected = true;
}
@Override
@Event(eventType = EnvoyCloseEvent.class, priority = 50)
@Event(EnvoyCloseEvent.class)
@Priority(50)
public void close() {
if (online) {
logger.log(Level.INFO, "Closing connection...");

20
client/src/main/java/envoy/client/net/Receiver.java

@ -6,7 +6,7 @@ import java.util.*;
import java.util.function.Consumer;
import java.util.logging.*;
import dev.kske.eventbus.*;
import dev.kske.eventbus.core.EventBus;
import envoy.util.*;
@ -87,15 +87,17 @@ public final class Receiver extends Thread {
// Dispatch to the processor if present
if (processor != null)
processor.accept(obj);
// Dispatch to the event bus if the object is an event without a processor
else if (obj instanceof IEvent)
eventBus.dispatch((IEvent) obj);
// Notify if no processor could be located
// Dispatch to the event bus if the object has no processor
else
logger.log(Level.WARNING,
String.format(
"The received object has the %s for which no processor is defined.",
obj.getClass()));
eventBus.dispatch(obj);
// TODO: Log DeadEvent from Event Bus 1.1.0
// Notify if no processor could be located
// else
// logger.log(Level.WARNING,
// String.format(
// "The received object has the %s for which no processor is defined.",
// obj.getClass()));
}
} catch (final SocketException | EOFException e) {
// Connection probably closed by client.

10
client/src/main/java/envoy/client/ui/SceneContext.java

@ -8,7 +8,7 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;
import dev.kske.eventbus.*;
import dev.kske.eventbus.core.*;
import envoy.util.EnvoyLog;
@ -25,7 +25,7 @@ import envoy.client.event.*;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public final class SceneContext implements EventListener {
public final class SceneContext {
private final Stage stage;
private final Stack<Parent> roots = new Stack<>();
@ -126,13 +126,15 @@ public final class SceneContext implements EventListener {
}
}
@Event(eventType = Logout.class, priority = 150)
@Event(Logout.class)
@Priority(150)
private void onLogout() {
roots.clear();
controllers.clear();
}
@Event(priority = 150, eventType = ThemeChangeEvent.class)
@Event(ThemeChangeEvent.class)
@Priority(150)
private void onThemeChange() {
applyCSS();
}

15
client/src/main/java/envoy/client/ui/Startup.java

@ -12,7 +12,7 @@ import javafx.stage.Stage;
import envoy.data.*;
import envoy.data.User.UserStatus;
import envoy.event.*;
import envoy.event.UserStatusChange;
import envoy.exception.EnvoyException;
import envoy.util.EnvoyLog;
@ -115,21 +115,20 @@ public final class Startup extends Application {
* @since Envoy Client v0.2-beta
*/
public static boolean performHandshake(LoginCredentials credentials) {
final var cacheMap = new CacheMap();
cacheMap.put(Message.class, new Cache<Message>());
cacheMap.put(GroupMessage.class, new Cache<GroupMessage>());
cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>());
cacheMap.put(GroupMessageStatusChange.class, new Cache<GroupMessageStatusChange>());
final var originalStatus =
localDB.getUser() == null ? UserStatus.ONLINE : localDB.getUser().getStatus();
try {
client.performHandshake(credentials, cacheMap);
client.performHandshake(credentials);
if (client.isOnline()) {
// Restore the original status as the server automatically returns status ONLINE
client.getSender().setStatus(originalStatus);
loadChatScene();
client.initReceiver(localDB, cacheMap);
// Request an ID generator if none is present or the existing one is consumed
if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext())
client.requestIDGenerator();
return true;
} else
return false;

8
client/src/main/java/envoy/client/ui/StatusTrayIcon.java

@ -9,8 +9,8 @@ import java.awt.image.BufferedImage;
import javafx.application.Platform;
import javafx.stage.Stage;
import dev.kske.eventbus.*;
import dev.kske.eventbus.Event;
import dev.kske.eventbus.core.Event;
import dev.kske.eventbus.core.EventBus;
import envoy.data.Message;
import envoy.data.User.UserStatus;
@ -31,7 +31,7 @@ import envoy.client.util.*;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.2-alpha
*/
public final class StatusTrayIcon implements EventListener {
public final class StatusTrayIcon {
/**
* The {@link TrayIcon} provided by the System Tray API for controlling the system tray. This
@ -136,7 +136,7 @@ public final class StatusTrayIcon implements EventListener {
*
* @since Envoy Client v0.2-beta
*/
@Event(eventType = Logout.class)
@Event(Logout.class)
public void hide() {
SystemTray.getSystemTray().remove(trayIcon);
}

30
client/src/main/java/envoy/client/ui/controller/ChatScene.java

@ -21,14 +21,14 @@ import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.FileChooser;
import javafx.util.Duration;
import dev.kske.eventbus.*;
import dev.kske.eventbus.Event;
import dev.kske.eventbus.core.*;
import dev.kske.eventbus.core.Event;
import envoy.data.*;
import envoy.data.Attachment.AttachmentType;
@ -55,7 +55,7 @@ import envoy.client.util.*;
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public final class ChatScene implements EventListener, Restorable, KeyboardMapping {
public final class ChatScene implements Restorable, KeyboardMapping {
@FXML
private ListView<Message> messageList;
@ -220,12 +220,13 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
});
}
@Event(eventType = BackEvent.class)
@Event(BackEvent.class)
private void onBackEvent() {
tabPane.getSelectionModel().select(Tabs.CONTACT_LIST.ordinal());
}
@Event(includeSubtypes = true)
@Event
@Polymorphic
private void onMessage(Message message) {
// The sender of the message is the recipient of the chat
@ -304,7 +305,7 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
}));
}
@Event(eventType = NoAttachments.class)
@Event(NoAttachments.class)
private void onNoAttachments() {
Platform.runLater(() -> {
attachmentButton.setDisable(true);
@ -317,12 +318,13 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
});
}
@Event(priority = 150)
@Event
@Priority(150)
private void onGroupCreationResult(GroupCreationResult result) {
Platform.runLater(() -> newGroupButton.setDisable(result.get() == null));
}
@Event(eventType = ThemeChangeEvent.class)
@Event(ThemeChangeEvent.class)
private void onThemeChange() {
ChatControl.reloadDefaultChatIcons();
settingsButton.setGraphic(
@ -346,12 +348,13 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
}
@Event(eventType = Logout.class, priority = 200)
@Event(Logout.class)
@Priority(200)
private void onLogout() {
eventBus.removeListener(this);
}
@Event(eventType = AccountDeletion.class)
@Event(AccountDeletion.class)
private void onAccountDeletion() {
Platform.runLater(chatList::refresh);
}
@ -783,7 +786,8 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
attachmentView.setVisible(visible);
}
@Event(eventType = OwnStatusChange.class, priority = 50)
@Event(OwnStatusChange.class)
@Priority(50)
private void generateOwnStatusControl() {
// Update the own user status if present
@ -794,7 +798,7 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
// Else prepend it to the HBox children
final var ownUserControl = new ContactControl(localDB.getUser());
ownUserControl.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(ownUserControl, Priority.NEVER);
HBox.setHgrow(ownUserControl, javafx.scene.layout.Priority.NEVER);
ownContactControl.getChildren().add(1, ownUserControl);
}
}

4
client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java

@ -7,7 +7,7 @@ import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import dev.kske.eventbus.*;
import dev.kske.eventbus.core.*;
import envoy.data.User;
import envoy.event.ElementOperation;
@ -34,7 +34,7 @@ import envoy.client.ui.listcell.ListCellFactory;
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public class ContactSearchTab implements EventListener {
public class ContactSearchTab {
@FXML
private TextArea searchBar;

6
client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java

@ -10,11 +10,11 @@ import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import dev.kske.eventbus.*;
import dev.kske.eventbus.core.*;
import envoy.data.*;
import envoy.event.GroupCreation;
import envoy.event.contact.*;
import envoy.event.contact.UserOperation;
import envoy.util.Bounds;
import envoy.client.data.*;
@ -33,7 +33,7 @@ import envoy.client.ui.listcell.ListCellFactory;
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public class GroupCreationTab implements EventListener {
public class GroupCreationTab {
@FXML
private Button createButton;

4
client/src/main/java/envoy/client/ui/controller/LoginScene.java

@ -10,7 +10,7 @@ import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.ImageView;
import dev.kske.eventbus.*;
import dev.kske.eventbus.core.*;
import envoy.data.LoginCredentials;
import envoy.event.HandshakeRejection;
@ -27,7 +27,7 @@ import envoy.client.util.IconUtil;
* @author Maximilian K&auml;fer
* @since Envoy Client v0.1-beta
*/
public final class LoginScene implements EventListener {
public final class LoginScene {
@FXML
private TextField userTextField;

2
client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java

@ -2,7 +2,7 @@ package envoy.client.ui.settings;
import javafx.scene.control.*;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.core.EventBus;
import envoy.data.User.UserStatus;

2
client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java

@ -15,7 +15,7 @@ import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.util.Duration;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.core.EventBus;
import envoy.event.*;
import envoy.util.*;

2
client/src/main/java/envoy/client/util/MessageUtil.java

@ -7,7 +7,7 @@ import java.util.logging.*;
import javafx.stage.FileChooser;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.core.EventBus;
import envoy.data.Message;
import envoy.util.EnvoyLog;

2
client/src/main/java/envoy/client/util/UserUtil.java

@ -5,7 +5,7 @@ import java.util.logging.*;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import dev.kske.eventbus.EventBus;
import dev.kske.eventbus.core.EventBus;
import envoy.data.*;
import envoy.data.User.UserStatus;

11
client/src/main/java/module-info.java

@ -16,12 +16,13 @@ module envoy.client {
requires javafx.fxml;
requires javafx.base;
requires javafx.graphics;
requires dev.kske.eventbus.core;
opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus;
opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus;
opens envoy.client.ui.chatscene to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus;
opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus.core;
opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus.core;
opens envoy.client.ui.chatscene to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus.core;
opens envoy.client.ui.control to javafx.graphics, javafx.fxml;
opens envoy.client.ui.settings to envoy.client.util;
opens envoy.client.net to dev.kske.eventbus;
opens envoy.client.data to dev.kske.eventbus;
opens envoy.client.net to dev.kske.eventbus.core;
opens envoy.client.data to dev.kske.eventbus.core;
}

11
common/pom.xml

@ -12,18 +12,11 @@
<version>0.2-beta</version>
</parent>
<repositories>
<repository>
<id>kske-repo</id>
<url>https://kske.dev/maven-repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>dev.kske</groupId>
<artifactId>event-bus</artifactId>
<version>0.0.4</version>
<artifactId>event-bus-core</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>

4
common/src/main/java/envoy/data/IDGenerator.java

@ -2,15 +2,13 @@ package envoy.data;
import java.io.Serializable;
import dev.kske.eventbus.IEvent;
/**
* Generates increasing IDs between two numbers.
*
* @author Kai S. K. Engelbart
* @since Envoy Common v0.2-alpha
*/
public final class IDGenerator implements IEvent, Serializable {
public final class IDGenerator implements Serializable {
private final long end;
private long current;

4
common/src/main/java/envoy/data/Message.java

@ -4,8 +4,6 @@ import java.io.Serializable;
import java.time.Instant;
import java.util.Objects;
import dev.kske.eventbus.IEvent;
/**
* Represents a unique message with a unique, numeric ID. Further metadata includes the sender and
* recipient {@link User}s, as well as the creation date and the current {@link MessageStatus}.<br>
@ -14,7 +12,7 @@ import dev.kske.eventbus.IEvent;
* @author Leon Hofmeister
* @since Envoy Common v0.2-alpha
*/
public class Message implements Serializable, IEvent {
public class Message implements Serializable {
/**
* This enumeration defines all possible statuses a {link Message} can have.

9
common/src/main/java/envoy/event/Event.java

@ -3,18 +3,15 @@ package envoy.event;
import java.io.Serializable;
import java.util.Objects;
import dev.kske.eventbus.IEvent;
/**
* This class serves as a convenience base class for all events. It implements the {@link IEvent}
* interface and provides a generic value. For events without a value there also is
* {@link envoy.event.Event.Valueless}.
* This class serves as a convenience base class for all events. It provides a generic value. For
* events without a value there also is {@link envoy.event.Event.Valueless}.
*
* @author Kai S. K. Engelbart
* @param <T> the type of the Event
* @since Envoy v0.2-alpha
*/
public abstract class Event<T> implements IEvent, Serializable {
public abstract class Event<T> implements Serializable {
protected final T value;

2
common/src/main/java/module-info.java

@ -16,5 +16,5 @@ module envoy.common {
exports envoy.event.contact;
requires transitive java.logging;
requires transitive dev.kske.eventbus;
requires transitive dev.kske.eventbus.core;
}

4
common/src/test/java/envoy/data/UserTest.java

@ -18,10 +18,10 @@ import envoy.util.SerializationUtils;
* @author Leon Hofmeister
* @since Envoy Common v0.1-beta
*/
class UserTest {
public class UserTest {
@Test
void test() throws IOException, ClassNotFoundException {
public void test() throws IOException, ClassNotFoundException {
User user2 = new User(2, "kai");
User user3 = new User(3, "ai");
User user4 = new User(4, "ki", Set.of(user2, user3));

7
pom.xml

@ -28,6 +28,13 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
<modules>

31
server/src/main/java/envoy/server/processors/LoginCredentialProcessor.java

@ -40,6 +40,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
// Cache this write proxy for user-independent notifications
UserStatusChangeProcessor.setWriteProxy(writeProxy);
// Check for compatible versions
if (!VersionUtil.verifyCompatibility(credentials.getClientVersion())) {
logger.info("The client has the wrong version.");
writeProxy.write(socketID, new HandshakeRejection(WRONG_VERSION));
@ -70,10 +71,10 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
writeProxy.write(socketID, new HandshakeRejection(INVALID_TOKEN));
return;
}
} else
} else if (!PasswordUtil.validate(credentials.getPassword(),
user.getPasswordHash())) {
// Check the password hash
if (!PasswordUtil.validate(credentials.getPassword(), user.getPasswordHash())) {
// Check the password hash
logger.info(user + " has entered the wrong password.");
writeProxy.write(socketID, new HandshakeRejection(WRONG_PASSWORD_OR_USER));
return;
@ -101,7 +102,8 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
writeProxy.write(socketID, new HandshakeRejection(USERNAME_TAKEN));
return;
} catch (final NoResultException e) {
// Creation of a new user
// Create a new user
user = new User();
user.setName(credentials.getIdentifier());
user.setLastSeen(Instant.now());
@ -138,6 +140,15 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
persistenceManager.updateContact(user);
writeProxy.write(socketID, new NewAuthToken(token));
}
// Notify the user if a contact deletion has happened since he last logged in
if (user.getLatestContactDeletion().isAfter(user.getLastSeen()))
writeProxy.write(socketID, new ContactsChangedSinceLastLogin());
// Complete the handshake
writeProxy.write(socketID, user.toCommon());
// Send pending (group) messages and status changes
final var pendingMessages =
PersistenceManager.getInstance().getPendingMessages(user, credentials.getLastSync());
pendingMessages.removeIf(GroupMessage.class::isInstance);
@ -162,8 +173,9 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
writeProxy.write(connectionManager.getSocketID(msg.getSender().getID()),
new MessageStatusChange(msgCommon));
}
} else
} else {
writeProxy.write(socketID, new MessageStatusChange(msgCommon));
}
}
final List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance()
@ -197,10 +209,11 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
}
PersistenceManager.getInstance().updateMessage(gmsg);
} else
} else {
// Just send the message without updating if it was received in the past
writeProxy.write(socketID, gmsgCommon);
}
} else {
// Sending group message status changes
@ -220,11 +233,5 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
writeProxy.write(socketID, new MessageStatusChange(gmsgCommon));
}
}
// Notify the user if a contact deletion has happened since he last logged in
if (user.getLatestContactDeletion().isAfter(user.getLastSeen()))
writeProxy.write(socketID, new ContactsChangedSinceLastLogin());
// Complete the handshake
writeProxy.write(socketID, user.toCommon());
}
}