Packet, Auth reworks & Messages
This commit is contained in:
@@ -20,6 +20,22 @@
|
||||
<artifactId>Lib</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</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>
|
||||
|
||||
</project>
|
||||
@@ -1,14 +1,20 @@
|
||||
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.Topic;
|
||||
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.security.SecureRandom;
|
||||
import java.util.*;
|
||||
|
||||
public class Database {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(Database.class);
|
||||
|
||||
private int userIdCounter = 1;
|
||||
private final Map<Long, User> users = 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) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
byte[] secret = new byte[32];
|
||||
random.nextBytes(secret);
|
||||
byte[] secretBytes = new byte[32];
|
||||
random.nextBytes(secretBytes);
|
||||
AuthSecret secret = new AuthSecret(secretBytes);
|
||||
|
||||
long userID = userIdCounter++;
|
||||
|
||||
@@ -40,10 +47,10 @@ public class Database {
|
||||
|
||||
users.put(userID, user);
|
||||
userSockets.put(userID, socket);
|
||||
usersBySecret.put(new String(secret), user);
|
||||
usersBySecret.put(secret.getString(), user);
|
||||
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);
|
||||
}
|
||||
@@ -59,8 +66,8 @@ public class Database {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public User getUserBySecret(byte[] secret) {
|
||||
return usersBySecret.getOrDefault(secret, null);
|
||||
public User getUserBySecret(AuthSecret secret) {
|
||||
return usersBySecret.getOrDefault(secret.getString(), null);
|
||||
}
|
||||
|
||||
public Collection<User> getUsers() {
|
||||
@@ -92,12 +99,14 @@ public class Database {
|
||||
userSockets.remove(user.getUserID());
|
||||
|
||||
usedUsernames.remove(user.getUsername());
|
||||
|
||||
logger.info("User removed: \"{}\" (#{})", user.getUsername(), user.getUserID());
|
||||
}
|
||||
|
||||
public Topic createTopic(byte[] userSecret, String topicName, String topicDescription) {
|
||||
if (!usersBySecret.containsKey(new String(userSecret))) return null;
|
||||
public Topic createTopic(AuthSecret userSecret, String topicName, String topicDescription) {
|
||||
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)));
|
||||
|
||||
@@ -111,6 +120,8 @@ public class Database {
|
||||
|
||||
topics.put(topic.getId(), topic);
|
||||
|
||||
logger.info("Topic created: \"{}\" (#{})", topic.getName(), topic.getId());
|
||||
|
||||
return topic;
|
||||
}
|
||||
|
||||
@@ -119,6 +130,8 @@ public class Database {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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.net.ServerSocket;
|
||||
@@ -13,6 +11,37 @@ public class Program {
|
||||
|
||||
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();
|
||||
|
||||
int port = Config.getPort();
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
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.Topic;
|
||||
import dev.wiing.gossip.lib.models.User;
|
||||
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.IOException;
|
||||
@@ -12,9 +16,19 @@ import java.net.SocketException;
|
||||
|
||||
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
|
||||
public void run() {
|
||||
while (true) {
|
||||
info("Established");
|
||||
|
||||
boolean loop = true;
|
||||
|
||||
while (socket.isConnected() && loop) {
|
||||
try {
|
||||
if (!socket.isConnected())
|
||||
break;
|
||||
@@ -26,22 +40,30 @@ public record UserSocket(Socket socket) implements Runnable {
|
||||
packet.setSource(socket);
|
||||
|
||||
switch (packet.getType()) {
|
||||
case RegisterPacket.TYPE:
|
||||
onRegisterUser((RegisterPacket) packet);
|
||||
case RegisterRequestPacket.TYPE:
|
||||
onRegisterUser((RegisterRequestPacket) packet);
|
||||
break;
|
||||
|
||||
case CreateTopicPacket.TYPE:
|
||||
onCreateTopic((CreateTopicPacket) packet);
|
||||
case TopicPushPacket.TYPE:
|
||||
onCreateTopic((TopicPushPacket) packet);
|
||||
break;
|
||||
|
||||
case FetchUserPacket.TYPE:
|
||||
onFetchUser((FetchUserPacket) packet);
|
||||
case TopicJoinPacket.TYPE:
|
||||
onUserJoinTopic((TopicJoinPacket) packet);
|
||||
break;
|
||||
|
||||
case UserFetchPacket.TYPE:
|
||||
onFetchUser((UserFetchPacket) packet);
|
||||
break;
|
||||
|
||||
case MessagePushPacket.TYPE:
|
||||
onUserMessage((MessagePushPacket) packet);
|
||||
break;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
break;
|
||||
loop = false;
|
||||
} 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);
|
||||
}
|
||||
|
||||
private void onRegisterUser(RegisterPacket packet) {
|
||||
private void onRegisterUser(RegisterRequestPacket packet) {
|
||||
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.setUID(user.getUserID());
|
||||
|
||||
try {
|
||||
Globals.getPacketManager().replyPacket(packet, creds);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCreateTopic(CreateTopicPacket packet) {
|
||||
Topic topic = Database.getInstance().createTopic(packet.getUserSecret(), packet.getTopicName(), packet.getTopicDescription());
|
||||
private void onCreateTopic(TopicPushPacket packet) {
|
||||
Topic topic = Database.getInstance().createTopic(packet.getAuth(), packet.getTopicName(), packet.getTopicDescription());
|
||||
|
||||
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.setHostID(topic.getHost().getUserID());
|
||||
added.setTopicName(topic.getName());
|
||||
@@ -82,14 +108,54 @@ public record UserSocket(Socket socket) implements Runnable {
|
||||
try {
|
||||
Globals.getPacketManager().writePacket(socket.getOutputStream(), added);
|
||||
} 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());
|
||||
|
||||
if (user == null) return;
|
||||
|
||||
info("Requested user #{}", user.getUserID());
|
||||
|
||||
UserDataPacket resp = new UserDataPacket();
|
||||
resp.setUserID(user.getUserID());
|
||||
resp.setUsername(user.getUsername());
|
||||
@@ -98,7 +164,45 @@ public record UserSocket(Socket socket) implements Runnable {
|
||||
try {
|
||||
Globals.getPacketManager().replyPacket(packet, resp);
|
||||
} 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 {
|
||||
requires dev.wiing.gossip.lib;
|
||||
requires org.apache.logging.log4j;
|
||||
|
||||
opens dev.wiing.gossip.server to org.apache.logging.log4j;
|
||||
}
|
||||
@@ -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>
|
||||
Binary file not shown.
Reference in New Issue
Block a user