Added chat history stuff.
This commit is contained in:
parent
468758c7ab
commit
4faba0d2eb
|
@ -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.");
|
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);
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import lombok.extern.java.Log;
|
||||||
import nl.andrewl.concord_core.msg.Message;
|
import nl.andrewl.concord_core.msg.Message;
|
||||||
import nl.andrewl.concord_core.msg.Serializer;
|
import nl.andrewl.concord_core.msg.Serializer;
|
||||||
import nl.andrewl.concord_core.msg.types.Chat;
|
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.Identification;
|
||||||
import nl.andrewl.concord_core.msg.types.ServerWelcome;
|
import nl.andrewl.concord_core.msg.types.ServerWelcome;
|
||||||
|
|
||||||
|
@ -65,6 +66,8 @@ public class ClientThread extends Thread {
|
||||||
var msg = Serializer.readMessage(this.in);
|
var msg = Serializer.readMessage(this.in);
|
||||||
if (msg instanceof Chat chat) {
|
if (msg instanceof Chat chat) {
|
||||||
this.server.handleChat(chat);
|
this.server.handleChat(chat);
|
||||||
|
} else if (msg instanceof ChatHistoryRequest historyRequest) {
|
||||||
|
this.server.handleHistoryRequest(historyRequest, this);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.info("Client disconnected: " + e.getMessage());
|
log.info("Client disconnected: " + e.getMessage());
|
||||||
|
|
|
@ -3,6 +3,9 @@ package nl.andrewl.concord_server;
|
||||||
import lombok.extern.java.Log;
|
import lombok.extern.java.Log;
|
||||||
import nl.andrewl.concord_core.msg.Serializer;
|
import nl.andrewl.concord_core.msg.Serializer;
|
||||||
import nl.andrewl.concord_core.msg.types.Chat;
|
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.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
@ -19,10 +22,14 @@ public class ConcordServer implements Runnable {
|
||||||
private final Map<Long, ClientThread> clients = new ConcurrentHashMap<>(32);
|
private final Map<Long, ClientThread> clients = new ConcurrentHashMap<>(32);
|
||||||
private final int port;
|
private final int port;
|
||||||
private final Random random;
|
private final Random random;
|
||||||
|
private final Nitrite db;
|
||||||
|
|
||||||
public ConcordServer(int port) {
|
public ConcordServer(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.random = new SecureRandom();
|
this.random = new SecureRandom();
|
||||||
|
this.db = Nitrite.builder()
|
||||||
|
.filePath("concord-server.db")
|
||||||
|
.openOrCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long registerClient(ClientThread clientThread) {
|
public long registerClient(ClientThread clientThread) {
|
||||||
|
@ -37,6 +44,15 @@ public class ConcordServer implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleChat(Chat chat) {
|
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());
|
System.out.println(chat.getSenderNickname() + ": " + chat.getMessage());
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(chat.getByteCount());
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(chat.getByteCount());
|
||||||
try {
|
try {
|
||||||
|
@ -51,6 +67,10 @@ public class ConcordServer implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleHistoryRequest(ChatHistoryRequest request, ClientThread clientThread) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ServerSocket serverSocket;
|
ServerSocket serverSocket;
|
||||||
|
|
Loading…
Reference in New Issue