1
0
mirror of https://github.com/deavmi/birchwood synced 2024-09-20 15:22:53 +02:00

Merge branch 'master' into ircv3

This commit is contained in:
Tristan B. Velloza Kildaire 2023-03-18 11:33:24 +02:00
commit c6a74d3cee
10 changed files with 232 additions and 66 deletions

View File

@ -1,4 +1,5 @@
{ {
"homepage": "https://deavmi.assigned.network/projects/birchwood",
"authors": [ "authors": [
"Tristan B. Velloza Kildaire" "Tristan B. Velloza Kildaire"
], ],

View File

@ -9,7 +9,7 @@ import core.thread : Thread, dur;
import std.string; import std.string;
import eventy : EventyEvent = Event, Engine, EventType, Signal; import eventy : EventyEvent = Event, Engine, EventType, Signal;
import birchwood.config : ConnectionInfo; import birchwood.config : ConnectionInfo;
import birchwood.client.exceptions : BirchwoodException; import birchwood.client.exceptions : BirchwoodException, ErrorType;
import birchwood.protocol.messages : Message, encodeMessage, decodeMessage, isValidText; import birchwood.protocol.messages : Message, encodeMessage, decodeMessage, isValidText;
import birchwood.client.receiver : ReceiverThread; import birchwood.client.receiver : ReceiverThread;
@ -190,12 +190,12 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.INVALID_CHANNEL_NAME); throw new BirchwoodException(ErrorType.INVALID_CHANNEL_NAME);
} }
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -248,7 +248,7 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -258,13 +258,13 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
/* If no channels provided at all (error) */ /* If no channels provided at all (error) */
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.EMPTY_PARAMS); throw new BirchwoodException(ErrorType.EMPTY_PARAMS);
} }
} }
@ -319,7 +319,7 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -329,13 +329,13 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
/* If no channels provided at all (error) */ /* If no channels provided at all (error) */
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.EMPTY_PARAMS); throw new BirchwoodException(ErrorType.EMPTY_PARAMS);
} }
} }
@ -403,7 +403,7 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -413,18 +413,18 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
/* If no recipients provided at all (error) */ /* If no recipients provided at all (error) */
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.EMPTY_PARAMS); throw new BirchwoodException(ErrorType.EMPTY_PARAMS);
} }
} }
@ -451,12 +451,12 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.INVALID_NICK_NAME); throw new BirchwoodException(ErrorType.INVALID_NICK_NAME);
} }
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -509,7 +509,7 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -519,18 +519,18 @@ public class Client : Thread
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
/* If no channels provided at all (error) */ /* If no channels provided at all (error) */
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.EMPTY_PARAMS); throw new BirchwoodException(ErrorType.EMPTY_PARAMS);
} }
} }
@ -556,13 +556,13 @@ public class Client : Thread
else else
{ {
//TODO: Invalid channel name //TODO: Invalid channel name
throw new BirchwoodException(BirchwoodException.ErrorType.INVALID_CHANNEL_NAME); throw new BirchwoodException(ErrorType.INVALID_CHANNEL_NAME);
} }
} }
else else
{ {
//TODO: Illegal characters //TODO: Illegal characters
throw new BirchwoodException(BirchwoodException.ErrorType.ILLEGAL_CHARACTERS); throw new BirchwoodException(ErrorType.ILLEGAL_CHARACTERS);
} }
} }
@ -749,13 +749,13 @@ public class Client : Thread
} }
catch(SocketOSException e) catch(SocketOSException e)
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.CONNECT_ERROR); throw new BirchwoodException(ErrorType.CONNECT_ERROR);
} }
} }
// TODO: Do actual liveliness check here // TODO: Do actual liveliness check here
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.ALREADY_CONNECTED); throw new BirchwoodException(ErrorType.ALREADY_CONNECTED);
} }
} }
@ -799,7 +799,7 @@ public class Client : Thread
/* If above then throw an exception */ /* If above then throw an exception */
else else
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.COMMAND_TOO_LONG); throw new BirchwoodException(ErrorType.COMMAND_TOO_LONG);
} }
} }
@ -1011,6 +1011,8 @@ public class Client : Thread
client.connect(); client.connect();
// TODO: The below should all be automatic, maybe once IRCV3 is done
// ... we should automate sending in NICK and USER stuff
Thread.sleep(dur!("seconds")(2)); Thread.sleep(dur!("seconds")(2));
client.command(new Message("", "NICK", "birchwood")); // TODO: add nickcommand client.command(new Message("", "NICK", "birchwood")); // TODO: add nickcommand

View File

@ -1,40 +1,112 @@
/**
* Exception handling
*/
module birchwood.client.exceptions; module birchwood.client.exceptions;
import std.conv : to; import std.conv : to;
public class BirchwoodException : Exception /**
{ * The type of error to be used
// TODO: Move outside one level * with BirchwoodException
*/
public enum ErrorType public enum ErrorType
{ {
/**
* If the provided connection information
* is invalid, such as incorrect hostname,
* invalid nick
*/
INVALID_CONN_INFO, INVALID_CONN_INFO,
/**
* If an attempt to call connect() is made
* when already connected
*/
ALREADY_CONNECTED, ALREADY_CONNECTED,
/**
* If there is an erroring opening a connection
* to the endpoint server
*/
CONNECT_ERROR, CONNECT_ERROR,
/**
* If invalid parameter information is provided
* to an IRC command method
*/
EMPTY_PARAMS, EMPTY_PARAMS,
/**
* If an invalid channel name is provided
*/
INVALID_CHANNEL_NAME, INVALID_CHANNEL_NAME,
/**
* If an invalid nickname is provided
*/
INVALID_NICK_NAME, INVALID_NICK_NAME,
/**
* If illegal characters exist within the
* message
*/
ILLEGAL_CHARACTERS, ILLEGAL_CHARACTERS,
/**
* If the final encoded IRC message
* is too long to send to the server
*/
COMMAND_TOO_LONG COMMAND_TOO_LONG
} }
/**
* A runtime exception in the Birchwood library
*/
public class BirchwoodException : Exception
{
/**
* The specific type of error occurred
*/
private ErrorType errType; private ErrorType errType;
/* Auxillary error information */ /**
/* TODO: Make these actually Object */ * Auxillary information
*/
private string auxInfo; private string auxInfo;
/**
* Constructs a new exception with the given sub-error type
* and infers the auxillary information based on said sub-error
* type
*
* Params:
* errType = the sub-error type
*/
this(ErrorType errType) this(ErrorType errType)
{ {
super("BirchwoodError("~to!(string)(errType)~")"~(auxInfo.length == 0 ? "" : " "~auxInfo)); super("BirchwoodError("~to!(string)(errType)~")"~(auxInfo.length == 0 ? "" : " "~auxInfo));
this.errType = errType; this.errType = errType;
} }
/**
* Constructs a new exception with the given sub-error type
* and auxillary information
*
* Params:
* errType = the sub-error type
* auxInfo = the auxillary information
*/
this(ErrorType errType, string auxInfo) this(ErrorType errType, string auxInfo)
{ {
this(errType); this(errType);
this.auxInfo = auxInfo; this.auxInfo = auxInfo;
} }
/**
* Retrieve the specific error which occurred
*
* Returns: the ErrorType of the error
*/
public ErrorType getType() public ErrorType getType()
{ {
return errType; return errType;

View File

@ -1,4 +1,14 @@
/**
* IRC client and runtime related
*/
module birchwood.client; module birchwood.client;
/**
* IRC client
*/
public import birchwood.client.client; public import birchwood.client.client;
public import birchwood.client.exceptions : BirchwoodException;
/**
* Error handling
*/
public import birchwood.client.exceptions;

View File

@ -1,3 +1,6 @@
/**
* Receive queue management
*/
module birchwood.client.receiver; module birchwood.client.receiver;
import core.thread : Thread, dur; import core.thread : Thread, dur;
@ -15,13 +18,23 @@ import birchwood.client;
import birchwood.protocol.messages : Message, decodeMessage; import birchwood.protocol.messages : Message, decodeMessage;
import std.string : indexOf; import std.string : indexOf;
import birchwood.client.events : PongEvent, IRCEvent; import birchwood.client.events : PongEvent, IRCEvent;
import std.string : cmp;
/**
* Manages the receive queue and performs
* message parsing and event triggering
* based on said messages
*/
public final class ReceiverThread : Thread public final class ReceiverThread : Thread
{ {
/** /**
* The receive queue and its lock * The receive queue
*/ */
private SList!(ubyte[]) recvQueue; private SList!(ubyte[]) recvQueue;
/**
* The receive queue's lock
*/
private Mutex recvQueueLock; private Mutex recvQueueLock;
/** /**
@ -151,7 +164,6 @@ public final class ReceiverThread : Thread
Message pingMessage; Message pingMessage;
foreach(Message curMsg; currentMessageQueue[]) foreach(Message curMsg; currentMessageQueue[])
{ {
import std.string : cmp;
if(cmp(curMsg.getCommand(), "PING") == 0) if(cmp(curMsg.getCommand(), "PING") == 0)
{ {
currentMessageQueue.linearRemoveElement(curMsg); currentMessageQueue.linearRemoveElement(curMsg);
@ -221,15 +233,13 @@ public final class ReceiverThread : Thread
} }
} }
/**
* Stops the receive queue manager
*/
public void end() public void end()
{ {
// TODO: See above notes about libsnooze behaviour due // TODO: See above notes about libsnooze behaviour due
// ... to usage in our context // ... to usage in our context
receiveEvent.notifyAll(); receiveEvent.notifyAll();
} }
// public bool isReady()
// {
// return hasEnsured;
// }
} }

View File

@ -1,3 +1,6 @@
/**
* Send queue management
*/
module birchwood.client.sender; module birchwood.client.sender;
import core.thread : Thread, dur; import core.thread : Thread, dur;
@ -11,12 +14,19 @@ import libsnooze;
import birchwood.client; import birchwood.client;
/**
* Manages the send queue
*/
public final class SenderThread : Thread public final class SenderThread : Thread
{ {
/** /**
* The send queue and its lock * The send queue
*/ */
private SList!(ubyte[]) sendQueue; private SList!(ubyte[]) sendQueue;
/**
* The send queue's lock
*/
private Mutex sendQueueLock; private Mutex sendQueueLock;
/** /**
@ -130,15 +140,13 @@ public final class SenderThread : Thread
} }
} }
/**
* Stops the send queue manager
*/
public void end() public void end()
{ {
// TODO: See above notes about libsnooze behaviour due // TODO: See above notes about libsnooze behaviour due
// ... to usage in our context // ... to usage in our context
sendEvent.notifyAll(); sendEvent.notifyAll();
} }
// public bool isReady()
// {
// return hasEnsured;
// }
} }

View File

@ -1,10 +1,10 @@
/** /**
* COnfiguration-related types * Configuration-related types
*/ */
module birchwood.config.conninfo; module birchwood.config.conninfo;
import std.socket : SocketException, Address, getAddress; import std.socket : SocketException, Address, getAddress;
import birchwood.client.exceptions : BirchwoodException; import birchwood.client.exceptions;
/** /**
* Represents the connection details for a server * Represents the connection details for a server
@ -12,21 +12,46 @@ import birchwood.client.exceptions : BirchwoodException;
*/ */
public struct ConnectionInfo public struct ConnectionInfo
{ {
/* Server address information */ /**
* Server address
*/
private Address addrInfo; private Address addrInfo;
/**
* Nickname to use
*/
private string nickname; private string nickname;
/* Misc. */ /**
/* TODO: Make final/const (find out difference) */ * Size to use to dequeue bytes
* from socket in read-loop
*/
private ulong bulkReadSize; private ulong bulkReadSize;
/* Client behaviour (TODO: what is sleep(0), like nothing) */ //TODO: Make this a Duration
/**
* Time to wait (in seconds) between
* sending messages
*/
private ulong fakeLag; private ulong fakeLag;
/* The quit message */ /**
* Quit message
*/
public const string quitMessage; public const string quitMessage;
/* TODO: before publishing change this bulk size */ /* TODO: before publishing change this bulk size */
/**
* Constructs a new ConnectionInfo instance with the
* provided details
*
* Params:
* addrInfo = the server's endpoint
* nickname = the nickname to use
* bulkReadSize = the dequeue read size
* quitMessage = the message to use when quitting
*/
private this(Address addrInfo, string nickname, ulong bulkReadSize = 20, string quitMessage = "birchwood client disconnecting...") private this(Address addrInfo, string nickname, ulong bulkReadSize = 20, string quitMessage = "birchwood client disconnecting...")
{ {
this.addrInfo = addrInfo; this.addrInfo = addrInfo;
@ -38,6 +63,11 @@ public struct ConnectionInfo
this.fakeLag = 1; this.fakeLag = 1;
} }
/**
* Retrieve the read-dequeue size
*
* Returns: the number of bytes
*/
public ulong getBulkReadSize() public ulong getBulkReadSize()
{ {
return this.bulkReadSize; return this.bulkReadSize;
@ -83,6 +113,7 @@ public struct ConnectionInfo
* hostname = hostname of the server * hostname = hostname of the server
* port = server port * port = server port
* nickname = nickname to use * nickname = nickname to use
*
* Returns: ConnectionInfo for this server * Returns: ConnectionInfo for this server
*/ */
public static ConnectionInfo newConnection(string hostname, ushort port, string nickname) public static ConnectionInfo newConnection(string hostname, ushort port, string nickname)
@ -95,7 +126,7 @@ public struct ConnectionInfo
/* Username check */ /* Username check */
if(!nickname.length) if(!nickname.length)
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.INVALID_CONN_INFO); throw new BirchwoodException(ErrorType.INVALID_CONN_INFO);
} }
/* TODO: Add feature to choose which address to use, prefer v4 or v6 type of thing */ /* TODO: Add feature to choose which address to use, prefer v4 or v6 type of thing */
@ -105,7 +136,7 @@ public struct ConnectionInfo
} }
catch(SocketException e) catch(SocketException e)
{ {
throw new BirchwoodException(BirchwoodException.ErrorType.INVALID_CONN_INFO); throw new BirchwoodException(ErrorType.INVALID_CONN_INFO);
} }
} }
@ -124,7 +155,7 @@ public struct ConnectionInfo
} }
catch(BirchwoodException e) catch(BirchwoodException e)
{ {
assert(e.getType() == BirchwoodException.ErrorType.INVALID_CONN_INFO); assert(e.getType() == ErrorType.INVALID_CONN_INFO);
} }
try try
@ -134,7 +165,7 @@ public struct ConnectionInfo
} }
catch(BirchwoodException e) catch(BirchwoodException e)
{ {
assert(e.getType() == BirchwoodException.ErrorType.INVALID_CONN_INFO); assert(e.getType() == ErrorType.INVALID_CONN_INFO);
} }
} }

View File

@ -1,3 +1,9 @@
/**
* Configuration system
*/
module birchwood.config; module birchwood.config;
/**
* Connection information
*/
public import birchwood.config.conninfo : ConnectionInfo; public import birchwood.config.conninfo : ConnectionInfo;

View File

@ -1,5 +1,19 @@
/**
* A sane IRC framework for the D language
*/
module birchwood; module birchwood;
/**
* Client
*/
public import birchwood.client; public import birchwood.client;
/**
* Configuration
*/
public import birchwood.config; public import birchwood.config;
/**
* Encoding and decoding
*/
public import birchwood.protocol; public import birchwood.protocol;

View File

@ -1,7 +1,19 @@
/**
* IRC protocol decoding and encoding
*/
module birchwood.protocol; module birchwood.protocol;
/**
* Message type and parsing
*/
public import birchwood.protocol.messages : Message; public import birchwood.protocol.messages : Message;
/**
* Numeric response codes
*/
public import birchwood.protocol.constants : ReplyType; public import birchwood.protocol.constants : ReplyType;
// TODO: Look how to neaten up (if any) /**
* Message formatting utilities
*/
public import birchwood.protocol.formatting; public import birchwood.protocol.formatting;