Packet, Auth reworks & Messages
This commit is contained in:
parent
22ee07a5b3
commit
0b1270a916
@ -4,10 +4,7 @@ import dev.wiing.gossip.lib.PacketHandler;
|
|||||||
import dev.wiing.gossip.lib.PacketManager;
|
import dev.wiing.gossip.lib.PacketManager;
|
||||||
import dev.wiing.gossip.lib.models.SecretUser;
|
import dev.wiing.gossip.lib.models.SecretUser;
|
||||||
import dev.wiing.gossip.lib.models.User;
|
import dev.wiing.gossip.lib.models.User;
|
||||||
import dev.wiing.gossip.lib.packets.FetchUserPacket;
|
import dev.wiing.gossip.lib.packets.*;
|
||||||
import dev.wiing.gossip.lib.packets.Packet;
|
|
||||||
import dev.wiing.gossip.lib.packets.UserDataPacket;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@ -58,10 +55,22 @@ public class Connection {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
Packet packet = connection.nextPacket();
|
Packet packet;
|
||||||
connection.getPacketHandler().runPacket(packet);
|
if (connection.getSocket().getInputStream().available() > 0 || connection.queuedPackets.isEmpty()) {
|
||||||
|
packet = connection.nextPacket(false);
|
||||||
|
} else {
|
||||||
|
packet = connection.findPacketOfTypes(connection.packetHandler.getListeningTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet == null) continue;
|
||||||
|
|
||||||
|
if (!connection.getPacketHandler().runPacket(packet)) {
|
||||||
|
connection.queuedPackets.add(packet);
|
||||||
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
break;
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,8 +97,13 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendPacketAuthenticated(AuthRequiredPacket packet) {
|
||||||
|
packet.setAuth(getSelf().getUserSecret());
|
||||||
|
sendPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
public Packet nextPacket(boolean useQueue) throws SocketException {
|
public Packet nextPacket(boolean useQueue) throws SocketException {
|
||||||
if (!queuedPackets.isEmpty()) {
|
if (useQueue && !queuedPackets.isEmpty()) {
|
||||||
return queuedPackets.remove(0);
|
return queuedPackets.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +134,56 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Packet findPacketOfTypes(List<Short> types) {
|
||||||
|
Packet packet = null;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < queuedPackets.size(); i++) {
|
||||||
|
Packet queuedPacket = queuedPackets.get(i);
|
||||||
|
|
||||||
|
if (types.contains(queuedPacket.getType())) {
|
||||||
|
packet = queuedPacket;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet != null) {
|
||||||
|
queuedPackets.remove(i);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean findAck(short acknowledgement) throws IOException {
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (socket.getInputStream().available() > 0);
|
||||||
|
|
||||||
|
AckPacket ack = null;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < queuedPackets.size(); i++) {
|
||||||
|
Packet queuedPacket = queuedPackets.get(i);
|
||||||
|
|
||||||
|
if (queuedPacket.getType() == AckPacket.TYPE) {
|
||||||
|
ack = (AckPacket) queuedPacket;
|
||||||
|
|
||||||
|
if (ack.getAcknowledgement() == acknowledgement) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ack = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack != null) {
|
||||||
|
queuedPackets.remove(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SecretUser getSelf() {
|
public SecretUser getSelf() {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -143,7 +207,7 @@ public class Connection {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchUserPacket fetch = new FetchUserPacket();
|
UserFetchPacket fetch = new UserFetchPacket();
|
||||||
fetch.setUserID(userID);
|
fetch.setUserID(userID);
|
||||||
Connection.getInstance().sendPacket(fetch);
|
Connection.getInstance().sendPacket(fetch);
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,11 @@ import java.io.IOException;
|
|||||||
public class GossipApp extends Application {
|
public class GossipApp extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
|
System.setProperty("prism.lcdtext", "false");
|
||||||
|
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(Program.class.getResource("views/login-view.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(Program.class.getResource("views/login-view.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
|
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
|
||||||
|
|
||||||
stage.setTitle("GossipApp");
|
stage.setTitle("GossipApp");
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|||||||
@ -4,9 +4,9 @@ package dev.wiing.gossip.client.controllers;
|
|||||||
import dev.wiing.gossip.client.Connection;
|
import dev.wiing.gossip.client.Connection;
|
||||||
import dev.wiing.gossip.client.data.UserAvatar;
|
import dev.wiing.gossip.client.data.UserAvatar;
|
||||||
import dev.wiing.gossip.lib.models.SecretUser;
|
import dev.wiing.gossip.lib.models.SecretUser;
|
||||||
import dev.wiing.gossip.lib.packets.CredentialsPacket;
|
import dev.wiing.gossip.lib.packets.RegisterCredentialsPacket;
|
||||||
import dev.wiing.gossip.lib.packets.Packet;
|
import dev.wiing.gossip.lib.packets.Packet;
|
||||||
import dev.wiing.gossip.lib.packets.RegisterPacket;
|
import dev.wiing.gossip.lib.packets.RegisterRequestPacket;
|
||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.Event;
|
import javafx.event.Event;
|
||||||
@ -51,7 +51,7 @@ public class LoginController implements Initializable {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void onLogin(ActionEvent event) {
|
public void onLogin(ActionEvent event) {
|
||||||
RegisterPacket packet = new RegisterPacket();
|
RegisterRequestPacket packet = new RegisterRequestPacket();
|
||||||
packet.setAvatarID((byte)0);
|
packet.setAvatarID((byte)0);
|
||||||
packet.setUsername(txtUsername.getText());
|
packet.setUsername(txtUsername.getText());
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ public class LoginController implements Initializable {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != null && result.getType() == CredentialsPacket.TYPE) {
|
if (result != null && result.getType() == RegisterCredentialsPacket.TYPE) {
|
||||||
CredentialsPacket creds = (CredentialsPacket)result;
|
RegisterCredentialsPacket creds = (RegisterCredentialsPacket)result;
|
||||||
|
|
||||||
SecretUser user = new SecretUser(packet.getUsername(), packet.getAvatarID(), creds.getUID(), creds.getSecret());
|
SecretUser user = new SecretUser(packet.getUsername(), packet.getAvatarID(), creds.getUID(), creds.getSecret());
|
||||||
Connection.getInstance().setSelf(user);
|
Connection.getInstance().setSelf(user);
|
||||||
|
|||||||
@ -1,27 +1,33 @@
|
|||||||
package dev.wiing.gossip.client.controllers;
|
package dev.wiing.gossip.client.controllers;
|
||||||
|
|
||||||
import dev.wiing.gossip.client.Connection;
|
import dev.wiing.gossip.client.Connection;
|
||||||
|
import dev.wiing.gossip.client.controllers.item.MessageItemController;
|
||||||
import dev.wiing.gossip.client.generic.Pair;
|
import dev.wiing.gossip.client.generic.Pair;
|
||||||
import dev.wiing.gossip.client.utils.Utils;
|
import dev.wiing.gossip.client.utils.Utils;
|
||||||
|
import dev.wiing.gossip.lib.models.Message;
|
||||||
import dev.wiing.gossip.lib.models.Topic;
|
import dev.wiing.gossip.lib.models.Topic;
|
||||||
import dev.wiing.gossip.lib.models.User;
|
import dev.wiing.gossip.lib.packets.MessagePushPacket;
|
||||||
|
import dev.wiing.gossip.lib.packets.TopicJoinPacket;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
public class MainChatController {
|
public class MainChatController {
|
||||||
|
|
||||||
private Topic topic;
|
private Topic topic;
|
||||||
|
|
||||||
|
private final List<MessageItemController> messageItems = new ArrayList<>();
|
||||||
|
private MessageItemController latestMessageItem = null;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label lblBabblersCount;
|
private Label lblBabblersCount;
|
||||||
|
|
||||||
@ -68,7 +74,15 @@ public class MainChatController {
|
|||||||
|
|
||||||
this.topic.addChangeListener(evt -> {
|
this.topic.addChangeListener(evt -> {
|
||||||
if (evt.getPropertyName().equals("userAdd") || evt.getPropertyName().equals("userRemove")) {
|
if (evt.getPropertyName().equals("userAdd") || evt.getPropertyName().equals("userRemove")) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
setBabblerCount(topic.getUsersReadOnly().size());
|
setBabblerCount(topic.getUsersReadOnly().size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.getPropertyName().equals("messageAdd")) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
addMessage((Message)evt.getNewValue());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -78,6 +92,10 @@ public class MainChatController {
|
|||||||
lblVisitTopicName.setText(name);
|
lblVisitTopicName.setText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Topic getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
private void setBabblerCount(int count) {
|
private void setBabblerCount(int count) {
|
||||||
String res = "No Babblers";
|
String res = "No Babblers";
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
@ -95,20 +113,59 @@ public class MainChatController {
|
|||||||
vboxVisitPage.setVisible(!participating);
|
vboxVisitPage.setVisible(!participating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addMessage(Message message) {
|
||||||
|
if (latestMessageItem == null || latestMessageItem.getAuthor().getUserID() != message.getAuthor().getUserID()) {
|
||||||
|
var newPair = MessageItemController.createInstance();
|
||||||
|
|
||||||
|
newPair.second().setAuthor(message.getAuthor());
|
||||||
|
|
||||||
|
vboxMessages.getChildren().add(newPair.first());
|
||||||
|
|
||||||
|
latestMessageItem = newPair.second();
|
||||||
|
}
|
||||||
|
|
||||||
|
latestMessageItem.addMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void onJoinTopic(ActionEvent event) {
|
void onJoinTopic(ActionEvent event) {
|
||||||
topic.addUser(Connection.getInstance().getSelf());
|
TopicJoinPacket packet = new TopicJoinPacket();
|
||||||
|
packet.setTopicID(topic.getId());
|
||||||
|
|
||||||
|
Connection.getInstance().sendPacketAuthenticated(packet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Connection.getInstance().findAck(TopicJoinPacket.TYPE);
|
||||||
|
|
||||||
togglePages(true);
|
togglePages(true);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void onSend(MouseEvent event) {
|
void onSend(MouseEvent event) {
|
||||||
|
String messageContents = txtCompose.getText();
|
||||||
|
|
||||||
|
txtCompose.clear();
|
||||||
|
|
||||||
|
MessagePushPacket packet = new MessagePushPacket();
|
||||||
|
packet.setTopicID(topic.getId());
|
||||||
|
packet.setMessage(messageContents);
|
||||||
|
|
||||||
|
Connection.getInstance().sendPacketAuthenticated(packet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Connection.getInstance().findAck(MessagePushPacket.TYPE);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<Parent, MainChatController> createInstance() {
|
public static Pair<Parent, MainChatController> createInstance() {
|
||||||
return Utils.createInstance("views/main-chat-view.fxml");
|
return Utils.createInstance("views/chat-view.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package dev.wiing.gossip.client.controllers;
|
package dev.wiing.gossip.client.controllers;
|
||||||
|
|
||||||
import dev.wiing.gossip.client.Connection;
|
import dev.wiing.gossip.client.Connection;
|
||||||
import dev.wiing.gossip.client.controllers.item.MainTopicItemController;
|
import dev.wiing.gossip.client.controllers.item.TopicItemController;
|
||||||
import dev.wiing.gossip.client.data.UserAvatar;
|
import dev.wiing.gossip.client.data.UserAvatar;
|
||||||
import dev.wiing.gossip.client.generic.Pair;
|
import dev.wiing.gossip.client.generic.Pair;
|
||||||
import dev.wiing.gossip.client.utils.Utils;
|
import dev.wiing.gossip.client.utils.Utils;
|
||||||
|
import dev.wiing.gossip.lib.data.LongData;
|
||||||
|
import dev.wiing.gossip.lib.models.Message;
|
||||||
import dev.wiing.gossip.lib.models.Topic;
|
import dev.wiing.gossip.lib.models.Topic;
|
||||||
import dev.wiing.gossip.lib.models.User;
|
import dev.wiing.gossip.lib.models.User;
|
||||||
import dev.wiing.gossip.lib.packets.*;
|
import dev.wiing.gossip.lib.packets.*;
|
||||||
@ -27,7 +29,7 @@ public class MainController implements Initializable {
|
|||||||
|
|
||||||
Topic activeTopic = null;
|
Topic activeTopic = null;
|
||||||
Parent activeTopicElement = null;
|
Parent activeTopicElement = null;
|
||||||
private final Map<Long, Parent> topicContentMap = new ConcurrentHashMap<>();
|
private final Map<Long, Pair<Parent, MainChatController>> topicMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private VBox vboxRoot;
|
private VBox vboxRoot;
|
||||||
@ -54,7 +56,7 @@ public class MainController implements Initializable {
|
|||||||
|
|
||||||
UserAvatar.getAvatar(user.getAvatarID()).applyToRegionBackground(paneIcon, true);
|
UserAvatar.getAvatar(user.getAvatarID()).applyToRegionBackground(paneIcon, true);
|
||||||
|
|
||||||
Connection.getInstance().getPacketHandler().addListener(TopicAddedPacket.class, packet -> {
|
Connection.getInstance().getPacketHandler().addListener(TopicCreatedPacket.class, packet -> {
|
||||||
User host = Connection.getInstance().getUser(packet.getHostID());
|
User host = Connection.getInstance().getUser(packet.getHostID());
|
||||||
|
|
||||||
Topic topic = new Topic(
|
Topic topic = new Topic(
|
||||||
@ -65,13 +67,13 @@ public class MainController implements Initializable {
|
|||||||
packet.getTopicColor()
|
packet.getTopicColor()
|
||||||
);
|
);
|
||||||
|
|
||||||
var pair = MainTopicItemController.createInstance();
|
var pair = TopicItemController.createInstance();
|
||||||
pair.second().setTopic(topic);
|
pair.second().setTopic(topic);
|
||||||
|
|
||||||
var contentPair = MainChatController.createInstance();
|
var contentPair = MainChatController.createInstance();
|
||||||
contentPair.second().setTopic(topic);
|
contentPair.second().setTopic(topic);
|
||||||
|
|
||||||
topicContentMap.put(topic.getId(), contentPair.first());
|
topicMap.put(topic.getId(), contentPair);
|
||||||
|
|
||||||
AnchorPane.setLeftAnchor(contentPair.first(), 0.0);
|
AnchorPane.setLeftAnchor(contentPair.first(), 0.0);
|
||||||
AnchorPane.setBottomAnchor(contentPair.first(), 0.0);
|
AnchorPane.setBottomAnchor(contentPair.first(), 0.0);
|
||||||
@ -90,6 +92,41 @@ public class MainController implements Initializable {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Connection.getInstance().getPacketHandler().addListener(TopicUpdatePacket.class, packet -> {
|
||||||
|
if (!topicMap.containsKey(packet.getTopicID())) return;
|
||||||
|
|
||||||
|
Topic topic = topicMap.get(packet.getTopicID()).second().getTopic();
|
||||||
|
|
||||||
|
if (packet.isTopicNameModified()) topic.setName(packet.getTopicName());
|
||||||
|
if (packet.isTopicDescriptionModified()) topic.setDescription(packet.getTopicDescription());
|
||||||
|
|
||||||
|
if (packet.haveUsersJoined()) {
|
||||||
|
for (LongData userID : packet.getUsersJoined()) {
|
||||||
|
User userJoined = Connection.getInstance().getUser(userID.getValue());
|
||||||
|
topic.addUser(userJoined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet.haveUsersLeft()) {
|
||||||
|
for (LongData userID : packet.getUsersLeft()) {
|
||||||
|
User userJoined = Connection.getInstance().getUser(userID.getValue());
|
||||||
|
topic.removeUser(userJoined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Connection.getInstance().getPacketHandler().addListener(MessageCreatedPacket.class, packet -> {
|
||||||
|
if (!topicMap.containsKey(packet.getTopicID())) return;
|
||||||
|
|
||||||
|
Topic topic = topicMap.get(packet.getTopicID()).second().getTopic();
|
||||||
|
|
||||||
|
User author = Connection.getInstance().getUser(packet.getAuthorID());
|
||||||
|
|
||||||
|
Message message = new Message(author, topic, packet.getContents());
|
||||||
|
|
||||||
|
topic.addMessage(message);
|
||||||
|
});
|
||||||
|
|
||||||
Connection.getInstance().beginHandlingPackets();
|
Connection.getInstance().beginHandlingPackets();
|
||||||
|
|
||||||
vboxTopics.getChildren().clear();
|
vboxTopics.getChildren().clear();
|
||||||
@ -98,7 +135,7 @@ public class MainController implements Initializable {
|
|||||||
public void setActiveTopic(Topic topic, Parent element) {
|
public void setActiveTopic(Topic topic, Parent element) {
|
||||||
if (activeTopic != null) {
|
if (activeTopic != null) {
|
||||||
activeTopicElement.getStyleClass().remove("tag-min");
|
activeTopicElement.getStyleClass().remove("tag-min");
|
||||||
topicContentMap.get(activeTopic.getId()).setVisible(false);
|
topicMap.get(activeTopic.getId()).first().setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
lblJoinMessage.setVisible(false);
|
lblJoinMessage.setVisible(false);
|
||||||
}
|
}
|
||||||
@ -120,13 +157,13 @@ public class MainController implements Initializable {
|
|||||||
activeTopic = topic;
|
activeTopic = topic;
|
||||||
activeTopicElement = element;
|
activeTopicElement = element;
|
||||||
|
|
||||||
topicContentMap.get(activeTopic.getId()).setVisible(true);
|
topicMap.get(activeTopic.getId()).first().setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void onCreateTopic(ActionEvent event) {
|
void onCreateTopic(ActionEvent event) {
|
||||||
CreateTopicPacket packet = new CreateTopicPacket();
|
TopicPushPacket packet = new TopicPushPacket();
|
||||||
packet.setUserSecret(Connection.getInstance().getSelf().getUserSecret());
|
packet.setAuth(Connection.getInstance().getSelf().getUserSecret());
|
||||||
packet.setTopicName("Point Nemo");
|
packet.setTopicName("Point Nemo");
|
||||||
packet.setTopicDescription("We are so gone XDD");
|
packet.setTopicDescription("We are so gone XDD");
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
package dev.wiing.gossip.client.controllers.item;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.client.Connection;
|
||||||
|
import dev.wiing.gossip.client.data.UserAvatar;
|
||||||
|
import dev.wiing.gossip.client.generic.Pair;
|
||||||
|
import dev.wiing.gossip.client.utils.Utils;
|
||||||
|
import dev.wiing.gossip.lib.models.Message;
|
||||||
|
import dev.wiing.gossip.lib.models.User;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
public class MessageItemController implements Initializable {
|
||||||
|
|
||||||
|
private User author;
|
||||||
|
private final List<Message> messages = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label lblAuthor;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label lblTag;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label lblTimeAgo;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Pane paneIcon;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private VBox vboxMessages;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
vboxMessages.getChildren().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(User author) {
|
||||||
|
this.author = author;
|
||||||
|
|
||||||
|
this.lblAuthor.setText(author.getUsernameDisplay());
|
||||||
|
|
||||||
|
if (this.author.getUserID() == Connection.getInstance().getSelf().getUserID()) {
|
||||||
|
this.lblTag.setVisible(true);
|
||||||
|
this.lblTag.setText("You");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserAvatar.getAvatar(this.author.getAvatarID()).applyToRegionBackground(paneIcon, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessage(Message message) {
|
||||||
|
if (message.getAuthor() != author) return;
|
||||||
|
|
||||||
|
if (!this.lblTag.isVisible() && messages.isEmpty() && message.getTopic().getHost().getUserID() == message.getAuthor().getUserID()) {
|
||||||
|
this.lblTag.setVisible(true);
|
||||||
|
this.lblTag.setText("Host");
|
||||||
|
this.lblTag.getStyleClass().add("secondary");
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(message);
|
||||||
|
|
||||||
|
Label label = new Label(message.getContents());
|
||||||
|
|
||||||
|
vboxMessages.getChildren().add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Message> getMessageReadOnly() {
|
||||||
|
return Collections.unmodifiableList(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<Parent, MessageItemController> createInstance() {
|
||||||
|
return Utils.createInstance("views/message-item.fxml");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,7 +3,6 @@ package dev.wiing.gossip.client.controllers.item;
|
|||||||
import dev.wiing.gossip.client.generic.Pair;
|
import dev.wiing.gossip.client.generic.Pair;
|
||||||
import dev.wiing.gossip.client.utils.Utils;
|
import dev.wiing.gossip.client.utils.Utils;
|
||||||
import dev.wiing.gossip.lib.models.Topic;
|
import dev.wiing.gossip.lib.models.Topic;
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
@ -11,7 +10,7 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
|
||||||
public class MainTopicItemController {
|
public class TopicItemController {
|
||||||
|
|
||||||
private Topic topic;
|
private Topic topic;
|
||||||
|
|
||||||
@ -30,8 +29,8 @@ public class MainTopicItemController {
|
|||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<Parent, MainTopicItemController> createInstance() {
|
public static Pair<Parent, TopicItemController> createInstance() {
|
||||||
return Utils.createInstance("views/main-topic-item.fxml");
|
return Utils.createInstance("views/topic-item.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnMouseClicked(EventHandler<MouseEvent> eventHandler) {
|
public void setOnMouseClicked(EventHandler<MouseEvent> eventHandler) {
|
||||||
@ -151,7 +151,7 @@ Label.tag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label.tag.small {
|
Label.tag.small {
|
||||||
-fx-background-color: -color;
|
-fx-background-color: ladder(hsb(0, 0%, 30%), -color, #0000);
|
||||||
-fx-background-radius: 4px;
|
-fx-background-radius: 4px;
|
||||||
-fx-border-width: 0;
|
-fx-border-width: 0;
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
@ -159,6 +159,10 @@ Label.tag.small {
|
|||||||
-fx-padding: 2px 8px;
|
-fx-padding: 2px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag.secondary {
|
||||||
|
-color: #4a4a55;
|
||||||
|
}
|
||||||
|
|
||||||
CheckBox .box {
|
CheckBox .box {
|
||||||
-fx-background-color: #25252c;
|
-fx-background-color: #25252c;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,7 @@
|
|||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.shape.Circle?>
|
<?import javafx.scene.shape.Circle?>
|
||||||
|
|
||||||
|
<AnchorPane prefHeight="318.0" prefWidth="523.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.MainChatController">
|
||||||
<AnchorPane xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.MainChatController">
|
|
||||||
<children>
|
<children>
|
||||||
<VBox fx:id="vboxVisitPage" alignment="CENTER" layoutX="10.0" layoutY="10.0" spacing="8.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<VBox fx:id="vboxVisitPage" alignment="CENTER" layoutX="10.0" layoutY="10.0" spacing="8.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
<children>
|
<children>
|
||||||
@ -57,7 +56,7 @@
|
|||||||
<Label fx:id="lblBabblersCount" alignment="CENTER_RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 12;" styleClass="faint" text="2 babblers" HBox.hgrow="ALWAYS" />
|
<Label fx:id="lblBabblersCount" alignment="CENTER_RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 12;" styleClass="faint" text="2 babblers" HBox.hgrow="ALWAYS" />
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
|
<ScrollPane fitToWidth="true" hbarPolicy="NEVER" VBox.vgrow="ALWAYS">
|
||||||
<content>
|
<content>
|
||||||
<VBox fx:id="vboxMessages" spacing="16.0">
|
<VBox fx:id="vboxMessages" spacing="16.0">
|
||||||
<children>
|
<children>
|
||||||
@ -126,6 +125,12 @@
|
|||||||
<String fx:value="container" />
|
<String fx:value="container" />
|
||||||
<String fx:value="list" />
|
<String fx:value="list" />
|
||||||
</styleClass>
|
</styleClass>
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
<padding>
|
||||||
|
<Insets right="4.0" />
|
||||||
|
</padding>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
<VBox spacing="8.0">
|
<VBox spacing="8.0">
|
||||||
<children>
|
<children>
|
||||||
@ -141,7 +146,7 @@
|
|||||||
<String fx:value="list" />
|
<String fx:value="list" />
|
||||||
</styleClass>
|
</styleClass>
|
||||||
<children>
|
<children>
|
||||||
<TextArea fx:id="txtCompose" maxHeight="1.7976931348623157E308" minHeight="1.0" prefHeight="24.0" prefRowCount="1" promptText="Compose..." styleClass="transparent" wrapText="true" HBox.hgrow="ALWAYS" />
|
<TextArea fx:id="txtCompose" maxHeight="1.7976931348623157E308" minHeight="1.0" prefHeight="25.0" prefRowCount="1" promptText="Compose..." styleClass="transparent" wrapText="true" HBox.hgrow="ALWAYS" />
|
||||||
<ImageView fitHeight="20.0" fitWidth="20.0" onMouseClicked="#onSend" opacity="0.5" pickOnBounds="true" preserveRatio="true">
|
<ImageView fitHeight="20.0" fitWidth="20.0" onMouseClicked="#onSend" opacity="0.5" pickOnBounds="true" preserveRatio="true">
|
||||||
<image>
|
<image>
|
||||||
<Image url="@../icons/icon-send-2.png" />
|
<Image url="@../icons/icon-send-2.png" />
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.String?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.Pane?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
|
||||||
|
<HBox spacing="8.0" stylesheets="@../styling.css" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.item.MessageItemController">
|
||||||
|
<children>
|
||||||
|
<Pane fx:id="paneIcon" maxHeight="40.0" maxWidth="40.0" minHeight="40.0" minWidth="40.0" style="-fx-background-color: white;" />
|
||||||
|
<VBox alignment="CENTER_LEFT" minHeight="40.0" spacing="4.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<HBox alignment="BOTTOM_LEFT" spacing="8.0">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="lblAuthor" style="-fx-font-size: 14;" text="\@ Username">
|
||||||
|
<styleClass>
|
||||||
|
<String fx:value="axis" />
|
||||||
|
<String fx:value="accent" />
|
||||||
|
</styleClass>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="lblTag" text="You" visible="false">
|
||||||
|
<styleClass>
|
||||||
|
<String fx:value="tag" />
|
||||||
|
<String fx:value="small" />
|
||||||
|
<String fx:value="axis" />
|
||||||
|
</styleClass>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="lblTimeAgo" alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 10;" styleClass="faint" text="10 minutes ago" textAlignment="RIGHT" HBox.hgrow="ALWAYS" />
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
<VBox fx:id="vboxMessages" spacing="4.0">
|
||||||
|
<children>
|
||||||
|
<Label text="Message contents" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<?import javafx.scene.image.ImageView?>
|
<?import javafx.scene.image.ImageView?>
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
|
||||||
<HBox fx:id="hboxParent" opacity="0.8" spacing="4.0" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.item.MainTopicItemController">
|
<HBox fx:id="hboxParent" opacity="0.8" spacing="4.0" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.item.TopicItemController">
|
||||||
<children>
|
<children>
|
||||||
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
|
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
|
||||||
<image>
|
<image>
|
||||||
@ -1,8 +1,9 @@
|
|||||||
package dev.wiing.gossip.lib;
|
package dev.wiing.gossip.lib;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.packets.CreateTopicPacket;
|
import dev.wiing.gossip.lib.packets.MessageCreatedPacket;
|
||||||
import dev.wiing.gossip.lib.packets.Packet;
|
import dev.wiing.gossip.lib.packets.Packet;
|
||||||
import dev.wiing.gossip.lib.packets.TopicAddedPacket;
|
import dev.wiing.gossip.lib.packets.TopicCreatedPacket;
|
||||||
|
import dev.wiing.gossip.lib.packets.TopicUpdatePacket;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -28,22 +29,30 @@ public class PacketHandler {
|
|||||||
listeners.get(type).remove(listener);
|
listeners.get(type).remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Packet> void runPacket(Class<T> packetClass, T packet) {
|
public <T extends Packet> boolean runPacket(Class<T> packetClass, T packet) {
|
||||||
Set<PacketListener<T>> result = getListeners(packetClass);
|
Set<PacketListener<T>> result = getListeners(packetClass);
|
||||||
|
|
||||||
if (result == null) return;
|
if (result == null || result.isEmpty()) return false;
|
||||||
|
|
||||||
for (PacketListener<T> packetListener : result) {
|
for (PacketListener<T> packetListener : result) {
|
||||||
packetListener.onReceive(packet);
|
packetListener.onReceive(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runPacket(Packet packet) {
|
public boolean runPacket(Packet packet) {
|
||||||
switch (packet.getType()) {
|
switch (packet.getType()) {
|
||||||
case TopicAddedPacket.TYPE:
|
case TopicCreatedPacket.TYPE:
|
||||||
runPacket(TopicAddedPacket.class, (TopicAddedPacket)packet);
|
return runPacket(TopicCreatedPacket.class, (TopicCreatedPacket)packet);
|
||||||
break;
|
|
||||||
|
case TopicUpdatePacket.TYPE:
|
||||||
|
return runPacket(TopicUpdatePacket.class, (TopicUpdatePacket)packet);
|
||||||
|
|
||||||
|
case MessageCreatedPacket.TYPE:
|
||||||
|
return runPacket(MessageCreatedPacket.class, (MessageCreatedPacket)packet);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Packet> Set<PacketListener<T>> getListeners(Class<T> packetClass) {
|
public <T extends Packet> Set<PacketListener<T>> getListeners(Class<T> packetClass) {
|
||||||
@ -55,4 +64,14 @@ public class PacketHandler {
|
|||||||
}).collect(Collectors.toSet());
|
}).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Short> getListeningTypes() {
|
||||||
|
return new ArrayList<>() {
|
||||||
|
{
|
||||||
|
add(TopicCreatedPacket.TYPE);
|
||||||
|
add(TopicUpdatePacket.TYPE);
|
||||||
|
add(MessageCreatedPacket.TYPE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,15 +14,21 @@ public class PacketManager {
|
|||||||
private final List<Packet> packetList = new ArrayList<>() {
|
private final List<Packet> packetList = new ArrayList<>() {
|
||||||
{
|
{
|
||||||
add(new TestPacket());
|
add(new TestPacket());
|
||||||
|
add(new AckPacket());
|
||||||
|
|
||||||
add(new RegisterPacket());
|
add(new RegisterRequestPacket());
|
||||||
add(new CredentialsPacket());
|
add(new RegisterCredentialsPacket());
|
||||||
|
|
||||||
add(new CreateTopicPacket());
|
add(new TopicPushPacket());
|
||||||
add(new TopicAddedPacket());
|
add(new TopicCreatedPacket());
|
||||||
|
add(new TopicJoinPacket());
|
||||||
|
add(new TopicUpdatePacket());
|
||||||
|
|
||||||
add(new FetchUserPacket());
|
add(new UserFetchPacket());
|
||||||
add(new UserDataPacket());
|
add(new UserDataPacket());
|
||||||
|
|
||||||
|
add(new MessagePushPacket());
|
||||||
|
add(new MessageCreatedPacket());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
47
Lib/src/main/java/dev/wiing/gossip/lib/data/AuthSecret.java
Normal file
47
Lib/src/main/java/dev/wiing/gossip/lib/data/AuthSecret.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AuthSecret {
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
private byte[] value = new byte[LENGTH];
|
||||||
|
|
||||||
|
public AuthSecret(byte... value) {
|
||||||
|
if (value.length != LENGTH)
|
||||||
|
throw new RuntimeException("Invalid length");
|
||||||
|
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthSecret(Byte... value) {
|
||||||
|
if (value.length != LENGTH)
|
||||||
|
throw new RuntimeException("Invalid length");
|
||||||
|
|
||||||
|
for (int i = 0; i < value.length; i++) {
|
||||||
|
this.value[i] = value[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthSecret(List<Byte> value) {
|
||||||
|
this(value.toArray(new Byte[32]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthSecret(String value) {
|
||||||
|
this(value.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthSecret(ByteBuffer buffer) {
|
||||||
|
buffer.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
return new String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
Lib/src/main/java/dev/wiing/gossip/lib/data/ListData.java
Normal file
60
Lib/src/main/java/dev/wiing/gossip/lib/data/ListData.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ListData<T extends PacketData> implements PacketData {
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ListDataInitializer<U> {
|
||||||
|
U create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ListDataInitializer<T> entryInitializer;
|
||||||
|
|
||||||
|
private final List<T> data = new ArrayList<>();
|
||||||
|
|
||||||
|
public ListData(ListDataInitializer<T> entryInitializer) {
|
||||||
|
this.entryInitializer = entryInitializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return 4 + data.stream()
|
||||||
|
.map(PacketData::getLength)
|
||||||
|
.reduce(0, Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer getBytes() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(getLength());
|
||||||
|
|
||||||
|
buffer.putInt(data.size());
|
||||||
|
|
||||||
|
for (T datum : data) {
|
||||||
|
buffer.put(datum.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBytes(ByteBuffer buffer) {
|
||||||
|
this.data.clear();
|
||||||
|
|
||||||
|
int size = buffer.getInt();
|
||||||
|
|
||||||
|
for (; size > 0; --size) {
|
||||||
|
T entry = entryInitializer.create();
|
||||||
|
entry.setBytes(buffer);
|
||||||
|
this.data.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Lib/src/main/java/dev/wiing/gossip/lib/data/LongData.java
Normal file
34
Lib/src/main/java/dev/wiing/gossip/lib/data/LongData.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class LongData implements PacketAtomicData<Long> {
|
||||||
|
|
||||||
|
private long value = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongData setValue(Long value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer getBytes() {
|
||||||
|
return ByteBuffer.allocate(getLength()).putLong(value).rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBytes(ByteBuffer buffer) {
|
||||||
|
value = buffer.getLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
|
public interface PacketAtomicData<T> extends PacketData {
|
||||||
|
T getValue();
|
||||||
|
PacketAtomicData<T> setValue(T value);
|
||||||
|
}
|
||||||
@ -1,13 +1,8 @@
|
|||||||
package dev.wiing.gossip.lib.data;
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public interface DataType<T> {
|
public interface PacketData {
|
||||||
|
|
||||||
T getValue();
|
|
||||||
void setValue(T val);
|
|
||||||
|
|
||||||
int getLength();
|
int getLength();
|
||||||
|
|
||||||
ByteBuffer getBytes();
|
ByteBuffer getBytes();
|
||||||
@ -1,11 +1,9 @@
|
|||||||
package dev.wiing.gossip.lib.data;
|
package dev.wiing.gossip.lib.data;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class StringType implements DataType<String> {
|
public class StringData implements PacketAtomicData<String> {
|
||||||
|
|
||||||
private String value = "";
|
private String value = "";
|
||||||
|
|
||||||
@ -15,8 +13,9 @@ public class StringType implements DataType<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(String val) {
|
public StringData setValue(String val) {
|
||||||
this.value = val;
|
this.value = val;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -3,15 +3,35 @@ package dev.wiing.gossip.lib.models;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
public class Message {
|
public class Message {
|
||||||
private User author;
|
private final User author;
|
||||||
private String message;
|
private final Topic topic;
|
||||||
private LocalDateTime postTime;
|
private final String contents;
|
||||||
|
private final LocalDateTime postTime;
|
||||||
|
|
||||||
public Message(User author, String message, LocalDateTime postTime) {
|
public Message(User author, Topic topic, String contents, LocalDateTime postTime) {
|
||||||
this.author = author;
|
this.author = author;
|
||||||
this.message = message;
|
this.topic = topic;
|
||||||
|
this.contents = contents;
|
||||||
this.postTime = postTime;
|
this.postTime = postTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Message(User author, Topic topic, String contents) {
|
||||||
|
this(author, topic, contents, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Topic getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContents() {
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getPostTime() {
|
||||||
|
return postTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
package dev.wiing.gossip.lib.models;
|
package dev.wiing.gossip.lib.models;
|
||||||
|
|
||||||
public class SecretUser extends User {
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
private final byte[] userSecret;
|
import dev.wiing.gossip.lib.models.User;
|
||||||
|
|
||||||
public SecretUser(String username, int iconID, long userID, byte[] userSecret) {
|
public class SecretUser extends User {
|
||||||
|
private final AuthSecret userSecret;
|
||||||
|
|
||||||
|
public SecretUser(String username, int iconID, long userID, AuthSecret userSecret) {
|
||||||
super(username, iconID, userID);
|
super(username, iconID, userID);
|
||||||
this.userSecret = userSecret;
|
this.userSecret = userSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getUserSecret() {
|
public AuthSecret getUserSecret() {
|
||||||
return userSecret;
|
return userSecret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,7 @@ package dev.wiing.gossip.lib.models;
|
|||||||
|
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class Topic {
|
public class Topic {
|
||||||
@ -16,6 +15,8 @@ public class Topic {
|
|||||||
private final Map<Long, User> users = new ConcurrentHashMap<>();
|
private final Map<Long, User> users = new ConcurrentHashMap<>();
|
||||||
private short color;
|
private short color;
|
||||||
|
|
||||||
|
private final List<Message> messages = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
public Topic(long id, String name, String description, User host, short color) {
|
public Topic(long id, String name, String description, User host, short color) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -72,20 +73,30 @@ public class Topic {
|
|||||||
if (this.users.containsKey(user.getUserID())) return;
|
if (this.users.containsKey(user.getUserID())) return;
|
||||||
|
|
||||||
this.users.put(user.getUserID(), user);
|
this.users.put(user.getUserID(), user);
|
||||||
this.changeSupport.firePropertyChange("userAdd", null, getUsersReadOnly());
|
this.changeSupport.firePropertyChange("userAdd", user, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeUser(User user) {
|
public void removeUser(User user) {
|
||||||
if (!this.users.containsKey(user.getUserID())) return;
|
if (!this.users.containsKey(user.getUserID())) return;
|
||||||
|
|
||||||
this.users.remove(user.getUserID());
|
this.users.remove(user.getUserID());
|
||||||
this.changeSupport.firePropertyChange("userRemove", null, getUsersReadOnly());
|
this.changeSupport.firePropertyChange("userRemove", null, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasUser(User user) {
|
public boolean hasUser(User user) {
|
||||||
return this.users.containsKey(user.getUserID());
|
return this.users.containsKey(user.getUserID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Message> getMessagesReadOnly() {
|
||||||
|
return Collections.unmodifiableList(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessage(Message message) {
|
||||||
|
messages.add(message);
|
||||||
|
|
||||||
|
this.changeSupport.firePropertyChange("messageAdd", null, message);
|
||||||
|
}
|
||||||
|
|
||||||
public void addChangeListener(PropertyChangeListener listener) {
|
public void addChangeListener(PropertyChangeListener listener) {
|
||||||
this.changeSupport.addPropertyChangeListener(listener);
|
this.changeSupport.addPropertyChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,41 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class AckPacket extends Packet {
|
||||||
|
|
||||||
|
public static final short TYPE = 0x02;
|
||||||
|
public static final int LENGTH = 0x002;
|
||||||
|
|
||||||
|
private short acknowledgement;
|
||||||
|
|
||||||
|
public AckPacket() {
|
||||||
|
super(TYPE, LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getAcknowledgement() {
|
||||||
|
return acknowledgement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcknowledgement(short acknowledgement) {
|
||||||
|
this.acknowledgement = acknowledgement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcknowledgement(Packet packet) {
|
||||||
|
setAcknowledgement(packet.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
|
AckPacket packet = new AckPacket();
|
||||||
|
|
||||||
|
packet.acknowledgement = buffer.getShort();
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
|
buffer.putShort(acknowledgement);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
|
|
||||||
|
public abstract class AuthRequiredPacket extends Packet {
|
||||||
|
private AuthSecret auth;
|
||||||
|
|
||||||
|
public AuthRequiredPacket(short type, int length) {
|
||||||
|
super(type, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthSecret getAuth() {
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuth(AuthSecret auth) {
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class MessageCreatedPacket extends Packet {
|
||||||
|
|
||||||
|
public static final short TYPE = 0x32;
|
||||||
|
public static final int LENGTH = 0x014;
|
||||||
|
|
||||||
|
private long authorID;
|
||||||
|
private long topicID;
|
||||||
|
private final StringData contents = new StringData();
|
||||||
|
|
||||||
|
public MessageCreatedPacket() {
|
||||||
|
super(TYPE, LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAuthorID() {
|
||||||
|
return authorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthorID(long authorID) {
|
||||||
|
this.authorID = authorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTopicID() {
|
||||||
|
return topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicID(long topicID) {
|
||||||
|
this.topicID = topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContents() {
|
||||||
|
return contents.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContents(String contents) {
|
||||||
|
this.contents.setValue(contents);
|
||||||
|
setLength(16 + this.contents.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
|
MessageCreatedPacket packet = new MessageCreatedPacket();
|
||||||
|
packet.setLength(size);
|
||||||
|
|
||||||
|
packet.authorID = buffer.getLong();
|
||||||
|
packet.topicID = buffer.getLong();
|
||||||
|
packet.contents.setBytes(buffer);
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
|
buffer.putLong(authorID);
|
||||||
|
buffer.putLong(topicID);
|
||||||
|
buffer.put(contents.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class MessagePushPacket extends AuthRequiredPacket {
|
||||||
|
public static final short TYPE = 0x31;
|
||||||
|
public static final int LENGTH = 0x02C;
|
||||||
|
|
||||||
|
private long topicID;
|
||||||
|
private final StringData message = new StringData();
|
||||||
|
|
||||||
|
public MessagePushPacket() {
|
||||||
|
super(TYPE, LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTopicID() {
|
||||||
|
return topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicID(long topicID) {
|
||||||
|
this.topicID = topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message.setValue(message);
|
||||||
|
setLength(40 + this.message.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
|
MessagePushPacket packet = new MessagePushPacket();
|
||||||
|
packet.setLength(size);
|
||||||
|
|
||||||
|
packet.setAuth(new AuthSecret(buffer));
|
||||||
|
packet.topicID = buffer.getLong();
|
||||||
|
packet.message.setBytes(buffer);
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
|
buffer.put(getAuth().getBytes());
|
||||||
|
buffer.putLong(topicID);
|
||||||
|
buffer.put(message.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,24 +1,26 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class CredentialsPacket extends Packet {
|
public class RegisterCredentialsPacket extends Packet {
|
||||||
|
|
||||||
public static short TYPE = 0x03;
|
public static short TYPE = 0x04;
|
||||||
public static int LENGTH = 0x028;
|
public static int LENGTH = 0x028;
|
||||||
|
|
||||||
private byte[] secret = new byte[32];
|
private AuthSecret secret;
|
||||||
private long uID;
|
private long uID;
|
||||||
|
|
||||||
public CredentialsPacket() {
|
public RegisterCredentialsPacket() {
|
||||||
super(TYPE, LENGTH);
|
super(TYPE, LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getSecret() {
|
public AuthSecret getSecret() {
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecret(byte[] secret) {
|
public void setSecret(AuthSecret secret) {
|
||||||
this.secret = secret;
|
this.secret = secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +34,9 @@ public class CredentialsPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet readBytes(ByteBuffer buffer, int size) {
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
CredentialsPacket packet = new CredentialsPacket();
|
RegisterCredentialsPacket packet = new RegisterCredentialsPacket();
|
||||||
|
|
||||||
buffer.get(packet.secret);
|
packet.secret = new AuthSecret(buffer);
|
||||||
packet.setUID(buffer.getLong());
|
packet.setUID(buffer.getLong());
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
@ -42,7 +44,7 @@ public class CredentialsPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeBytes(ByteBuffer buffer) {
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
buffer.put(getSecret());
|
buffer.put(getSecret().getBytes());
|
||||||
buffer.putLong(getUID());
|
buffer.putLong(getUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,24 +1,24 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.data.StringType;
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class RegisterPacket extends Packet {
|
public class RegisterRequestPacket extends Packet {
|
||||||
|
|
||||||
public static final short TYPE = 0x02;
|
public static final short TYPE = 0x03;
|
||||||
public static final int SIZE = 0x0005;
|
public static final int SIZE = 0x0005;
|
||||||
|
|
||||||
private final StringType username = new StringType();
|
private final StringData username = new StringData();
|
||||||
private byte avatarID;
|
private byte avatarID;
|
||||||
|
|
||||||
public RegisterPacket() {
|
public RegisterRequestPacket() {
|
||||||
super(TYPE, SIZE);
|
super(TYPE, SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet readBytes(ByteBuffer buffer, int size) {
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
RegisterPacket packet = new RegisterPacket();
|
RegisterRequestPacket packet = new RegisterRequestPacket();
|
||||||
packet.setLength(size);
|
packet.setLength(size);
|
||||||
|
|
||||||
packet.username.setBytes(buffer);
|
packet.username.setBytes(buffer);
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.data.StringType;
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class TestPacket extends Packet {
|
public class TestPacket extends Packet {
|
||||||
@ -10,7 +9,7 @@ public class TestPacket extends Packet {
|
|||||||
public static final short TYPE = 0x01;
|
public static final short TYPE = 0x01;
|
||||||
public static final int SIZE = 0x0000;
|
public static final int SIZE = 0x0000;
|
||||||
|
|
||||||
private final StringType message = new StringType();
|
private final StringData message = new StringData();
|
||||||
|
|
||||||
public TestPacket() {
|
public TestPacket() {
|
||||||
super(TYPE, SIZE);
|
super(TYPE, SIZE);
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.data.StringType;
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class TopicAddedPacket extends Packet {
|
public class TopicCreatedPacket extends Packet {
|
||||||
|
|
||||||
public static final short TYPE = 0x12;
|
public static final short TYPE = 0x12;
|
||||||
public static final int LENGTH = 0x014;
|
public static final int LENGTH = 0x014;
|
||||||
|
|
||||||
private long topicID;
|
private long topicID;
|
||||||
private long hostID;
|
private long hostID;
|
||||||
private final StringType topicName = new StringType();
|
private final StringData topicName = new StringData();
|
||||||
private final StringType topicDescription = new StringType();
|
private final StringData topicDescription = new StringData();
|
||||||
private short topicColor;
|
private short topicColor;
|
||||||
|
|
||||||
public TopicAddedPacket() {
|
public TopicCreatedPacket() {
|
||||||
super(TYPE, LENGTH);
|
super(TYPE, LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ public class TopicAddedPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet readBytes(ByteBuffer buffer, int size) {
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
TopicAddedPacket packet = new TopicAddedPacket();
|
TopicCreatedPacket packet = new TopicCreatedPacket();
|
||||||
setLength(size);
|
setLength(size);
|
||||||
|
|
||||||
packet.topicID = buffer.getLong();
|
packet.topicID = buffer.getLong();
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class TopicJoinPacket extends AuthRequiredPacket {
|
||||||
|
|
||||||
|
public static final short TYPE = 0x13;
|
||||||
|
public static final int LENGTH = 0x028;
|
||||||
|
|
||||||
|
private long topicID;
|
||||||
|
|
||||||
|
public TopicJoinPacket() {
|
||||||
|
super(TYPE, LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTopicID() {
|
||||||
|
return topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicID(long topicID) {
|
||||||
|
this.topicID = topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
|
TopicJoinPacket packet = new TopicJoinPacket();
|
||||||
|
|
||||||
|
packet.setAuth(new AuthSecret(buffer));
|
||||||
|
packet.topicID = buffer.getLong();
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
|
buffer.put(getAuth().getBytes());
|
||||||
|
buffer.putLong(topicID);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +1,19 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.data.StringType;
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class CreateTopicPacket extends Packet {
|
public class TopicPushPacket extends AuthRequiredPacket {
|
||||||
|
|
||||||
public static final short TYPE = 0x11;
|
public static final short TYPE = 0x11;
|
||||||
public static final int LENGTH = 0x022;
|
public static final int LENGTH = 0x022;
|
||||||
|
|
||||||
private byte[] userSecret = new byte[32];
|
private final StringData topicName = new StringData();
|
||||||
private final StringType topicName = new StringType();
|
private final StringData topicDescription = new StringData();
|
||||||
private final StringType topicDescription = new StringType();
|
|
||||||
|
|
||||||
public CreateTopicPacket() {
|
public TopicPushPacket() {
|
||||||
super(TYPE, LENGTH);
|
super(TYPE, LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,14 +25,6 @@ public class CreateTopicPacket extends Packet {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getUserSecret() {
|
|
||||||
return userSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserSecret(byte[] userSecret) {
|
|
||||||
this.userSecret = userSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTopicName() {
|
public String getTopicName() {
|
||||||
return topicName.getValue();
|
return topicName.getValue();
|
||||||
}
|
}
|
||||||
@ -53,10 +45,10 @@ public class CreateTopicPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet readBytes(ByteBuffer buffer, int size) {
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
CreateTopicPacket packet = new CreateTopicPacket();
|
TopicPushPacket packet = new TopicPushPacket();
|
||||||
packet.setLength(size);
|
packet.setLength(size);
|
||||||
|
|
||||||
buffer.get(packet.userSecret);
|
packet.setAuth(new AuthSecret(buffer));
|
||||||
packet.topicName.setBytes(buffer);
|
packet.topicName.setBytes(buffer);
|
||||||
packet.topicDescription.setBytes(buffer);
|
packet.topicDescription.setBytes(buffer);
|
||||||
|
|
||||||
@ -65,7 +57,7 @@ public class CreateTopicPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeBytes(ByteBuffer buffer) {
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
buffer.put(userSecret);
|
buffer.put(getAuth().getBytes());
|
||||||
buffer.put(topicName.getBytes());
|
buffer.put(topicName.getBytes());
|
||||||
buffer.put(topicDescription.getBytes());
|
buffer.put(topicDescription.getBytes());
|
||||||
}
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.ListData;
|
||||||
|
import dev.wiing.gossip.lib.data.LongData;
|
||||||
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TopicUpdatePacket extends Packet {
|
||||||
|
public static final short TYPE = 0x14;
|
||||||
|
public static final int LENGTH = 0x009;
|
||||||
|
|
||||||
|
private long topicID;
|
||||||
|
private byte updateFlags = 0;
|
||||||
|
|
||||||
|
// FLAG 0b0001 == 0x1
|
||||||
|
public static final byte FLAG_TOPIC_NAME_UPDATED = 0b1;
|
||||||
|
private final StringData topicName = new StringData();
|
||||||
|
|
||||||
|
// FLAG 0b0010 == 0x2
|
||||||
|
public static final byte FLAG_TOPIC_DESCRIPTION_UPDATED = 0b10;
|
||||||
|
private final StringData topicDescription = new StringData();
|
||||||
|
|
||||||
|
// FLAG 0b0100 == 0x4
|
||||||
|
public static final byte FLAG_USERS_JOINED = 0b100;
|
||||||
|
private final ListData<LongData> usersJoined = new ListData<>(LongData::new);
|
||||||
|
|
||||||
|
// FLAG 0b1000 == 0x8
|
||||||
|
public static final byte FLAG_USERS_LEFT = 0b1000;
|
||||||
|
private final ListData<LongData> usersLeft = new ListData<>(LongData::new);
|
||||||
|
|
||||||
|
public TopicUpdatePacket() {
|
||||||
|
super(TYPE, LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLength() {
|
||||||
|
if (!usersJoined.getData().isEmpty()) {
|
||||||
|
updateFlags |= FLAG_USERS_JOINED;
|
||||||
|
}
|
||||||
|
if (!usersLeft.getData().isEmpty()) {
|
||||||
|
updateFlags |= FLAG_USERS_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLength(9 +
|
||||||
|
(isTopicNameModified() ? topicName.getLength() : 0) +
|
||||||
|
(isTopicDescriptionModified() ? topicDescription.getLength() : 0) +
|
||||||
|
(haveUsersJoined() ? usersJoined.getLength() : 0) +
|
||||||
|
(haveUsersLeft() ? usersLeft.getLength() : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
updateLength();
|
||||||
|
return super.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTopicID() {
|
||||||
|
return topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicID(long topicID) {
|
||||||
|
this.topicID = topicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTopicNameModified() {
|
||||||
|
return (updateFlags & FLAG_TOPIC_NAME_UPDATED) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTopicDescriptionModified() {
|
||||||
|
return (updateFlags & FLAG_TOPIC_DESCRIPTION_UPDATED) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean haveUsersJoined() {
|
||||||
|
return (updateFlags & FLAG_USERS_JOINED) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean haveUsersLeft() {
|
||||||
|
return (updateFlags & FLAG_USERS_LEFT) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopicName() {
|
||||||
|
return topicName.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicName(String topicName) {
|
||||||
|
this.topicName.setValue(topicName);
|
||||||
|
this.updateFlags |= FLAG_TOPIC_NAME_UPDATED;
|
||||||
|
updateLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopicDescription() {
|
||||||
|
return topicDescription.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicDescription(String topicDescription) {
|
||||||
|
this.topicDescription.setValue(topicDescription);
|
||||||
|
this.updateFlags |= FLAG_TOPIC_DESCRIPTION_UPDATED;
|
||||||
|
updateLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LongData> getUsersJoined() {
|
||||||
|
return usersJoined.getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LongData> getUsersLeft() {
|
||||||
|
return usersLeft.getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
|
TopicUpdatePacket packet = new TopicUpdatePacket();
|
||||||
|
packet.setLength(size);
|
||||||
|
|
||||||
|
packet.topicID = buffer.getLong();
|
||||||
|
packet.updateFlags = buffer.get();
|
||||||
|
|
||||||
|
if (packet.isTopicNameModified()) packet.topicName.setBytes(buffer);
|
||||||
|
if (packet.isTopicDescriptionModified()) packet.topicDescription.setBytes(buffer);
|
||||||
|
if (packet.haveUsersJoined()) packet.usersJoined.setBytes(buffer);
|
||||||
|
if (packet.haveUsersLeft()) packet.usersLeft.setBytes(buffer);
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeBytes(ByteBuffer buffer) {
|
||||||
|
updateLength();
|
||||||
|
|
||||||
|
buffer.putLong(topicID);
|
||||||
|
buffer.put(updateFlags);
|
||||||
|
|
||||||
|
if (isTopicNameModified()) buffer.put(topicName.getBytes());
|
||||||
|
if (isTopicDescriptionModified()) buffer.put(topicDescription.getBytes());
|
||||||
|
if (haveUsersJoined()) buffer.put(usersJoined.getBytes());
|
||||||
|
if (haveUsersLeft()) buffer.put(usersLeft.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package dev.wiing.gossip.lib.packets;
|
package dev.wiing.gossip.lib.packets;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.data.StringType;
|
import dev.wiing.gossip.lib.data.StringData;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ public class UserDataPacket extends Packet {
|
|||||||
public static final int LENGTH = 0x00a;
|
public static final int LENGTH = 0x00a;
|
||||||
|
|
||||||
private long userID;
|
private long userID;
|
||||||
private final StringType username = new StringType();
|
private final StringData username = new StringData();
|
||||||
private byte avatarID;
|
private byte avatarID;
|
||||||
|
|
||||||
public UserDataPacket() {
|
public UserDataPacket() {
|
||||||
|
|||||||
@ -2,14 +2,14 @@ package dev.wiing.gossip.lib.packets;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class FetchUserPacket extends Packet {
|
public class UserFetchPacket extends Packet {
|
||||||
|
|
||||||
public static final short TYPE = 0x21;
|
public static final short TYPE = 0x21;
|
||||||
public static final int LENGTH = 0x008;
|
public static final int LENGTH = 0x008;
|
||||||
|
|
||||||
private long userID;
|
private long userID;
|
||||||
|
|
||||||
public FetchUserPacket() {
|
public UserFetchPacket() {
|
||||||
super(TYPE, LENGTH);
|
super(TYPE, LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ public class FetchUserPacket extends Packet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet readBytes(ByteBuffer buffer, int size) {
|
public Packet readBytes(ByteBuffer buffer, int size) {
|
||||||
FetchUserPacket packet = new FetchUserPacket();
|
UserFetchPacket packet = new UserFetchPacket();
|
||||||
|
|
||||||
packet.userID = buffer.getLong();
|
packet.userID = buffer.getLong();
|
||||||
|
|
||||||
@ -20,6 +20,22 @@
|
|||||||
<artifactId>Lib</artifactId>
|
<artifactId>Lib</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>2.20.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.20.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
<version>3.4.4</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@ -1,14 +1,20 @@
|
|||||||
package dev.wiing.gossip.server;
|
package dev.wiing.gossip.server;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.AuthSecret;
|
||||||
import dev.wiing.gossip.lib.models.SecretUser;
|
import dev.wiing.gossip.lib.models.SecretUser;
|
||||||
import dev.wiing.gossip.lib.models.Topic;
|
import dev.wiing.gossip.lib.models.Topic;
|
||||||
import dev.wiing.gossip.lib.models.User;
|
import dev.wiing.gossip.lib.models.User;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Database {
|
public class Database {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(Database.class);
|
||||||
|
|
||||||
private int userIdCounter = 1;
|
private int userIdCounter = 1;
|
||||||
private final Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());
|
private final Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());
|
||||||
private final Map<String, User> usersBySecret = Collections.synchronizedMap(new HashMap<>());
|
private final Map<String, User> usersBySecret = Collections.synchronizedMap(new HashMap<>());
|
||||||
@ -31,8 +37,9 @@ public class Database {
|
|||||||
public SecretUser registerUser(String username, byte iconID, Socket socket) {
|
public SecretUser registerUser(String username, byte iconID, Socket socket) {
|
||||||
SecureRandom random = new SecureRandom();
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
byte[] secret = new byte[32];
|
byte[] secretBytes = new byte[32];
|
||||||
random.nextBytes(secret);
|
random.nextBytes(secretBytes);
|
||||||
|
AuthSecret secret = new AuthSecret(secretBytes);
|
||||||
|
|
||||||
long userID = userIdCounter++;
|
long userID = userIdCounter++;
|
||||||
|
|
||||||
@ -40,10 +47,10 @@ public class Database {
|
|||||||
|
|
||||||
users.put(userID, user);
|
users.put(userID, user);
|
||||||
userSockets.put(userID, socket);
|
userSockets.put(userID, socket);
|
||||||
usersBySecret.put(new String(secret), user);
|
usersBySecret.put(secret.getString(), user);
|
||||||
usedUsernames.add(username);
|
usedUsernames.add(username);
|
||||||
|
|
||||||
System.out.println("Created user: " + username + " #" + Long.toUnsignedString(userID));
|
logger.info("User created: \"{}\" (#{})", user.getUsername(), user.getUserID());
|
||||||
|
|
||||||
return new SecretUser(username, iconID, userID, secret);
|
return new SecretUser(username, iconID, userID, secret);
|
||||||
}
|
}
|
||||||
@ -59,8 +66,8 @@ public class Database {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User getUserBySecret(byte[] secret) {
|
public User getUserBySecret(AuthSecret secret) {
|
||||||
return usersBySecret.getOrDefault(secret, null);
|
return usersBySecret.getOrDefault(secret.getString(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<User> getUsers() {
|
public Collection<User> getUsers() {
|
||||||
@ -92,12 +99,14 @@ public class Database {
|
|||||||
userSockets.remove(user.getUserID());
|
userSockets.remove(user.getUserID());
|
||||||
|
|
||||||
usedUsernames.remove(user.getUsername());
|
usedUsernames.remove(user.getUsername());
|
||||||
|
|
||||||
|
logger.info("User removed: \"{}\" (#{})", user.getUsername(), user.getUserID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Topic createTopic(byte[] userSecret, String topicName, String topicDescription) {
|
public Topic createTopic(AuthSecret userSecret, String topicName, String topicDescription) {
|
||||||
if (!usersBySecret.containsKey(new String(userSecret))) return null;
|
if (!usersBySecret.containsKey(userSecret.getString())) return null;
|
||||||
|
|
||||||
User user = usersBySecret.get(new String(userSecret));
|
User user = usersBySecret.get(userSecret.getString());
|
||||||
|
|
||||||
short colorHue = (short)Math.abs((new Random().nextInt(360)));
|
short colorHue = (short)Math.abs((new Random().nextInt(360)));
|
||||||
|
|
||||||
@ -111,6 +120,8 @@ public class Database {
|
|||||||
|
|
||||||
topics.put(topic.getId(), topic);
|
topics.put(topic.getId(), topic);
|
||||||
|
|
||||||
|
logger.info("Topic created: \"{}\" (#{})", topic.getName(), topic.getId());
|
||||||
|
|
||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +130,8 @@ public class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeTopic(long topicID) {
|
public void removeTopic(long topicID) {
|
||||||
topics.remove(topicID);
|
Topic topic = topics.remove(topicID);
|
||||||
|
|
||||||
|
logger.info("Topic removed: \"{}\" (#{})", topic.getName(), topic.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
package dev.wiing.gossip.server;
|
package dev.wiing.gossip.server;
|
||||||
|
|
||||||
import dev.wiing.gossip.lib.Config;
|
import dev.wiing.gossip.lib.Config;
|
||||||
import dev.wiing.gossip.lib.packets.RegisterPacket;
|
|
||||||
import dev.wiing.gossip.lib.packets.TestPacket;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
@ -13,6 +11,37 @@ public class Program {
|
|||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
|
// try (FileOutputStream stream = new FileOutputStream("test.bin")) {
|
||||||
|
//
|
||||||
|
// TopicUpdatePacket packet = new TopicUpdatePacket();
|
||||||
|
// packet.setTopicID(123456789);
|
||||||
|
// packet.setTopicDescription("New Name");
|
||||||
|
// packet.getUsersJoined().add(new LongData().setValue(696969420L));
|
||||||
|
// packet.getUsersJoined().add(new LongData().setValue(987654231L));
|
||||||
|
//
|
||||||
|
// BufferedOutputStream out = new BufferedOutputStream(stream);
|
||||||
|
//
|
||||||
|
// ByteBuffer buffer = ByteBuffer.allocate(packet.getTotalLength());
|
||||||
|
// buffer.putShort(packet.getType());
|
||||||
|
// buffer.putInt(packet.getLength());
|
||||||
|
// packet.writeBytes(buffer);
|
||||||
|
//
|
||||||
|
// out.write(buffer.array());
|
||||||
|
// out.flush();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// try (FileInputStream stream = new FileInputStream("test.bin")) {
|
||||||
|
//
|
||||||
|
// TopicUpdatePacket test = new TopicUpdatePacket();
|
||||||
|
//
|
||||||
|
// BufferedInputStream in = new BufferedInputStream(stream);
|
||||||
|
//
|
||||||
|
// ByteBuffer buffer = ByteBuffer.wrap(in.readAllBytes()).position(6);
|
||||||
|
// Packet result = test.readBytes(buffer, 0);
|
||||||
|
//
|
||||||
|
// int a = 10;
|
||||||
|
// }
|
||||||
|
|
||||||
Globals.getPacketManager().registerPackets();
|
Globals.getPacketManager().registerPackets();
|
||||||
|
|
||||||
int port = Config.getPort();
|
int port = Config.getPort();
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
package dev.wiing.gossip.server;
|
package dev.wiing.gossip.server;
|
||||||
|
|
||||||
|
import dev.wiing.gossip.lib.data.LongData;
|
||||||
|
import dev.wiing.gossip.lib.models.Message;
|
||||||
import dev.wiing.gossip.lib.models.SecretUser;
|
import dev.wiing.gossip.lib.models.SecretUser;
|
||||||
import dev.wiing.gossip.lib.models.Topic;
|
import dev.wiing.gossip.lib.models.Topic;
|
||||||
import dev.wiing.gossip.lib.models.User;
|
import dev.wiing.gossip.lib.models.User;
|
||||||
import dev.wiing.gossip.lib.packets.*;
|
import dev.wiing.gossip.lib.packets.*;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -12,9 +16,19 @@ import java.net.SocketException;
|
|||||||
|
|
||||||
public record UserSocket(Socket socket) implements Runnable {
|
public record UserSocket(Socket socket) implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(UserSocket.class);
|
||||||
|
|
||||||
|
private void info(String message, Object ...params) {
|
||||||
|
logger.info(socket.getInetAddress().toString() + ":" + socket.getPort() + " > " + message, params);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (true) {
|
info("Established");
|
||||||
|
|
||||||
|
boolean loop = true;
|
||||||
|
|
||||||
|
while (socket.isConnected() && loop) {
|
||||||
try {
|
try {
|
||||||
if (!socket.isConnected())
|
if (!socket.isConnected())
|
||||||
break;
|
break;
|
||||||
@ -26,22 +40,30 @@ public record UserSocket(Socket socket) implements Runnable {
|
|||||||
packet.setSource(socket);
|
packet.setSource(socket);
|
||||||
|
|
||||||
switch (packet.getType()) {
|
switch (packet.getType()) {
|
||||||
case RegisterPacket.TYPE:
|
case RegisterRequestPacket.TYPE:
|
||||||
onRegisterUser((RegisterPacket) packet);
|
onRegisterUser((RegisterRequestPacket) packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CreateTopicPacket.TYPE:
|
case TopicPushPacket.TYPE:
|
||||||
onCreateTopic((CreateTopicPacket) packet);
|
onCreateTopic((TopicPushPacket) packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FetchUserPacket.TYPE:
|
case TopicJoinPacket.TYPE:
|
||||||
onFetchUser((FetchUserPacket) packet);
|
onUserJoinTopic((TopicJoinPacket) packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UserFetchPacket.TYPE:
|
||||||
|
onFetchUser((UserFetchPacket) packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessagePushPacket.TYPE:
|
||||||
|
onUserMessage((MessagePushPacket) packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
break;
|
loop = false;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,26 +72,30 @@ public record UserSocket(Socket socket) implements Runnable {
|
|||||||
Database.getInstance().removeUser(user);
|
Database.getInstance().removeUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRegisterUser(RegisterPacket packet) {
|
private void onRegisterUser(RegisterRequestPacket packet) {
|
||||||
SecretUser user = Database.getInstance().registerUser(packet.getUsername(), packet.getAvatarID(), packet.getSource());
|
SecretUser user = Database.getInstance().registerUser(packet.getUsername(), packet.getAvatarID(), packet.getSource());
|
||||||
|
|
||||||
CredentialsPacket creds = new CredentialsPacket();
|
info("Register as \"{}\" (#{})", user.getUsername().toUpperCase(), user.getUserID());
|
||||||
|
|
||||||
|
RegisterCredentialsPacket creds = new RegisterCredentialsPacket();
|
||||||
creds.setSecret(user.getUserSecret());
|
creds.setSecret(user.getUserSecret());
|
||||||
creds.setUID(user.getUserID());
|
creds.setUID(user.getUserID());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Globals.getPacketManager().replyPacket(packet, creds);
|
Globals.getPacketManager().replyPacket(packet, creds);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCreateTopic(CreateTopicPacket packet) {
|
private void onCreateTopic(TopicPushPacket packet) {
|
||||||
Topic topic = Database.getInstance().createTopic(packet.getUserSecret(), packet.getTopicName(), packet.getTopicDescription());
|
Topic topic = Database.getInstance().createTopic(packet.getAuth(), packet.getTopicName(), packet.getTopicDescription());
|
||||||
|
|
||||||
if (topic == null) return;
|
if (topic == null) return;
|
||||||
|
|
||||||
TopicAddedPacket added = new TopicAddedPacket();
|
info("\"{}\" created topic \"{}\" (#{})", topic.getHost().getUsername().toUpperCase(), topic.getName().toUpperCase(), topic.getId());
|
||||||
|
|
||||||
|
TopicCreatedPacket added = new TopicCreatedPacket();
|
||||||
added.setTopicID(topic.getId());
|
added.setTopicID(topic.getId());
|
||||||
added.setHostID(topic.getHost().getUserID());
|
added.setHostID(topic.getHost().getUserID());
|
||||||
added.setTopicName(topic.getName());
|
added.setTopicName(topic.getName());
|
||||||
@ -82,14 +108,54 @@ public record UserSocket(Socket socket) implements Runnable {
|
|||||||
try {
|
try {
|
||||||
Globals.getPacketManager().writePacket(socket.getOutputStream(), added);
|
Globals.getPacketManager().writePacket(socket.getOutputStream(), added);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onFetchUser(FetchUserPacket packet) {
|
private void onUserJoinTopic(TopicJoinPacket packet) {
|
||||||
|
Topic topic = Database.getInstance().getTopic(packet.getTopicID());
|
||||||
|
User requester = Database.getInstance().getUserBySecret(packet.getAuth());
|
||||||
|
|
||||||
|
if (requester == null) return;
|
||||||
|
if (topic == null) return;
|
||||||
|
|
||||||
|
if (!topic.hasUser(requester)) {
|
||||||
|
info("\"{}\" joined topic \"{}\" (#{})", topic.getHost().getUsername().toUpperCase(), topic.getName().toUpperCase(), topic.getId());
|
||||||
|
topic.addUser(requester);
|
||||||
|
}
|
||||||
|
|
||||||
|
AckPacket resp = new AckPacket();
|
||||||
|
resp.setAcknowledgement(packet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Globals.getPacketManager().replyPacket(packet, resp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
TopicUpdatePacket updatePacket = new TopicUpdatePacket();
|
||||||
|
updatePacket.setTopicID(topic.getId());
|
||||||
|
updatePacket.getUsersJoined().add(new LongData().setValue(requester.getUserID()));
|
||||||
|
|
||||||
|
for (User user : Database.getInstance().getUsers()) {
|
||||||
|
Socket socket = Database.getInstance().getUserSocket(user.getUserID());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Globals.getPacketManager().writePacket(socket.getOutputStream(), updatePacket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFetchUser(UserFetchPacket packet) {
|
||||||
User user = Database.getInstance().getUserByID(packet.getUserID());
|
User user = Database.getInstance().getUserByID(packet.getUserID());
|
||||||
|
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
info("Requested user #{}", user.getUserID());
|
||||||
|
|
||||||
UserDataPacket resp = new UserDataPacket();
|
UserDataPacket resp = new UserDataPacket();
|
||||||
resp.setUserID(user.getUserID());
|
resp.setUserID(user.getUserID());
|
||||||
resp.setUsername(user.getUsername());
|
resp.setUsername(user.getUsername());
|
||||||
@ -98,7 +164,45 @@ public record UserSocket(Socket socket) implements Runnable {
|
|||||||
try {
|
try {
|
||||||
Globals.getPacketManager().replyPacket(packet, resp);
|
Globals.getPacketManager().replyPacket(packet, resp);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
logger.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUserMessage(MessagePushPacket packet) {
|
||||||
|
Topic topic = Database.getInstance().getTopic(packet.getTopicID());
|
||||||
|
User user = Database.getInstance().getUserBySecret(packet.getAuth());
|
||||||
|
|
||||||
|
if (user == null) return;
|
||||||
|
if (topic == null) return;
|
||||||
|
|
||||||
|
Message message = new Message(user, topic, packet.getMessage());
|
||||||
|
|
||||||
|
topic.addMessage(message);
|
||||||
|
|
||||||
|
info("\"{}\" in \"{}\" sends \"{}\"", user.getUsername().toUpperCase(), topic.getName().toUpperCase(), packet.getMessage());
|
||||||
|
|
||||||
|
AckPacket ack = new AckPacket();
|
||||||
|
ack.setAcknowledgement(packet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Globals.getPacketManager().replyPacket(packet, ack);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageCreatedPacket messageCreated = new MessageCreatedPacket();
|
||||||
|
messageCreated.setAuthorID(user.getUserID());
|
||||||
|
messageCreated.setTopicID(topic.getId());
|
||||||
|
messageCreated.setContents(message.getContents());
|
||||||
|
|
||||||
|
for (User babbler : topic.getUsersReadOnly().values()) {
|
||||||
|
Socket userSocket = Database.getInstance().getUserSocket(babbler.getUserID());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Globals.getPacketManager().writePacket(userSocket.getOutputStream(), messageCreated);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
module dev.wiing.gossip.server {
|
module dev.wiing.gossip.server {
|
||||||
requires dev.wiing.gossip.lib;
|
requires dev.wiing.gossip.lib;
|
||||||
|
requires org.apache.logging.log4j;
|
||||||
|
|
||||||
|
opens dev.wiing.gossip.server to org.apache.logging.log4j;
|
||||||
}
|
}
|
||||||
12
Server/src/main/resources/log4j2.xml
Normal file
12
Server/src/main/resources/log4j2.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Configuration name="GossipServer" packages="">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="stdout" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %c{1} %highlight{ %p } %m%n"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Root level="info">
|
||||||
|
<AppenderRef ref="stdout"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
BIN
Server/test.bin
Normal file
BIN
Server/test.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user