Merge branch 'threaded_sender' into develop

This commit is contained in:
Tristan B. Kildaire 2021-01-23 19:25:03 +02:00
commit f7909c3562
2 changed files with 192 additions and 96 deletions

View File

@ -21,7 +21,7 @@ public final class ButterflyClient : Thread
/**
* The associated listener
*/
private ButterflyListener listener;
public ButterflyListener listener;
/**
* Socket of the client connection
@ -48,7 +48,7 @@ public final class ButterflyClient : Thread
* The Mailbox (if client) of the connected
* user.
*/
private Mailbox mailbox;
public Mailbox mailbox;
this(ButterflyListener listener, Socket clientSocket)
{
@ -638,7 +638,7 @@ public final class ButterflyClient : Thread
* Sends the mail message `mail` to the servers
* listed in the recipients field.
*/
private void sendMail(JSONValue mailBlock)
public void sendMail(JSONValue mailBlock)
{
/* Filter the mail */
bool reject = filterMailOutgoing(&mailBlock);
@ -660,6 +660,9 @@ public final class ButterflyClient : Thread
/* List of server's failed to deliver to */
string[] failedRecipients;
/* List of remote recipients */
string[] remoteRecipients;
/* Send the mail to each of the recipients */
foreach(string recipient; recipients)
{
@ -685,7 +688,9 @@ public final class ButterflyClient : Thread
/* TODO: Add failed delivery here too */
if(!Mailbox.isMailbox(username))
{
goto deliveryFailed;
/* Append failed recipient to array of failed recipients */
failedRecipients ~= recipient;
continue;
}
/* Get the Mailbox of a given user */
@ -708,105 +713,22 @@ public final class ButterflyClient : Thread
}
else
{
/* TODO: Do remote mail delivery */
gprintln("Remote delivery occurring...");
try
{
/**
* Construct the server message to send to the
* remote server.
*/
JSONValue messageBlock;
messageBlock["command"] = "deliverMail";
JSONValue requestBlock;
requestBlock["mail"] = mailBlock;
messageBlock["request"] = requestBlock;
/* Deliver the mail to the remote server */
Socket remoteServer = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
/* TODO: Add check over here to make sure these are met */
string remoteHost = split(domain, ":")[0];
ushort remotePort = to!(ushort)(split(domain, ":")[1]);
remoteServer.connect(parseAddress(remoteHost, remotePort));
bool sendStatus = sendMessage(remoteServer, cast(byte[])toJSON(messageBlock));
if(!sendStatus)
{
goto deliveryFailed;
}
byte[] receivedBytes;
bool recvStatus = receiveMessage(remoteServer, receivedBytes);
if(!recvStatus)
{
goto deliveryFailed;
}
/* Close the connection with the remote host */
remoteServer.close();
JSONValue responseBlock = parseJSON(cast(string)receivedBytes);
/* TODO: Get ["status"]["code"] code here an act on it */
if(responseBlock["status"]["code"].integer() == 0)
{
gprintln("Message delivered to user "~recipient);
}
else
{
goto deliveryFailed;
}
}
catch(SocketOSException)
{
goto deliveryFailed;
}
catch(JSONException)
{
/* When delivery fails */
deliveryFailed:
gprintln("Error delivering to "~recipient);
/* Append failed recipient to array of failed recipients */
failedRecipients ~= recipient;
continue;
}
/* Tally up all non-local recipients for off-thread delivery */
remoteRecipients ~= recipient;
}
gprintln("Sent mail message to "~recipient);
}
gprintln("Mail delivered");
import client.sender : MailSender;
/**
* If there are failed sends then send an error message
* to the sender.
* Create a new MailSender for delivering remote mail
* off of this thread
*/
if(failedRecipients.length)
{
/* Create the error message */
JSONValue deliveryReport;
JSONValue[] errorRecipients = [JSONValue(mailbox.username~"@"~listener.getDomain())];
deliveryReport["recipients"] = errorRecipients;
MailSender remoteMailSender = new MailSender(remoteRecipients, mailBlock, failedRecipients, this);
/* TODO: Make more indepth, and have copy of the mail that was tried to be sent */
string errorMessage = "There was an error delivery the mail to: "~to!(string)(recipients)~"\n";
errorMessage ~= "\nThe message was:\n\n"~mailBlock.toPrettyString();
deliveryReport["message"] = errorMessage;
gprintln(deliveryReport);
/* Deliver the error message */
sendMail(deliveryReport);
gprintln("Mail delivery report sent: "~deliveryReport.toPrettyString());
}
gprintln("Mail delivered (there may be remote mail delivery ongoing)");
/* Store the message in this user's "Sent" folder */

View File

@ -1,6 +1,13 @@
module client.sender;
import core.thread;
import std.json : JSONValue, JSONException, parseJSON, toJSON;
import bmessage;
import std.socket;
import gogga;
import std.string;
import std.conv : to;
import client.client;
/**
* The MailSender class is used to instantiate an object
@ -11,8 +18,175 @@ import core.thread;
*/
public final class MailSender : Thread
{
/**
* Delivery information
*/
private string[] remoteRecipients;
private JSONValue mailBlock;
/* Failed recipients (at the beginning it will be only local) */
private string[] failedRecipients;
private ButterflyClient client;
/**
* Constructs a new MailSender with the given
* email to be delivered (remotely)
*/
}
this(string[] remoteRecipients, JSONValue mailBlock, string[] failedRecipients, ButterflyClient client)
{
/* Set the worker function */
super(&run);
/* Save delivery information */
this.remoteRecipients = remoteRecipients;
this.mailBlock = mailBlock;
/* Save the failed local recipients */
this.failedRecipients = failedRecipients;
this.client = client;
/* Start the delivery */
start();
}
/**
* Does the remote mail delivery
*/
private void remoteDeliver()
{
/* Deliver mail to each recipient */
foreach (string remoteRecipient; remoteRecipients)
{
/* TODO: Do remote mail delivery */
gprintln("Remote delivery occurring...");
/* Get the mail address */
string[] mailAddress = split(remoteRecipient, "@");
/* Get the username */
string username = mailAddress[0];
/* Get the domain */
string domain = mailAddress[1];
try
{
/**
* Construct the server message to send to the
* remote server.
*/
JSONValue messageBlock;
messageBlock["command"] = "deliverMail";
JSONValue requestBlock;
requestBlock["mail"] = mailBlock;
messageBlock["request"] = requestBlock;
/* Deliver the mail to the remote server */
Socket remoteServer = new Socket(AddressFamily.INET,
SocketType.STREAM, ProtocolType.TCP);
/* TODO: Add check over here to make sure these are met */
string remoteHost = split(domain, ":")[0];
ushort remotePort = to!(ushort)(split(domain, ":")[1]);
remoteServer.connect(parseAddress(remoteHost, remotePort));
bool sendStatus = sendMessage(remoteServer, cast(byte[]) toJSON(messageBlock));
if (!sendStatus)
{
goto deliveryFailed;
}
byte[] receivedBytes;
bool recvStatus = receiveMessage(remoteServer, receivedBytes);
if (!recvStatus)
{
goto deliveryFailed;
}
/* Close the connection with the remote host */
remoteServer.close();
JSONValue responseBlock = parseJSON(cast(string) receivedBytes);
/* TODO: Get ["status"]["code"] code here an act on it */
if (responseBlock["status"]["code"].integer() == 0)
{
gprintln("Message delivered to user " ~ remoteRecipient);
}
else
{
goto deliveryFailed;
}
}
catch (SocketOSException)
{
goto deliveryFailed;
}
catch (JSONException)
{
/* When delivery fails */
deliveryFailed:
gprintln("Error delivering to " ~ remoteRecipient);
/* Append failed recipient to array of failed recipients */
failedRecipients ~= remoteRecipient;
continue;
}
}
gprintln("Sent mail message to " ~ remoteRecipients);
}
/**
* Sends a mail message to the sender's INbox specifying that there
* was a mail delivery failure to one or more of the provided addresses
*/
private void mailReport()
{
/* Create the error message */
JSONValue deliveryReport;
JSONValue[] errorRecipients = [
JSONValue(client.mailbox.username ~ "@" ~ client.listener.getDomain())
];
deliveryReport["recipients"] = errorRecipients;
/* TODO: Make more indepth, and have copy of the mail that was tried to be sent */
/* Get a list of the recipients of the mail message */
string[] recipients;
foreach(JSONValue recipient; mailBlock["recipients"].array())
{
recipients ~= recipient.str();
}
string errorMessage = "There was an error delivery the mail to: " ~ to!(
string)(recipients) ~ "\n";
errorMessage ~= "\nThe message was:\n\n" ~ mailBlock.toPrettyString();
deliveryReport["message"] = errorMessage;
gprintln(deliveryReport);
/* Deliver the error message */
client.sendMail(deliveryReport);
gprintln("Mail delivery report sent: " ~ deliveryReport.toPrettyString());
}
private void run()
{
/* Do the remote mail delivery */
remoteDeliver();
/* If there were failed recipients send a report to the sender */
if (failedRecipients.length)
{
/* Send the mail report */
mailReport();
}
}
}