Skip to content

Commit

Permalink
Add chat logging
Browse files Browse the repository at this point in the history
  • Loading branch information
logandhillon committed Oct 1, 2024
1 parent 081e598 commit 4f20428
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 12 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

group 'net.logandhillon'
version '0.9.6-alpha'
version '0.9.7-alpha'

repositories {
mavenCentral()
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/net/logandhillon/icx/ICX.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

public class ICX {
private static final Logger LOG = LoggerContext.getContext().getLogger(ICX.class);
private static boolean isServer = false;

public static void main(String[] args) {
boolean isServer = false;
for (String arg : args)
switch (arg) {
case "-h", "--help" -> printHelp();
Expand Down Expand Up @@ -40,4 +40,8 @@ Internet Communication Exchange (ICX)
-s, --server host an ICX server instead of launching a client
-i, --setup re-run initial config for ICX servers""");
}

public static boolean isServer() {
return isServer;
}
}
14 changes: 13 additions & 1 deletion src/main/java/net/logandhillon/icx/client/S2CHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import javafx.scene.control.ButtonType;
import net.logandhillon.icx.common.ICXMultimediaPayload;
import net.logandhillon.icx.common.ICXPacket;
import net.logandhillon.icx.server.ChatLogger;
import net.logandhillon.icx.server.NameRegistry;
import net.logandhillon.icx.ui.UI;
import net.logandhillon.icx.ui.view.ChatView;
import net.logandhillon.icx.ui.view.LoginView;
Expand All @@ -16,6 +18,7 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.net.SocketException;
import java.util.Objects;
import java.util.Optional;

public class S2CHandler extends Thread {
Expand Down Expand Up @@ -51,9 +54,18 @@ public void run() {

switch (packet.command()) {
case SRV_HELLO -> {
ICXClient.connectedRoomName = packet.content();
String[] payload = packet.content().split("\035");
ICXClient.connectedRoomName = payload[0];
ChatView.updateRoomName();
LOG.info("Server room name is {}", packet.content());

if (payload.length < 2) break;
LOG.info("Parsing chat history");
for (ChatLogger.Message msgLog : ChatLogger.parseLogs(payload[1])) {
if (Objects.equals(msgLog.sender(), NameRegistry.SERVER.name()))
Platform.runLater(() -> ChatView.postAlert(msgLog.message()));
else Platform.runLater(() -> ChatView.postMessage(msgLog.sender(), msgLog.message()));
}
}
case SRV_KICK -> {
Platform.runLater(() -> UI.reloadScene(new Scene(new LoginView()), () -> {
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/net/logandhillon/icx/server/C2SHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ public void run() {
OutputStream output = socket.getOutputStream();
writer = new PrintWriter(output, true);

sendPacket(writer, new ICXPacket(ICXPacket.Command.SRV_HELLO, NameRegistry.SERVER, ICXServer.PROPERTIES.roomName()));
sendPacket(writer, new ICXPacket(ICXPacket.Command.SRV_HELLO,
NameRegistry.SERVER,
ICXServer.PROPERTIES.roomName() + "\035" + ChatLogger.encodeLogs()));

String msg;
while ((msg = reader.readLine()) != null) {
Expand Down Expand Up @@ -71,12 +73,16 @@ public void run() {
case SEND -> {
if (packet.content().isBlank())
throw new RuntimeException("Message content cannot be blank");
LOG.info("{}: '{}'", packet.snvs().name(), packet.content());
ChatLogger.log(packet.snvs().name(), packet.content());
}
case FILE_INF ->
ICXMultimediaPayload.parseOrThrow(packet.content()); // verify packet integrity or throw
case FILE_INF -> {
ICXMultimediaPayload.parseOrThrow(packet.content()); // verify packet integrity or throw
ChatLogger.log(packet.snvs().name(), "[ Media unavailable ]");
}
case JOIN -> ChatLogger.logAlert(String.format("Welcome, %s!", packet.snvs().name()));
case EXIT -> {
LOG.info("Received EXIT command");
ChatLogger.logAlert(String.format("Farewell, %s!", packet.snvs().name()));
LOG.debug("Received EXIT command");
socket.close();
}
case SRV_ERR -> throw new RuntimeException("Illegal command");
Expand Down
68 changes: 68 additions & 0 deletions src/main/java/net/logandhillon/icx/server/ChatLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package net.logandhillon.icx.server;

import net.logandhillon.icx.ICX;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;

import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Objects;

public class ChatLogger {
private static final Logger LOG = LoggerContext.getContext().getLogger(ChatLogger.class);
private static final int MAX_LOG_SIZE = ICX.isServer() ? ICXServer.PROPERTIES.chatLoggerSize() : -1;
private static final Deque<Message> CHAT_LOG = new LinkedList<>();

public static void log(String sender, String message) {
Message msg = new Message(sender, message);
LOG.info(msg);

synchronized (CHAT_LOG) {
if (CHAT_LOG.size() >= MAX_LOG_SIZE) CHAT_LOG.removeFirst();
CHAT_LOG.addLast(msg);
}
}

public static void logAlert(String alert) {
log(NameRegistry.SERVER.name(), alert);
}

public static String encodeLogs() {
StringBuilder builder = new StringBuilder();
for (Message msg : CHAT_LOG) builder.append(msg.encode()).append("\036");
return builder.toString();
}

public static Message[] parseLogs(String payload) {
return Arrays.stream(payload.split("\036"))
.map(s -> {
try {
LOG.debug(s);
return Message.decode(s);
} catch (Exception e) {
LOG.warn("Chat-log parsing error: {}", e.getMessage());
return null;
}
})
.filter(Objects::nonNull)
.toArray(Message[]::new);
}

public record Message(String sender, String message) {
@Override
public String toString() {
return sender + ": " + message;
}

public String encode() {
return sender + "\037" + message;
}

public static Message decode(String s) {
String[] parts = s.split("\037");
if (parts.length < 2) return null;
return new Message(parts[0], parts[1]);
}
}
}
3 changes: 2 additions & 1 deletion src/main/java/net/logandhillon/icx/server/ICXServer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.logandhillon.icx.server;

import net.logandhillon.icx.ICX;
import net.logandhillon.icx.common.ICXPacket;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
Expand All @@ -22,7 +23,7 @@ public class ICXServer {

static {
ServerProperties properties = null;
try {
if (ICX.isServer()) try {
properties = ServerProperties.fromDisk();
} catch (Exception e) {
LOG.fatal("ICX server could not be started: {}", e.getMessage());
Expand Down
17 changes: 14 additions & 3 deletions src/main/java/net/logandhillon/icx/server/ServerProperties.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package net.logandhillon.icx.server;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public record ServerProperties(String keystoreFile, String keystorePassword, String roomName) {
public record ServerProperties(String keystoreFile, String keystorePassword, String roomName, int chatLoggerSize) {
public static final String FILENAME = "server.properties";
private static final Logger LOG = LoggerContext.getContext().getLogger(ServerProperties.class);

public static ServerProperties fromDisk() throws IOException, IllegalArgumentException {
Properties properties = new Properties();
Expand All @@ -18,14 +22,21 @@ public static ServerProperties fromDisk() throws IOException, IllegalArgumentExc

String keystoreFile = properties.getProperty("keystore.file");
String keystorePassword = properties.getProperty("keystore.password");
String roomName = properties.getProperty("room.name");
String roomName = properties.getProperty("room.name", "Unnamed chatroom");
int chatLoggerSize = 50;
String _s = properties.getProperty("chat_logger.size");
try {
chatLoggerSize = Integer.parseInt(_s);
} catch (NumberFormatException e) {
LOG.warn("Invalid chat logger size '{}', defaulting to 50", _s);
}

if (keystoreFile == null || keystorePassword == null || keystoreFile.isBlank() || keystorePassword.isBlank())
throw new IllegalArgumentException("missing or blank property in server.properties");

if (!new File(keystoreFile).isFile())
throw new IllegalArgumentException("keystore.file '" + keystoreFile + "' is not a valid file");

return new ServerProperties(keystoreFile, keystorePassword, roomName);
return new ServerProperties(keystoreFile, keystorePassword, roomName, chatLoggerSize);
}
}

0 comments on commit 4f20428

Please sign in to comment.