besterd/source/handlers/response.d

235 lines
6.4 KiB
D

module handlers.response;
import std.json : JSONValue, JSONException, parseJSON;
import std.conv : to;
import utils.debugging : debugPrint;
import std.string : cmp;
import std.stdio : writeln;
import connection.connection;
import base.types;
import std.socket : Socket,SocketOSException;
import connection.message;
/* The type of the command the message handler wants us to run */
private enum CommandType
{
SEND_CLIENTS, SEND_SERVERS, SEND_HANDLER
}
public final class HandlerResponse
{
/* The message-handler's response */
private JSONValue messageResponse;
/* The command to be executed */
private CommandType commandType;
this(JSONValue messageResponse)
{
/* Set the message-handler's response message */
this.messageResponse = messageResponse;
/* Attempt parsing the message and error checking it */
parse(messageResponse);
}
private void parse(JSONValue handlerResponse)
{
/**
* Handles the response sent back to the server from the
* message handler.
*/
/* Get the status */
ulong statusCode;
/* Error? */
bool error;
/* TODO: Bounds checking, type checking */
try
{
/* Get the header block */
JSONValue headerBlock = handlerResponse["header"];
/* Get the status */
statusCode = to!(ulong)(headerBlock["status"].str());
debugPrint("Status code: " ~ to!(string)(statusCode));
/* If the status is 0, then it is all fine */
if(statusCode == 0)
{
debugPrint("Status is fine, the handler ran correctly");
/* The command block */
JSONValue commandBlock = headerBlock["command"];
/**
* Get the command that the message handler wants the
* server to run.
*/
string serverCommand = commandBlock["type"].str;
debugPrint("Handler->Server command: \"" ~ serverCommand ~ "\"");
/* Check the command to be run */
if(cmp(serverCommand, "sendClients") == 0)
{
/* Set the command type to SEND_CLIENTS */
commandType = CommandType.SEND_CLIENTS;
/* TODO: Error check and do accesses JSON that would be done in `.execute` */
}
else if(cmp(serverCommand, "sendServers") == 0)
{
/* Set the command type to SEND_SERVERS */
commandType = CommandType.SEND_SERVERS;
/* TODO: Error check and do accesses JSON that would be done in `.execute` */
}
else if(cmp(serverCommand, "sendHandler") == 0)
{
/* Set the command type to SEND_HAANDLER */
commandType = CommandType.SEND_HANDLER;
/* TODO: Error check and do accesses JSON that would be done in `.execute` */
}
else
{
/* TODO: Error handling */
debugPrint("The message handler is using an invalid command");
}
}
else
{
/* If the message handler returned a response in error */
debugPrint("Message handler returned an error code: " ~ to!(string)(statusCode));
error = true;
}
}
catch(JSONException exception)
{
debugPrint("<<< There was an error handling the response message >>>\n\n" ~ exception.toString());
error = true;
}
/**
* If an error was envountered anyway down the processing of the
* message-handler then raise a `ResponseError` exception.
*/
if(error)
{
throw new ResponseError(messageResponse, statusCode);
}
}
public void execute(BesterConnection originalRequester)
{
/* TODO: Implement me */
/* If the command is SEND_CLIENTS */
if(commandType == CommandType.SEND_CLIENTS)
{
/* Get the list of clients to send to */
string[] clients;
JSONValue[] clientList = messageResponse["header"]["command"]["data"].array();
for(ulong i = 0; i < clientList.length; i++)
{
clients ~= clientList[i].str();
}
debugPrint("Users wanting to send to: " ~ to!(string)(clients));
/* Find the users that are wanting to be sent to */
BesterConnection[] connectionList = originalRequester.server.getClients(clients);
// debugPrint("Users matched online on server: " ~ to!(string)(connectionList));
/* TODO: Implement me */
/* TODO: Construct a payload for the receiving clients */
JSONValue clientPayload;
JSONValue headerBlock;
//headerBlock["handlerName"] =
clientPayload["header"] = 2;
/**
* Loop through each BesterConnection in connectionList and
* send the message-handler payload response message to each
* of them.
*/
for(ulong i = 0; i < connectionList.length; i++)
{
/* Get the conneciton */
BesterConnection clientConnection = connectionList[i];
try
{
/* Get the client's socket */
Socket clientSocket = clientConnection.getSocket();
//debugPrint("IsAlive?: " ~ to!(string)(clientSocket.isAlive()));
/* Send the message to the client */
debugPrint("Sending handler's response to client \"" ~ clientConnection.toString() ~ "\"...");
sendMessage(clientSocket, clientPayload);
debugPrint("Sending handler's response to client \"" ~ clientConnection.toString() ~ "\"... [sent]");
}
catch(SocketOSException exception)
{
/**
* If there was an error sending to the client, this can happen
* if the client has disconnected but hasn't yet been removed from
* the connections array and hence we try to send on a dead socket
* or get the remoteAddress on a dead socket, which causes a
* SocketOSException to be called.
*/
debugPrint("Attempted interacting with dead socket");
}
}
debugPrint("SEND_CLIENTS: Completed run");
}
else if (commandType == CommandType.SEND_SERVERS)
{
/* Get the list of servers to send to */
string[] servers;
JSONValue[] serverList = messageResponse["header"]["command"]["data"].array();
for(ulong i = 0; i < serverList.length; i++)
{
servers ~= serverList[i].str();
}
/* TODO: Implement me */
writeln("Servers wanting to send to ", servers);
}
else if (commandType == CommandType.SEND_HANDLER)
{
/* Name of the handler to send the message to */
string handler = messageResponse["header"]["command"]["data"]["handler"].str();
debugPrint("Handler to forward to: " ~ handler);
/* TODO: Add me */
}
}
override public string toString()
{
return messageResponse.toPrettyString();
}
}
public final class ResponseError : BesterException
{
/* */
/* The status code that resulted in the response handling error */
private ulong statusCode;
this(JSONValue messageResponse, ulong statusCode)
{
/* TODO: Set message afterwards again */
super("");
}
}