- Proper encoding/decoding

This commit is contained in:
Tristan B. Velloza Kildaire 2023-05-05 09:45:57 +02:00
parent 8810c1c369
commit 64ba57778a
5 changed files with 134 additions and 28 deletions

View File

@ -1,16 +1,34 @@
module davinci.base.base;
import msgpack;
/**
* This is the base message type for all messages
* in the Renaissance protocol; both client-to-server
* and server-to-server
*/
public abstract class BaseMessage
public class BaseMessage
{
static this()
{
registerPackHandler!(typeof(this), pkr);
registerUnpackHandler!(typeof(this), upkr);
}
/**
* Current version of the protocol in use
*/
private ProtocolVersion protocolVersion;
/**
* The type of message
*/
private MessageType type;
private CommandType commandType;
private Command command;
/**
* Constructs a new base message of the provided
@ -19,9 +37,11 @@ public abstract class BaseMessage
* Params:
* type = the type of message
*/
this(MessageType type)
this(MessageType type, CommandType commandType, Command command)
{
this.type = type;
this.commandType = commandType;
this.command = command;
}
/**
@ -34,6 +54,16 @@ public abstract class BaseMessage
return type;
}
public CommandType getCommandType()
{
return commandType;
}
public Command getCommand()
{
return command;
}
/**
* Encodes this message into the wire format
*
@ -41,9 +71,48 @@ public abstract class BaseMessage
*/
public final byte[] encode()
{
import msgpack;
// FIXME: It won't encode nested classes, so enforce each `Command`
// ... to have an `encode()` that gives byte array then and we should
// ... manually pack here then for that
return cast(byte[])pack(this);
}
public static void pkr(ref Packer packer, ref BaseMessage message)
{
packer.pack(message.protocolVersion);
packer.pack(message.type);
packer.pack(message.commandType);
/* Payload bytes */
byte[] payload = message.getCommand().getEncoded();
packer.pack(payload);
}
public static void upkr(ref Unpacker unpacker, ref BaseMessage message)
{
unpacker.unpack!(ProtocolVersion)(message.protocolVersion);
unpacker.unpack!(MessageType)(message.type);
unpacker.unpack!(CommandType)(message.commandType);
byte[] payload;
unpacker.unpack!(byte[])(payload);
// TODO: Now COmmndType check
if(message.commandType == CommandType.NOP_COMMAND)
{
import davinci.c2s.test : TestMessage;
message.command = Command.decodeTo!(TestMessage)(payload);
}
}
}
public enum ProtocolVersion
{
VERSION_0_PHONK
}
/**
@ -60,4 +129,38 @@ public enum MessageType
* If the message is server-to-server
*/
SERVER_TO_SERVER
}
public abstract class Command
{
private byte[] data;
this(byte[] data)
{
this.data = data;
}
// public abstract byte[] encode();
public final byte[] getEncoded()
{
return data;
}
// TODO: Add a way to enforce that T must be derived from or equal to BaseMessage
public static T decodeTo(T)(byte[] data)
{
// Currently we are using message pack
import msgpack;
return unpack!(T)(cast(ubyte[])data);
}
}
public enum CommandType
{
NOP_COMMAND
}

View File

@ -2,10 +2,10 @@ module davinci.c2s.client;
import davinci.base.base : BaseMessage, MessageType;
public abstract class C2SMessage : BaseMessage
{
this()
{
super(MessageType.CLIENT_TO_SERVER);
}
}
// public abstract class C2SMessage : BaseMessage
// {
// this()
// {
// super(MessageType.CLIENT_TO_SERVER);
// }
// }

View File

@ -4,15 +4,19 @@ import davinci.base.base;
import davinci.c2s.client;
import msgpack;
public class TestMessage : C2SMessage
public class TestMessage : Command
{
private string testField = "ABBA";
private string testField = "ABBAd";
this()
{
import msgpack;
registerClass!(typeof(this));
super(cast(byte[])pack(this));
}
public string getTestField()
{
return testField;
@ -26,7 +30,8 @@ version(unittest)
unittest
{
BaseMessage exampleMessage = new TestMessage();
TestMessage exampleCommand = new TestMessage();
BaseMessage exampleMessage = new BaseMessage(MessageType.CLIENT_TO_SERVER, CommandType.NOP_COMMAND, exampleCommand);
byte[] encodedBytes = exampleMessage.encode();
writeln("Encoded bytes: ", encodedBytes);
@ -38,7 +43,12 @@ unittest
//
// Here we just go ahead and assume it is a TestMessage
// ... kind-of message
TestMessage testMessage = unpack!(TestMessage)(cast(ubyte[])encodedBytes);
writeln(testMessage.getMessageType());
writeln(testMessage.getTestField());
BaseMessage testMessage = unpack!(BaseMessage)(cast(ubyte[])encodedBytes);
writeln(testMessage);
if(testMessage.getCommandType() == CommandType.NOP_COMMAND)
{
TestMessage testCommand = cast(TestMessage)testMessage.getCommand();
writeln(testCommand.getTestField());
}
}

View File

@ -2,10 +2,10 @@ module davinci.s2s.server;
import davinci.base.base : BaseMessage, MessageType;
public class S2SMessage : BaseMessage
public class S2SMessage
{
this()
{
super(MessageType.SERVER_TO_SERVER);
}
// this()
// {
// super(MessageType.SERVER_TO_SERVER);
// }
}

View File

@ -1,9 +1,2 @@
module davinci.tools;
// TODO: Add a way to enforce that T must be derived from or equal to BaseMessage
public T decodeTo(T)(byte[] data)
{
// Currently we are using message pack
import msgpack;
return unpack!(T)(cast(ubyte[])data);
}