2020-04-16 15:02:34 +02:00
|
|
|
module server.types;
|
|
|
|
|
2020-04-16 16:35:07 +02:00
|
|
|
import utils.debugging : debugPrint;
|
|
|
|
import std.conv : to;
|
2020-04-16 17:50:10 +02:00
|
|
|
import std.socket : Socket, AddressFamily, SocketType, ProtocolType, parseAddress, SocketFlags;
|
2020-04-16 17:05:56 +02:00
|
|
|
import core.thread : Thread;
|
2020-04-17 18:47:05 +02:00
|
|
|
import std.stdio : writeln, File;
|
2020-04-18 15:25:22 +02:00
|
|
|
import std.json : JSONValue, parseJSON, JSONException, JSONType, toJSON;
|
2020-04-17 14:50:12 +02:00
|
|
|
import std.string : cmp;
|
|
|
|
import server.handler;
|
2020-04-16 16:35:07 +02:00
|
|
|
|
2020-04-16 15:02:34 +02:00
|
|
|
public class BesterServer
|
|
|
|
{
|
2020-04-17 13:46:54 +02:00
|
|
|
/**
|
|
|
|
* Message handlers
|
|
|
|
*
|
|
|
|
* Associative array of `payloadType (string)`:`MessageHandler`
|
|
|
|
* TODO: Implement this
|
|
|
|
*/
|
2020-04-17 22:24:08 +02:00
|
|
|
private MessageHandler[] handlers;
|
2020-04-16 16:35:07 +02:00
|
|
|
|
2020-04-16 16:39:31 +02:00
|
|
|
/* The server's socket */
|
|
|
|
private Socket serverSocket;
|
|
|
|
|
2020-04-17 20:23:22 +02:00
|
|
|
this(JSONValue config)
|
2020-04-16 16:35:07 +02:00
|
|
|
{
|
2020-04-17 20:23:22 +02:00
|
|
|
|
2020-04-17 20:40:02 +02:00
|
|
|
/* TODO: Bounds check and JSON type check */
|
2020-04-17 20:23:22 +02:00
|
|
|
debugPrint("Setting up socket...");
|
|
|
|
setupServerSocket(config["network"]);
|
2020-04-17 20:40:02 +02:00
|
|
|
|
|
|
|
/* TODO: Bounds check and JSON type check */
|
2020-04-17 18:47:05 +02:00
|
|
|
debugPrint("Setting up message handlers...");
|
2020-04-17 20:40:02 +02:00
|
|
|
setupHandlers(config["handlers"]);
|
2020-04-16 16:39:31 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 20:40:02 +02:00
|
|
|
private void setupHandlers(JSONValue handlerBlock)
|
2020-04-17 13:46:54 +02:00
|
|
|
{
|
|
|
|
/* TODO: Implement me */
|
2020-04-17 18:07:13 +02:00
|
|
|
debugPrint("Constructing message handlers...");
|
2020-04-17 22:24:08 +02:00
|
|
|
handlers = MessageHandler.constructHandlers(handlerBlock);
|
2020-04-18 16:13:31 +02:00
|
|
|
writeln(handlers[0].getPluginName());
|
2020-04-17 13:46:54 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 20:23:22 +02:00
|
|
|
/* Setup the server socket */
|
|
|
|
private void setupServerSocket(JSONValue networkBlock)
|
2020-04-16 16:39:31 +02:00
|
|
|
{
|
2020-04-17 20:23:22 +02:00
|
|
|
string bindAddress;
|
|
|
|
ushort listenPort;
|
|
|
|
|
|
|
|
JSONValue jsonAddress, jsonPort;
|
|
|
|
|
|
|
|
writeln(networkBlock);
|
|
|
|
|
|
|
|
/* TODO: Bounds check */
|
|
|
|
jsonAddress = networkBlock["address"];
|
|
|
|
jsonPort = networkBlock["port"];
|
|
|
|
|
|
|
|
bindAddress = jsonAddress.str;
|
|
|
|
listenPort = cast(ushort)jsonPort.integer;
|
|
|
|
|
|
|
|
debugPrint("Binding to address: " ~ bindAddress ~ " and port " ~ to!(string)(listenPort));
|
|
|
|
|
2020-04-16 16:39:31 +02:00
|
|
|
/* Create a socket */
|
2020-04-16 16:41:56 +02:00
|
|
|
serverSocket = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
|
2020-04-16 16:43:00 +02:00
|
|
|
serverSocket.bind(parseAddress(bindAddress, listenPort));
|
2020-04-16 16:39:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Start listen loop */
|
|
|
|
public void run()
|
|
|
|
{
|
2020-04-16 16:43:00 +02:00
|
|
|
serverSocket.listen(1); /* TODO: This value */
|
2020-04-16 16:39:31 +02:00
|
|
|
debugPrint("Server listen loop started");
|
2020-04-16 17:05:56 +02:00
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
/* Wait for an incoming connection */
|
|
|
|
Socket clientConnection = serverSocket.accept();
|
|
|
|
|
2020-04-16 17:50:10 +02:00
|
|
|
/* Create a new client connection handler and start its thread */
|
2020-04-16 23:25:22 +02:00
|
|
|
BesterConnection besterConnection = new BesterConnection(clientConnection, this);
|
2020-04-16 17:50:10 +02:00
|
|
|
besterConnection.start();
|
2020-04-16 17:05:56 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-16 23:25:22 +02:00
|
|
|
|
|
|
|
/* Authenticate the user */
|
|
|
|
public bool authenticate(string username, string password)
|
|
|
|
{
|
|
|
|
/* TODO: Implement me */
|
2020-04-17 11:57:06 +02:00
|
|
|
debugPrint("Attempting to authenticate:\n\nUsername: " ~ username ~ "\nPassword: " ~ password);
|
2020-04-16 23:25:22 +02:00
|
|
|
return true;
|
|
|
|
}
|
2020-04-16 17:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private class BesterConnection : Thread
|
|
|
|
{
|
|
|
|
|
|
|
|
/* The socket to the client */
|
|
|
|
private Socket clientConnection;
|
|
|
|
|
2020-04-16 23:25:22 +02:00
|
|
|
/* The server backend */
|
|
|
|
private BesterServer server;
|
|
|
|
|
|
|
|
this(Socket clientConnection, BesterServer server)
|
2020-04-16 17:05:56 +02:00
|
|
|
{
|
|
|
|
/* Save socket and set thread worker function pointer */
|
|
|
|
super(&run);
|
2020-04-16 17:50:10 +02:00
|
|
|
this.clientConnection = clientConnection;
|
2020-04-16 23:25:22 +02:00
|
|
|
this.server = server;
|
2020-04-16 17:50:10 +02:00
|
|
|
|
|
|
|
debugPrint("New client handler spawned for " ~ clientConnection.remoteAddress().toAddrString());
|
2020-04-16 17:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read/send loop */
|
|
|
|
private void run()
|
|
|
|
{
|
2020-04-16 17:50:10 +02:00
|
|
|
/* Receive buffer */
|
|
|
|
byte[] buffer;
|
|
|
|
|
2020-04-16 16:39:31 +02:00
|
|
|
while(true)
|
|
|
|
{
|
2020-04-18 15:04:00 +02:00
|
|
|
/* Byte counter for loop-consumer */
|
|
|
|
uint currentByte = 0;
|
2020-04-16 17:50:10 +02:00
|
|
|
|
2020-04-18 15:04:00 +02:00
|
|
|
/* Bytes received counter */
|
|
|
|
long bytesReceived;
|
|
|
|
|
|
|
|
/* TODO: Add fix here to loop for bytes */
|
|
|
|
while(currentByte < 4)
|
2020-04-16 17:50:10 +02:00
|
|
|
{
|
2020-04-18 15:04:00 +02:00
|
|
|
/* Size buffer */
|
|
|
|
byte[4] tempBuffer;
|
|
|
|
|
|
|
|
/* Read at most 4 bytes */
|
|
|
|
bytesReceived = clientConnection.receive(tempBuffer);
|
|
|
|
|
|
|
|
if(!(bytesReceived > 0))
|
|
|
|
{
|
|
|
|
/* TODO: Handle error here */
|
|
|
|
debugPrint("Error with receiving");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Read the bytes from the temp buffer (as many as was received)
|
|
|
|
* and append them to the *real* buffer.
|
|
|
|
*/
|
|
|
|
buffer ~= tempBuffer[0..bytesReceived];
|
|
|
|
|
|
|
|
/* Increment the byte counter */
|
|
|
|
currentByte += bytesReceived;
|
|
|
|
}
|
2020-04-16 17:50:10 +02:00
|
|
|
}
|
2020-04-18 15:04:00 +02:00
|
|
|
|
2020-04-16 17:50:10 +02:00
|
|
|
/* Get the message length */
|
|
|
|
int messageLength = *(cast(int*)buffer.ptr);
|
2020-04-16 18:15:47 +02:00
|
|
|
writeln("Message length: ", cast(uint)messageLength);
|
2020-04-16 17:50:10 +02:00
|
|
|
|
2020-04-16 18:15:47 +02:00
|
|
|
/* TODO: Testing locally ain't good as stuff arrives way too fast, although not as fast as I can type */
|
|
|
|
/* What must happen is a loop to loop and wait for data */
|
2020-04-16 18:26:53 +02:00
|
|
|
|
|
|
|
/* Full message buffer */
|
|
|
|
byte[] messageBuffer;
|
|
|
|
|
|
|
|
|
2020-04-16 18:30:47 +02:00
|
|
|
/* TODO: Add timeout if we haven't received a message in a certain amount of time */
|
2020-04-18 15:04:00 +02:00
|
|
|
|
|
|
|
/* Reset the current byte counter */
|
|
|
|
currentByte = 0;
|
2020-04-16 18:30:47 +02:00
|
|
|
|
2020-04-18 15:04:00 +02:00
|
|
|
while(currentByte < messageLength)
|
2020-04-16 18:26:53 +02:00
|
|
|
{
|
2020-04-18 19:52:30 +02:00
|
|
|
/**
|
|
|
|
* Receive 20 bytes (at most) at a time and don't dequeue from
|
|
|
|
* the kernel's TCP stack's buffer.
|
|
|
|
*/
|
2020-04-16 18:26:53 +02:00
|
|
|
byte[20] messageBufferPartial;
|
2020-04-18 15:04:00 +02:00
|
|
|
bytesReceived = clientConnection.receive(messageBufferPartial, SocketFlags.PEEK);
|
|
|
|
|
|
|
|
/* Check for receive error */
|
|
|
|
if(!(bytesReceived > 0))
|
|
|
|
{
|
|
|
|
debugPrint("Error receiving");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Make sure we only take [0, messageLength) bytes */
|
|
|
|
if(cast(uint)bytesReceived+currentByte > messageLength)
|
|
|
|
{
|
|
|
|
byte[] remainingBytes;
|
|
|
|
remainingBytes.length = messageLength-currentByte;
|
|
|
|
|
|
|
|
clientConnection.receive(remainingBytes);
|
|
|
|
|
|
|
|
/* Increment counter of received bytes */
|
|
|
|
currentByte += remainingBytes.length;
|
|
|
|
|
|
|
|
/* Append the received bytes to the FULL message buffer */
|
|
|
|
messageBuffer ~= remainingBytes;
|
|
|
|
|
|
|
|
writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Increment counter of received bytes */
|
|
|
|
currentByte += bytesReceived;
|
|
|
|
|
|
|
|
|
|
|
|
/* Append the received bytes to the FULL message buffer */
|
|
|
|
messageBuffer ~= messageBufferPartial[0..bytesReceived];
|
|
|
|
|
|
|
|
/* TODO: Bug when over send, we must not allow this */
|
|
|
|
|
|
|
|
|
|
|
|
writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");
|
|
|
|
|
|
|
|
clientConnection.receive(messageBufferPartial);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2020-04-16 18:26:53 +02:00
|
|
|
}
|
|
|
|
|
2020-04-16 18:46:26 +02:00
|
|
|
/* Process the message */
|
|
|
|
processMessage(messageBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 00:07:41 +02:00
|
|
|
/* TODO: Pass in type and just payload or what */
|
2020-04-17 12:12:07 +02:00
|
|
|
private bool dispatch(string payloadType, JSONValue payload)
|
2020-04-17 00:07:41 +02:00
|
|
|
{
|
2020-04-17 12:12:07 +02:00
|
|
|
/* TODO: Implement me */
|
|
|
|
debugPrint("Dispatching payload [" ~ payloadType ~ "]");
|
|
|
|
debugPrint("Payload: " ~ payload.toPrettyString());
|
2020-04-17 13:46:54 +02:00
|
|
|
|
2020-04-18 19:30:43 +02:00
|
|
|
/* Status of dispatch */
|
|
|
|
bool dispatchStatus = true;
|
|
|
|
|
2020-04-17 22:24:08 +02:00
|
|
|
/* Lookup the payloadType handler */
|
|
|
|
MessageHandler chosenHandler;
|
|
|
|
|
|
|
|
for(uint i = 0; i < server.handlers.length; i++)
|
|
|
|
{
|
2020-04-18 16:13:31 +02:00
|
|
|
if(cmp(server.handlers[i].getPluginName(), payloadType) == 0)
|
2020-04-17 22:24:08 +02:00
|
|
|
{
|
|
|
|
chosenHandler = server.handlers[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 15:04:00 +02:00
|
|
|
|
|
|
|
|
2020-04-17 22:24:08 +02:00
|
|
|
if(chosenHandler)
|
|
|
|
{
|
|
|
|
/* TODO: Send and receive data here */
|
|
|
|
|
2020-04-18 15:04:00 +02:00
|
|
|
/* Handler's UNIX domain socket */
|
|
|
|
Socket handlerSocket = chosenHandler.getSocket();
|
|
|
|
|
2020-04-18 15:25:22 +02:00
|
|
|
|
|
|
|
/* Get the payload as a string */
|
|
|
|
string payloadString = toJSON(payload);
|
|
|
|
|
|
|
|
|
|
|
|
/* Construct the data to send */
|
|
|
|
byte[] sendBuffer;
|
|
|
|
|
|
|
|
/* TODO: Add 4 bytes of payload length encded in little endian */
|
|
|
|
int payloadLength = cast(int)payloadString.length;
|
|
|
|
byte* lengthBytes = cast(byte*)&payloadLength;
|
|
|
|
sendBuffer ~= *(lengthBytes+0);
|
|
|
|
sendBuffer ~= *(lengthBytes+1);
|
|
|
|
sendBuffer ~= *(lengthBytes+2);
|
|
|
|
sendBuffer ~= *(lengthBytes+3);
|
|
|
|
|
|
|
|
/* Add the string bytes */
|
|
|
|
sendBuffer ~= cast(byte[])payloadString;
|
|
|
|
|
2020-04-17 22:24:08 +02:00
|
|
|
/* TODO: Send payload */
|
2020-04-18 15:25:22 +02:00
|
|
|
writeln("Send buffer: ", sendBuffer);
|
2020-04-18 15:04:00 +02:00
|
|
|
|
2020-04-17 22:24:08 +02:00
|
|
|
debugPrint("Sending payload over to handler for \"" ~ chosenHandler.getPluginName() ~ "\".");
|
2020-04-18 16:13:31 +02:00
|
|
|
handlerSocket.send(sendBuffer);
|
2020-04-18 15:04:00 +02:00
|
|
|
|
2020-04-17 22:24:08 +02:00
|
|
|
|
|
|
|
/* TODO: Get response */
|
|
|
|
debugPrint("Waiting for response from handler for \"" ~ chosenHandler.getPluginName() ~ "\".");
|
2020-04-18 16:13:31 +02:00
|
|
|
|
2020-04-18 19:30:43 +02:00
|
|
|
/* Construct a buffer to receive into */
|
|
|
|
byte[] receiveBuffer;
|
|
|
|
|
|
|
|
/* The current byte */
|
|
|
|
uint currentByte = 0;
|
|
|
|
|
|
|
|
/* The amount of bytes received */
|
|
|
|
long bytesReceived;
|
|
|
|
|
|
|
|
/* Loop consume the next 4 bytes */
|
|
|
|
while(currentByte < 4)
|
|
|
|
{
|
|
|
|
/* Temporary buffer */
|
|
|
|
byte[4] tempBuffer;
|
|
|
|
|
|
|
|
/* Read at-most 4 bytes */
|
|
|
|
bytesReceived = handlerSocket.receive(tempBuffer);
|
|
|
|
|
|
|
|
/* If there was an error reading from the socket */
|
|
|
|
if(!(bytesReceived > 0))
|
|
|
|
{
|
|
|
|
/* TODO: Error handling */
|
|
|
|
debugPrint("Error receiving from UNIX domain socket");
|
|
|
|
}
|
|
|
|
/* If there is no error reading from the socket */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add the read bytes to the *real* buffer */
|
|
|
|
receiveBuffer ~= tempBuffer[0..bytesReceived];
|
|
|
|
|
|
|
|
/* Increment the byte counter */
|
|
|
|
currentByte += bytesReceived;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Response message length */
|
|
|
|
int messageLength = *cast(int*)receiveBuffer.ptr;
|
|
|
|
writeln("Message length is: ", cast(uint)messageLength);
|
|
|
|
|
|
|
|
/* Response message buffer */
|
|
|
|
byte[] fullMessage;
|
|
|
|
|
|
|
|
/* Reset the byte counter */
|
|
|
|
currentByte = 0;
|
|
|
|
|
|
|
|
while(currentByte < messageLength)
|
|
|
|
{
|
|
|
|
debugPrint("dhjkh");
|
2020-04-18 19:52:30 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive 20 bytes (at most) at a time and don't dequeue from
|
|
|
|
* the kernel's TCP stack's buffer.
|
|
|
|
*/
|
|
|
|
byte[20] tempBuffer;
|
|
|
|
bytesReceived = handlerSocket.receive(tempBuffer, SocketFlags.PEEK);
|
|
|
|
|
|
|
|
/* Check for an error whilst receiving */
|
|
|
|
if(!(bytesReceived > 0))
|
|
|
|
{
|
|
|
|
/* TODO: Error handling */
|
|
|
|
debugPrint("Error whilst receiving from unix domain socket");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Make sure we only take [0, messageLength) bytes */
|
|
|
|
if(cast(uint)bytesReceived+currentByte > messageLength)
|
|
|
|
{
|
|
|
|
byte[] remainingBytes;
|
|
|
|
remainingBytes.length = messageLength-currentByte;
|
|
|
|
|
|
|
|
handlerSocket.receive(remainingBytes);
|
|
|
|
|
|
|
|
/* Increment counter of received bytes */
|
|
|
|
currentByte += remainingBytes.length;
|
|
|
|
|
|
|
|
/* Append the received bytes to the FULL message buffer */
|
|
|
|
fullMessage ~= remainingBytes;
|
|
|
|
|
|
|
|
writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Increment counter of received bytes */
|
|
|
|
currentByte += bytesReceived;
|
|
|
|
|
|
|
|
|
|
|
|
/* Append the received bytes to the FULL message buffer */
|
|
|
|
fullMessage ~= tempBuffer[0..bytesReceived];
|
|
|
|
|
|
|
|
/* TODO: Bug when over send, we must not allow this */
|
|
|
|
|
|
|
|
|
|
|
|
writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");
|
|
|
|
|
|
|
|
handlerSocket.receive(tempBuffer);
|
|
|
|
}
|
|
|
|
}
|
2020-04-18 19:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-18 19:52:30 +02:00
|
|
|
writeln("MEssage ", fullMessage);
|
2020-04-18 19:30:43 +02:00
|
|
|
|
|
|
|
//int messageLength = 0;
|
2020-04-18 16:13:31 +02:00
|
|
|
|
|
|
|
/* TODO: Loop for collect message */
|
2020-04-18 19:30:43 +02:00
|
|
|
|
2020-04-18 20:10:16 +02:00
|
|
|
/* TODO: So now we have to think about what the hell it means
|
|
|
|
* for a response to be received, like cool and all, but we need
|
|
|
|
* the server to now do something.
|
|
|
|
*/
|
|
|
|
|
2020-04-18 19:30:43 +02:00
|
|
|
|
|
|
|
/* TODO: Set dispatchStatus */
|
2020-04-17 22:24:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Error handling */
|
|
|
|
debugPrint("No message handler for payload type \"" ~ payloadType ~ "\" found.");
|
2020-04-18 19:30:43 +02:00
|
|
|
dispatchStatus = false;
|
2020-04-17 22:24:08 +02:00
|
|
|
}
|
2020-04-17 12:12:07 +02:00
|
|
|
|
2020-04-17 00:07:41 +02:00
|
|
|
/* TODO: Set return value */
|
2020-04-18 19:30:43 +02:00
|
|
|
debugPrint("Dispatch status: " ~ to!(string)(dispatchStatus));
|
|
|
|
|
|
|
|
return dispatchStatus;
|
2020-04-17 00:07:41 +02:00
|
|
|
}
|
|
|
|
|
2020-04-18 22:34:26 +02:00
|
|
|
/* TODO: Version 2 of message dispatcher */
|
|
|
|
private bool dispatchMessage(JSONValue payloadBlock)
|
|
|
|
{
|
|
|
|
/* Status of dispatch */
|
|
|
|
bool dispatchStatus = true;
|
|
|
|
|
|
|
|
/* TODO: Bounds checking, type checking */
|
|
|
|
|
|
|
|
/* Get the payload type */
|
|
|
|
string payloadType = payloadBlock["type"].str;
|
|
|
|
debugPrint("Payload type is \"" ~ payloadType ~ "\"");
|
|
|
|
|
|
|
|
/* Get the payload data */
|
|
|
|
JSONValue payloadData = payloadBlock["data"];
|
|
|
|
|
|
|
|
/* Lookup the payloadType handler */
|
2020-04-18 22:50:47 +02:00
|
|
|
MessageHandler chosenHandler;
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-18 22:50:47 +02:00
|
|
|
for(uint i = 0; i < server.handlers.length; i++)
|
|
|
|
{
|
|
|
|
if(cmp(server.handlers[i].getPluginName(), payloadType) == 0)
|
|
|
|
{
|
|
|
|
chosenHandler = server.handlers[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Continue here */
|
2020-04-18 22:34:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
return dispatchStatus;
|
|
|
|
}
|
|
|
|
|
2020-04-16 18:46:26 +02:00
|
|
|
/* Process the received message */
|
|
|
|
private void processMessage(byte[] messageBuffer)
|
|
|
|
{
|
|
|
|
/* The message as a JSONValue struct */
|
|
|
|
JSONValue jsonMessage;
|
2020-04-18 22:34:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* Attempt to convert the message to JSON */
|
|
|
|
try
|
|
|
|
{
|
|
|
|
/* Convert message to JSON */
|
|
|
|
jsonMessage = parseJSON(cast(string)messageBuffer);
|
|
|
|
debugPrint("<<< Received JSON >>>\n\n" ~ jsonMessage.toPrettyString());
|
|
|
|
|
|
|
|
/* TODO: Bounds checking, type checking */
|
|
|
|
|
|
|
|
/* Get the header */
|
|
|
|
JSONValue headerBlock = jsonMessage["header"];
|
|
|
|
|
2020-04-19 13:16:16 +02:00
|
|
|
/* Get the authentication block */
|
|
|
|
JSONValue authenticationBlock = headerBlock["authentication"];
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-19 13:16:16 +02:00
|
|
|
/* Get the username and password */
|
|
|
|
JSONValue username = authenticationBlock["username"], password = authenticationBlock["password"];
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-19 13:16:16 +02:00
|
|
|
/* Get the payload block */
|
|
|
|
JSONValue payloadBlock = jsonMessage["payload"];
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-19 13:16:16 +02:00
|
|
|
/* Dispatch the message */
|
|
|
|
bool dispatchStatus = dispatchMessage(payloadBlock);
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-19 13:16:16 +02:00
|
|
|
if(dispatchStatus)
|
2020-04-18 22:34:26 +02:00
|
|
|
{
|
2020-04-19 13:16:16 +02:00
|
|
|
debugPrint("Dispatch succeeded");
|
2020-04-18 22:34:26 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Error handling */
|
2020-04-19 13:16:16 +02:00
|
|
|
debugPrint("Dispatching failed...");
|
2020-04-18 22:34:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If thr attempt to convert the message to JSON fails */
|
|
|
|
catch(JSONException exception)
|
|
|
|
{
|
|
|
|
debugPrint("<<< There was an error whilst parsing the JSON message >>>\n\n"~exception.toString());
|
|
|
|
}
|
|
|
|
|
2020-04-18 23:01:47 +02:00
|
|
|
/* TODO: Remove me once v2 is implemented */
|
|
|
|
bool f = true;
|
|
|
|
if(f)
|
|
|
|
{
|
|
|
|
goto skip_v1;
|
|
|
|
}
|
2020-04-18 22:34:26 +02:00
|
|
|
|
2020-04-16 18:46:26 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
/* Convert message to JSON */
|
|
|
|
jsonMessage = parseJSON(cast(string)messageBuffer);
|
|
|
|
writeln("JSON received: ", jsonMessage);
|
2020-04-16 19:16:38 +02:00
|
|
|
|
|
|
|
/* Make sure we have a JSON object */
|
|
|
|
if(jsonMessage.type == JSONType.object)
|
|
|
|
{
|
|
|
|
/* As per spec, look for the "besterHeader" */
|
|
|
|
JSONValue besterHeader;
|
|
|
|
|
|
|
|
/* TODO: Check for out of bounds here */
|
2020-04-16 22:15:24 +02:00
|
|
|
besterHeader = jsonMessage["header"];
|
2020-04-16 19:16:38 +02:00
|
|
|
|
|
|
|
/* Check if it is a JSON object */
|
|
|
|
if(besterHeader.type == JSONType.object)
|
|
|
|
{
|
|
|
|
/* TODO: Add further checks here */
|
2020-04-16 19:28:36 +02:00
|
|
|
|
2020-04-17 00:07:41 +02:00
|
|
|
/* TODO: Bounds check */
|
|
|
|
JSONValue payloadType;
|
|
|
|
|
2020-04-17 11:43:26 +02:00
|
|
|
payloadType = besterHeader["type"];
|
2020-04-17 00:07:41 +02:00
|
|
|
|
|
|
|
/* The payload type must be a string */
|
|
|
|
if(payloadType.type == JSONType.string)
|
|
|
|
{
|
2020-04-17 12:12:07 +02:00
|
|
|
string payloadTypeString = payloadType.str;
|
|
|
|
|
2020-04-17 00:07:41 +02:00
|
|
|
/* TODO: Move everything into this block */
|
2020-04-17 00:20:53 +02:00
|
|
|
/* The header must contain a scope block */
|
|
|
|
JSONValue scopeBlock;
|
2020-04-16 23:04:08 +02:00
|
|
|
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Add bounds check */
|
|
|
|
scopeBlock = besterHeader["scope"];
|
2020-04-16 23:04:08 +02:00
|
|
|
|
2020-04-17 00:20:53 +02:00
|
|
|
/* Make sure the type of the JSON value is string */
|
|
|
|
if(scopeBlock.type == JSONType.string)
|
|
|
|
{
|
|
|
|
/* Get the scope */
|
|
|
|
string scopeString = scopeBlock.str;
|
2020-04-16 23:04:08 +02:00
|
|
|
|
2020-04-17 00:20:53 +02:00
|
|
|
/* If the message is for client<->server */
|
|
|
|
if(cmp(scopeString, "client"))
|
2020-04-16 23:04:08 +02:00
|
|
|
{
|
2020-04-17 00:20:53 +02:00
|
|
|
debugPrint("Scope: client<->server");
|
|
|
|
|
|
|
|
/* The header must contain a authentication JSON object */
|
|
|
|
JSONValue authenticationBlock;
|
|
|
|
|
|
|
|
/* TODO: Check for out of bounds here */
|
|
|
|
authenticationBlock = besterHeader["authentication"];
|
|
|
|
|
|
|
|
/* TODO: Bounds check for both below */
|
|
|
|
JSONValue username, password;
|
|
|
|
username = authenticationBlock["username"];
|
|
|
|
password = authenticationBlock["password"];
|
|
|
|
|
|
|
|
|
|
|
|
if(username.type == JSONType.string && password.type == JSONType.string)
|
2020-04-16 23:25:22 +02:00
|
|
|
{
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Now do some stuff */
|
|
|
|
|
|
|
|
/* TODO: Authenticate the user */
|
|
|
|
string usernameString = username.str;
|
|
|
|
string passwordString = password.str;
|
|
|
|
bool isAuthenticated = server.authenticate(usernameString, passwordString);
|
|
|
|
|
|
|
|
if(isAuthenticated)
|
|
|
|
{
|
|
|
|
debugPrint("Authenticated");
|
2020-04-17 12:12:07 +02:00
|
|
|
|
|
|
|
/* Get the payload */
|
|
|
|
JSONValue payload;
|
|
|
|
|
|
|
|
/* TODO: Bounds check */
|
|
|
|
payload = jsonMessage["payload"];
|
|
|
|
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Dispatch to the correct message handler */
|
2020-04-17 12:12:07 +02:00
|
|
|
dispatch(payloadTypeString, payload);
|
2020-04-17 00:20:53 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Add error handling here */
|
|
|
|
debugPrint("Authentication failure");
|
|
|
|
}
|
2020-04-16 23:25:22 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Add error handling here */
|
2020-04-17 00:20:53 +02:00
|
|
|
debugPrint("Username or password is not a JSON string");
|
2020-04-16 23:25:22 +02:00
|
|
|
}
|
2020-04-16 23:04:08 +02:00
|
|
|
}
|
2020-04-17 00:20:53 +02:00
|
|
|
/* If the message is for server<->server */
|
|
|
|
else if(cmp(scopeString, "server"))
|
|
|
|
{
|
|
|
|
debugPrint("Scope: server<->server");
|
|
|
|
}
|
2020-04-16 23:04:08 +02:00
|
|
|
else
|
|
|
|
{
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Error handling */
|
|
|
|
debugPrint("Unknown scope provided");
|
2020-04-16 23:04:08 +02:00
|
|
|
}
|
2020-04-16 22:56:06 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Handle error */
|
|
|
|
debugPrint("Scope block JSON value not a string");
|
2020-04-16 22:56:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-17 00:20:53 +02:00
|
|
|
/* TODO: Add error handling */
|
|
|
|
debugPrint("Type is not of type JSON string");
|
2020-04-16 22:56:06 +02:00
|
|
|
}
|
2020-04-16 19:16:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Add error handling here */
|
2020-04-16 19:28:36 +02:00
|
|
|
debugPrint("Header received was not a JSON object");
|
2020-04-16 19:16:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* TODO: Add error here */
|
|
|
|
debugPrint("Did not receive a JSON object");
|
|
|
|
}
|
2020-04-16 18:46:26 +02:00
|
|
|
}
|
|
|
|
catch(JSONException exception)
|
|
|
|
{
|
|
|
|
/* TODO: Implement this */
|
2020-04-17 11:43:26 +02:00
|
|
|
debugPrint("Error parsing the received JSON message: " ~ exception.toString());
|
2020-04-16 16:39:31 +02:00
|
|
|
}
|
2020-04-18 23:01:47 +02:00
|
|
|
skip_v1:
|
2020-04-16 16:35:07 +02:00
|
|
|
}
|
2020-04-16 17:05:56 +02:00
|
|
|
|
2020-04-16 15:02:34 +02:00
|
|
|
|
|
|
|
}
|