From f4a2a750942c73a0160ebf7869e4c4dc4de8719f Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 14 Mar 2023 23:30:19 +0200 Subject: [PATCH 01/15] Formatting - Added module `formatting` to hold formatting subroutines and constants Package - Publically import `birchwood.protocol.formatting` --- source/birchwood/protocol/formatting.d | 2 ++ source/birchwood/protocol/package.d | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 source/birchwood/protocol/formatting.d 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/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 From 1f1796930d2baffd6e26d92110a836c30a3dadd2 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 14 Mar 2023 23:57:40 +0200 Subject: [PATCH 02/15] Messages - Removed implicit `static` - Added documentation to `ubyte[] encodeMessage(string)` --- source/birchwood/protocol/messages.d | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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]; From 12883f93dbff117aaf3ce0899dc7d77ff4e27222 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Tue, 14 Mar 2023 23:58:22 +0200 Subject: [PATCH 03/15] Client - Added a TODO - Removed now-completed TODO --- source/birchwood/client/client.d | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 06f3567..f3264ea 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -622,13 +622,6 @@ public class Client : Thread /* Enqueue the message to the receive queue */ receiver.rq(message); } - - /** - * 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) - */ /** * Sends a message to the server by enqueuing it on @@ -639,6 +632,9 @@ public class Client : Thread */ private void sendMessage(string messageOut) { + // TODO: Do message splits here + + /* Encode the mesage */ ubyte[] encodedMessage = encodeMessage(messageOut); From 256369abc5b40fa9575d9737d5f4d06738c97af0 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:19:07 +0200 Subject: [PATCH 04/15] Client - Implememted `sendMessage(Message)` --- source/birchwood/client/client.d | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index f3264ea..aca2845 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -641,6 +641,22 @@ public class Client : Thread /* 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 + * + * Params: + * message = the message to send + */ + private void sendMessage(Message message) + { + /* Encode the message */ + ubyte[] encodedMessage = message.encode(); + + /* Enqueue the message to the send queue */ + sender.sq(encodedMessage); + } /** * Disconnect from the IRC server gracefully From 11dbd1a96fb0f95a6242f79078a73c8e7de71f8f Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:24:56 +0200 Subject: [PATCH 05/15] Client - Fixed compilation error by adding missing `encodeMessage(string)` call - If the encoded message (CRLF included) is over 512 bytes then throw an exception Exceptions - Added new `ErrorType` enum member --- source/birchwood/client/client.d | 15 ++++++++++++--- source/birchwood/client/exceptions.d | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index aca2845..db03d94 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -652,10 +652,19 @@ public class Client : Thread private void sendMessage(Message message) { /* Encode the message */ - ubyte[] encodedMessage = message.encode(); + 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); + } } /** 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; From 4690c5a6c373b89960aca65d1850d75d3268e2b1 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:32:14 +0200 Subject: [PATCH 06/15] Client - Updated `joinChannel(string)` to use `sendMessage(Message)` - Added TODO relating to implementing `joinChannels(string[])` - `leaveChannel(string[])` now uses the new `sendMessage(Message)` - `leaveChannel(string)` now uses the new `sendMessage(Message)` --- source/birchwood/client/client.d | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index db03d94..b625921 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -101,6 +101,8 @@ public class Client : Thread * User operations (request-response type) */ + // TODO: Add joinChannels(strung[]) + /** * Joins the requested channel * @@ -118,7 +120,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 +190,8 @@ public class Client : Thread } /* Leave multiple channels */ - sendMessage("PART "~channelLine); + Message leaveMessage = new Message("", "PART", channelLine); + sendMessage(leaveMessage); } else { @@ -212,7 +216,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); } /** @@ -651,6 +656,8 @@ public class Client : Thread */ private void sendMessage(Message message) { + // TODO: Do message splits here + /* Encode the message */ ubyte[] encodedMessage = encodeMessage(message.encode()); From 52dbd12a24df0e9f91a5f195d93c2dd7159dd73b Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:36:39 +0200 Subject: [PATCH 07/15] Client - `directMessage(string, string[])` now uses `sendMessage(Message)` - `directMessage(string, string)` now uses `sendMessage(Message)` --- source/birchwood/client/client.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index b625921..72b6aa4 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -274,7 +274,8 @@ public class Client : Thread } /* Send the message */ - sendMessage("PRIVMSG "~recipientLine~" "~message); + Message privMessage = new Message("", "PRIVMSG", recipientLine~" "~message); + sendMessage(privMessage); } else { @@ -311,7 +312,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 { From 2b25f4933a783e59b83ede3da1012564e154d7f3 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:39:38 +0200 Subject: [PATCH 08/15] Client - Both variants of `channelMessage(..., ...)` now use `sendMessage(Message)` --- source/birchwood/client/client.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 72b6aa4..a484e28 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -380,7 +380,8 @@ public class Client : Thread } /* Send to multiple channels */ - sendMessage("PRIVMSG "~channelLine~" "~message); + Message privMessage = new Message("", "PRIVMSG", channelLine~" "~message); + sendMessage(privMessage); } else { @@ -415,7 +416,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 { From 75155795fa989a83407377d25aaac0bcab76a041 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:43:45 +0200 Subject: [PATCH 09/15] Client - Updated `command(Message)` to use `sendMessage(Message)` - Updated the `PongSignal` event handler to use `sendMessage(Message)` when sending the pong back - Make `quit()` use the new `sendMessage(Message)` - Disabled old `sendMessage(string)` --- source/birchwood/client/client.d | 44 +++++++++++++++----------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index a484e28..85dccfe 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -440,13 +440,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); } @@ -553,8 +548,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()); } } @@ -632,24 +628,24 @@ public class Client : Thread 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 + // /** + // * 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 - /* Encode the mesage */ - ubyte[] encodedMessage = encodeMessage(messageOut); + // /* Encode the mesage */ + // ubyte[] encodedMessage = encodeMessage(messageOut); - /* Enqueue the message to the send queue */ - sender.sq(encodedMessage); - } + // /* Enqueue the message to the send queue */ + // sender.sq(encodedMessage); + // } /** * Sends a message to the server by enqueuing it on @@ -685,7 +681,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)); From e4e1aaf0f44d3bb422cd9e541bfbd483a1bc5714 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:46:38 +0200 Subject: [PATCH 10/15] Unit tests - Updated unit test with some TODOs --- source/birchwood/client/client.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 85dccfe..9ede037 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -873,7 +873,7 @@ public class Client : Thread 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")); @@ -888,13 +888,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.command(new Message("", "PRIVMSG", "#birchwood naai")); // TODO: use channel mesge Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "PRIVMSG", "deavmi naai")); + client.command(new Message("", "PRIVMSG", "deavmi naai")); // TODO: use direct message /** From 9f6ab528c2e1c2e8eff048e698eaceb69f5c1932 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:47:40 +0200 Subject: [PATCH 11/15] Client - Updated header documentation for `sendMessage(Message)` --- source/birchwood/client/client.d | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 9ede037..4edde30 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -649,7 +649,10 @@ public class Client : Thread /** * 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: * message = the message to send From a00294989df2ecc1bb48a8c473b8ceeeb47d0874 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:53:51 +0200 Subject: [PATCH 12/15] Client - Unittest now uses IPv6 accessible IRC server - Placed any unittest-related imports into a `version(unittest) { ... }` block --- source/birchwood/client/client.d | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 4edde30..bb0dfd5 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -861,6 +861,12 @@ public class Client : Thread } } + + version(unittest) + { + import core.thread; + } + unittest { /* FIXME: Get domaina name resolution support */ @@ -868,13 +874,12 @@ 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"); Client client = new Client(connInfo); client.connect(); - import core.thread; Thread.sleep(dur!("seconds")(2)); client.command(new Message("", "NICK", "birchwood")); // TODO: add nickcommand From 044625194d5c6bd2bfef41b19104fc229950d707 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 08:56:56 +0200 Subject: [PATCH 13/15] Client - Updated unittests to not use `command(Message)` --- source/birchwood/client/client.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index bb0dfd5..71cdbb7 100644 --- a/source/birchwood/client/client.d +++ b/source/birchwood/client/client.d @@ -899,10 +899,10 @@ public class Client : Thread client.command(new Message("", "NAMES", "")); // TODO: add names commdn Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "PRIVMSG", "#birchwood naai")); // TODO: use channel mesge + client.channelMessage("naai", "#birchwood"); Thread.sleep(dur!("seconds")(2)); - client.command(new Message("", "PRIVMSG", "deavmi naai")); // TODO: use direct message + client.directMessage("naai", "deavmi"); /** From 44cce182ae0cab25232a9d4aed1221ae535d36ca Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 16:32:49 +0200 Subject: [PATCH 14/15] ConnectionInfo - Set default `fakeLag` to `1` - Added `getFakeLag()` and `setFakeLag()` Client - Added `getConnInfo()` to return the client's associated `ConnectionInfo` Sender - Use the fakelag configured by user --- source/birchwood/client/client.d | 9 +++++++++ source/birchwood/client/sender.d | 5 +---- source/birchwood/config/conninfo.d | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/source/birchwood/client/client.d b/source/birchwood/client/client.d index 71cdbb7..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; + } /** @@ -875,6 +879,11 @@ public class Client : Thread //snootnet: 178.62.125.123 //bonobonet: fd08:8441:e254::5 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(); 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 From f0ae335419073a00407d9304d21b572ecb758389 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 15 Mar 2023 16:51:46 +0200 Subject: [PATCH 15/15] Receiver - Documented a bug with the PING detection (#13) --- source/birchwood/client/receiver.d | 4 ++++ 1 file changed, 4 insertions(+) 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; }