diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 06f3567..445d225 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -71,6 +71,10 @@ public class Client : Thread //TODO: Do something here, tare downs } + public ConnectionInfo getConnInfo() + { + return connInfo; + } /** @@ -101,6 +105,8 @@ public class Client : Thread * User operations (request-response type) */ + // TODO: Add joinChannels(strung[]) + /** * Joins the requested channel * @@ -118,7 +124,8 @@ public class Client : Thread if(channel[0] == '#') { /* Join the channel */ - sendMessage("JOIN "~channel); + Message joinMessage = new Message("", "JOIN", channel); + sendMessage(joinMessage); } else { @@ -187,7 +194,8 @@ public class Client : Thread } /* Leave multiple channels */ - sendMessage("PART "~channelLine); + Message leaveMessage = new Message("", "PART", channelLine); + sendMessage(leaveMessage); } else { @@ -212,7 +220,8 @@ public class Client : Thread // TODO: Add check for valid and non-empty channel names /* Leave the channel */ - sendMessage("PART "~channel); + Message leaveMessage = new Message("", "PART", channel); + sendMessage(leaveMessage); } /** @@ -269,7 +278,8 @@ public class Client : Thread } /* Send the message */ - sendMessage("PRIVMSG "~recipientLine~" "~message); + Message privMessage = new Message("", "PRIVMSG", recipientLine~" "~message); + sendMessage(privMessage); } else { @@ -306,7 +316,8 @@ public class Client : Thread if(recipient[0] != '#') { /* Send the message */ - sendMessage("PRIVMSG "~recipient~" "~message); + Message privMessage = new Message("", "PRIVMSG", recipient~" "~message); + sendMessage(privMessage); } else { @@ -373,7 +384,8 @@ public class Client : Thread } /* Send to multiple channels */ - sendMessage("PRIVMSG "~channelLine~" "~message); + Message privMessage = new Message("", "PRIVMSG", channelLine~" "~message); + sendMessage(privMessage); } else { @@ -408,7 +420,8 @@ public class Client : Thread if(channel[0] == '#') { /* Send the channel message */ - sendMessage("PRIVMSG "~channel~" "~message); + Message privMessage = new Message("", "PRIVMSG", channel~" "~message); + sendMessage(privMessage); } else { @@ -431,13 +444,8 @@ public class Client : Thread */ public void command(Message message) { - /* Encode according to EBNF format */ - // TODO: Validty check - // TODO: Make `Message.encode()` actually encode instead of empty string - string stringToSend = message.encode(); - /* Send the message */ - sendMessage(stringToSend); + sendMessage(message); } @@ -544,8 +552,9 @@ public class Client : Thread PongEvent pongEvent = cast(PongEvent)e; assert(pongEvent); - string messageToSend = "PONG "~pongEvent.getID(); - client.sendMessage(messageToSend); + // string messageToSend = "PONG "~pongEvent.getID(); + Message pongMessage = new Message("", "PONG", pongEvent.getID()); + client.sendMessage(pongMessage); logger.log("Ponged back with "~pongEvent.getID()); } } @@ -622,28 +631,54 @@ public class Client : Thread /* Enqueue the message to the receive queue */ receiver.rq(message); } + + // /** + // * Sends a message to the server by enqueuing it on + // * the client-side send queue + // * + // * Params: + // * messageOut = the message to send + // */ + // private void sendMessage(string messageOut) + // { + // // TODO: Do message splits here - /** - * TODO: Make send queue which is used on another thread to send messages - * - * This allows us to intrpoduce fakelag and also prioritse pongs (we should - * send them via here) - */ + + // /* Encode the mesage */ + // ubyte[] encodedMessage = encodeMessage(messageOut); + + // /* Enqueue the message to the send queue */ + // sender.sq(encodedMessage); + // } /** * Sends a message to the server by enqueuing it on - * the client-side send queue + * the client-side send queue. + * + * A BirchwoodException is thrown if the messages + * final length exceeds 512 bytes * * Params: - * messageOut = the message to send + * message = the message to send */ - private void sendMessage(string messageOut) + private void sendMessage(Message message) { - /* Encode the mesage */ - ubyte[] encodedMessage = encodeMessage(messageOut); + // TODO: Do message splits here + + /* Encode the message */ + ubyte[] encodedMessage = encodeMessage(message.encode()); - /* Enqueue the message to the send queue */ - sender.sq(encodedMessage); + /* If the message is 512 bytes or less then send */ + if(encodedMessage.length <= 512) + { + /* Enqueue the message to the send queue */ + sender.sq(encodedMessage); + } + /* If above then throw an exception */ + else + { + throw new BirchwoodException(BirchwoodException.ErrorType.COMMAND_TOO_LONG); + } } /** @@ -653,7 +688,7 @@ public class Client : Thread { /* Generate the quit command using the custom quit message */ Message quitCommand = new Message("", "QUIT", connInfo.quitMessage); - sendMessage(quitCommand.encode()); + sendMessage(quitCommand); /* TODO: I don't know how long we should wait here */ Thread.sleep(dur!("seconds")(1)); @@ -830,6 +865,12 @@ public class Client : Thread } } + + version(unittest) + { + import core.thread; + } + unittest { /* FIXME: Get domaina name resolution support */ @@ -837,15 +878,19 @@ public class Client : Thread //freenode: 149.28.246.185 //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 - ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.deavmi.crxn", 6667, "testBirchwood"); + ConnectionInfo connInfo = ConnectionInfo.newConnection("worcester.community.networks.deavmi.assigned.network", 6667, "testBirchwood"); + + // // Set the fakelag to 1 second + // connInfo.setFakeLag(1); + + // Create a new Client Client client = new Client(connInfo); client.connect(); - import core.thread; Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "NICK", "birchwood")); + client.command(new Message("", "NICK", "birchwood")); // TODO: add nickcommand Thread.sleep(dur!("seconds")(2)); client.command(new Message("", "USER", "doggie doggie irc.frdeenode.net :Tristan B. Kildaire")); @@ -860,13 +905,13 @@ public class Client : Thread client.joinChannel("#birchwoodLeave3"); Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "NAMES", "")); + client.command(new Message("", "NAMES", "")); // TODO: add names commdn Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "PRIVMSG", "#birchwood naai")); + client.channelMessage("naai", "#birchwood"); Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "PRIVMSG", "deavmi naai")); + client.directMessage("naai", "deavmi"); /** diff --git a/source/birchwood/client/exceptions.d b/source/birchwood/client/exceptions.d index 816e154..4aaac53 100644 --- a/source/birchwood/client/exceptions.d +++ b/source/birchwood/client/exceptions.d @@ -13,7 +13,8 @@ public class BirchwoodException : Exception EMPTY_PARAMS, INVALID_CHANNEL_NAME, INVALID_NICK_NAME, - ILLEGAL_CHARACTERS + ILLEGAL_CHARACTERS, + COMMAND_TOO_LONG } private ErrorType errType; diff --git a/source/birchwood/client/receiver.d b/source/birchwood/client/receiver.d index 94b3bc2..93be2e8 100644 --- a/source/birchwood/client/receiver.d +++ b/source/birchwood/client/receiver.d @@ -126,10 +126,14 @@ public final class ReceiverThread : Thread ulong pos = 0; foreach(ubyte[] message; recvQueue[]) { + // FIXME: Holy shit this is funny (see https://github.com/deavmi/birchwood/issues/13) if(indexOf(cast(string)message, "PING") > -1) { pingMessage = message; recvQueue.linearRemoveElement(message); + + import std.stdio; + writeln("\n\nHOLY SHIT\n: "~cast(string)(message)~"\n\n"); break; } diff --git a/source/birchwood/client/sender.d b/source/birchwood/client/sender.d index 2db0b65..8f22468 100644 --- a/source/birchwood/client/sender.d +++ b/source/birchwood/client/sender.d @@ -79,9 +79,6 @@ public final class SenderThread : Thread */ private void sendHandlerFunc() { - /* TODO: Hoist up into ConnInfo */ - ulong fakeLagInBetween = 1; - while(client.running) { // // Do a once-off call to `ensure()` here which then only runs once and @@ -115,7 +112,7 @@ public final class SenderThread : Thread foreach(ubyte[] message; sendQueue[]) { client.socket.send(message); - Thread.sleep(dur!("seconds")(fakeLagInBetween)); + Thread.sleep(dur!("seconds")(client.getConnInfo().getFakeLag())); } /* Empty the send queue */ diff --git a/source/birchwood/config/conninfo.d b/source/birchwood/config/conninfo.d index d1fee31..ce2b9be 100644 --- a/source/birchwood/config/conninfo.d +++ b/source/birchwood/config/conninfo.d @@ -14,7 +14,7 @@ public struct ConnectionInfo private ulong bulkReadSize; /* Client behaviour (TODO: what is sleep(0), like nothing) */ - private ulong fakeLag = 0; + private ulong fakeLag; /* The quit message */ public const string quitMessage; @@ -26,6 +26,9 @@ public struct ConnectionInfo this.nickname = nickname; this.bulkReadSize = bulkReadSize; this.quitMessage = quitMessage; + + // Set the default fakelag to 1 + this.fakeLag = 1; } public ulong getBulkReadSize() @@ -38,6 +41,16 @@ public struct ConnectionInfo return addrInfo; } + public ulong getFakeLag() + { + return fakeLag; + } + + public void setFakeLag(ulong fakeLag) + { + this.fakeLag = fakeLag; + } + /** * Creates a ConnectionInfo struct representing a client configuration which * can be provided to the Client class to create a new connection based on its diff --git a/source/birchwood/protocol/formatting.d b/source/birchwood/protocol/formatting.d new file mode 100644 index 0000000..b0abaff --- /dev/null +++ b/source/birchwood/protocol/formatting.d @@ -0,0 +1,2 @@ +module birchwood.protocol.formatting; + diff --git a/source/birchwood/protocol/messages.d b/source/birchwood/protocol/messages.d index 101033d..590335c 100644 --- a/source/birchwood/protocol/messages.d +++ b/source/birchwood/protocol/messages.d @@ -30,7 +30,16 @@ __gshared static this() /** * Encoding/decoding primitives */ -public static ubyte[] encodeMessage(string messageIn) + +/** + * Encodes the provided message into a CRLF + * terminated byte array + * + * Params: + * messageIn = the message to encode + * Returns: the encoded message + */ +public ubyte[] encodeMessage(string messageIn) { ubyte[] messageOut = cast(ubyte[])messageIn; messageOut~=[cast(ubyte)13, cast(ubyte)10]; diff --git a/source/birchwood/protocol/package.d b/source/birchwood/protocol/package.d index 073ce31..0853c26 100644 --- a/source/birchwood/protocol/package.d +++ b/source/birchwood/protocol/package.d @@ -1,3 +1,6 @@ module birchwood.protocol; -public import birchwood.protocol.messages : Message; \ No newline at end of file +public import birchwood.protocol.messages : Message; + +// TODO: Look how to neaten up (if any) +public import birchwood.protocol.formatting; \ No newline at end of file