Added chat history stuff.

This commit is contained in:
Andrew Lalis 2021-08-21 23:57:33 +02:00
parent 468758c7ab
commit 4faba0d2eb
5 changed files with 157 additions and 0 deletions

View File

@ -82,4 +82,13 @@ public interface Message {
if (read != length) throw new IOException("Not all bytes of a string of length " + length + " could be read.");
return new String(data, StandardCharsets.UTF_8);
}
default void writeEnum(Enum<?> value, DataOutputStream o) throws IOException {
o.writeInt(value.ordinal());
}
default <T extends Enum<?>> T readEnum(Class<T> e, DataInputStream i) throws IOException {
int ordinal = i.readInt();
return e.getEnumConstants()[ordinal];
}
}

View File

@ -0,0 +1,71 @@
package nl.andrewl.concord_core.msg.types;
import lombok.Data;
import lombok.NoArgsConstructor;
import nl.andrewl.concord_core.msg.Message;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* A message which clients can send to the server to request some messages from
* the server's history of all sent messages from a particular source. Every
* request must provide the id of the source that messages should be fetched
* from, in addition to the type of source (channel, thread, dm).
* <p>
* The query string is a specially-formatted string that allows you to
* filter results to only certain messages, using different parameters that
* are separated by the <code>;</code> character.
* </p>
* <p>
* All query parameters are of the form <code>param=value</code>, where
* <code>param</code> is the case-sensitive name of the parameter, and
* <code>value</code> is the value of the parameter.
* </p>
* <p>
* The following query parameters are supported:
* <ul>
* <li><code>count</code> - Fetch up to N messages. Minimum of 1, and
* a server-specific maximum count, usually no higher than 1000.</li>
* <li><code>from</code> - ISO-8601 timestamp indicating the timestamp
* after which messages should be fetched. Only messages after this
* point in time are returned.</li>
* <li><code>to</code> - ISO-8601 timestamp indicating the timestamp
* before which messages should be fetched. Only messages before this
* point in time are returned.</li>
* </ul>
* </p>
* <p>
* Responses to this request are sent via {@link ChatHistoryResponse}, where
* the list of messages is always sorted by the timestamp.
* </p>
*/
@Data
@NoArgsConstructor
public class ChatHistoryRequest implements Message {
public enum Source {CHANNEL, THREAD, DIRECT_MESSAGE}
private long sourceId;
private Source sourceType;
private String query;
@Override
public int getByteCount() {
return Long.BYTES + Integer.BYTES + getByteSize(this.query);
}
@Override
public void write(DataOutputStream o) throws IOException {
o.writeLong(sourceId);
writeEnum(this.sourceType, o);
writeString(this.query, o);
}
@Override
public void read(DataInputStream i) throws IOException {
this.sourceId = i.readLong();
this.sourceType = readEnum(Source.class, i);
this.query = readString(i);
}
}

View File

@ -0,0 +1,54 @@
package nl.andrewl.concord_core.msg.types;
import lombok.Data;
import lombok.NoArgsConstructor;
import nl.andrewl.concord_core.msg.Message;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
/**
* The response that a server sends to a {@link ChatHistoryRequest}.
*/
@Data
@NoArgsConstructor
public class ChatHistoryResponse implements Message {
private long sourceId;
private ChatHistoryRequest.Source sourceType;
List<Chat> messages;
@Override
public int getByteCount() {
int count = Long.BYTES + Integer.BYTES + Integer.BYTES;
for (var message : this.messages) {
count += message.getByteCount();
}
return count;
}
@Override
public void write(DataOutputStream o) throws IOException {
o.writeLong(this.sourceId);
writeEnum(this.sourceType, o);
o.writeInt(messages.size());
for (var message : this.messages) {
message.write(o);
}
}
@Override
public void read(DataInputStream i) throws IOException {
this.sourceId = i.readInt();
this.sourceType = readEnum(ChatHistoryRequest.Source.class, i);
int messageCount = i.readInt();
Chat[] messages = new Chat[messageCount];
for (int k = 0; k < messageCount; k++) {
Chat c = new Chat();
c.read(i);
messages[k] = c;
}
this.messages = List.of(messages);
}
}

View File

@ -5,6 +5,7 @@ import lombok.extern.java.Log;
import nl.andrewl.concord_core.msg.Message;
import nl.andrewl.concord_core.msg.Serializer;
import nl.andrewl.concord_core.msg.types.Chat;
import nl.andrewl.concord_core.msg.types.ChatHistoryRequest;
import nl.andrewl.concord_core.msg.types.Identification;
import nl.andrewl.concord_core.msg.types.ServerWelcome;
@ -65,6 +66,8 @@ public class ClientThread extends Thread {
var msg = Serializer.readMessage(this.in);
if (msg instanceof Chat chat) {
this.server.handleChat(chat);
} else if (msg instanceof ChatHistoryRequest historyRequest) {
this.server.handleHistoryRequest(historyRequest, this);
}
} catch (IOException e) {
log.info("Client disconnected: " + e.getMessage());

View File

@ -3,6 +3,9 @@ package nl.andrewl.concord_server;
import lombok.extern.java.Log;
import nl.andrewl.concord_core.msg.Serializer;
import nl.andrewl.concord_core.msg.types.Chat;
import nl.andrewl.concord_core.msg.types.ChatHistoryRequest;
import org.dizitart.no2.Document;
import org.dizitart.no2.Nitrite;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@ -19,10 +22,14 @@ public class ConcordServer implements Runnable {
private final Map<Long, ClientThread> clients = new ConcurrentHashMap<>(32);
private final int port;
private final Random random;
private final Nitrite db;
public ConcordServer(int port) {
this.port = port;
this.random = new SecureRandom();
this.db = Nitrite.builder()
.filePath("concord-server.db")
.openOrCreate();
}
public long registerClient(ClientThread clientThread) {
@ -37,6 +44,15 @@ public class ConcordServer implements Runnable {
}
public void handleChat(Chat chat) {
var collection = db.getCollection("channel-TEST");
long messageId = this.random.nextLong();
Document doc = Document.createDocument(Long.toHexString(messageId), "message")
.put("senderId", Long.toHexString(chat.getSenderId()))
.put("senderNickname", chat.getSenderNickname())
.put("timestamp", chat.getTimestamp())
.put("message", chat.getMessage());
collection.insert(doc);
db.commit();
System.out.println(chat.getSenderNickname() + ": " + chat.getMessage());
ByteArrayOutputStream baos = new ByteArrayOutputStream(chat.getByteCount());
try {
@ -51,6 +67,10 @@ public class ConcordServer implements Runnable {
}
}
public void handleHistoryRequest(ChatHistoryRequest request, ClientThread clientThread) {
}
@Override
public void run() {
ServerSocket serverSocket;