mirror of
https://github.com/deavmi/birchwood
synced 2024-09-20 09:03:29 +02:00
Eventy integration
- Fully integrated eventy - PongEvent and IRCEvent along with respective GenericSignal and PingSignal handlers added - Moved parsing of messages into Message class Debugging - Added dlog which always logs (for now, we should add a debug clause that enables it)
This commit is contained in:
parent
ce8dbd7f5e
commit
cbe41bff80
1
dub.json
1
dub.json
@ -4,6 +4,7 @@
|
|||||||
],
|
],
|
||||||
"copyright": "Copyright © 2022, Tristan B. Kildaire",
|
"copyright": "Copyright © 2022, Tristan B. Kildaire",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"dlog": "~>0.0.6",
|
||||||
"eventy": "0.2.5"
|
"eventy": "0.2.5"
|
||||||
},
|
},
|
||||||
"description": "A sane IRC framework for the D language",
|
"description": "A sane IRC framework for the D language",
|
||||||
|
@ -12,6 +12,14 @@ import birchwood.messages : Message;
|
|||||||
|
|
||||||
// TODO: Remove this import
|
// TODO: Remove this import
|
||||||
import std.stdio : writeln;
|
import std.stdio : writeln;
|
||||||
|
import dlog;
|
||||||
|
|
||||||
|
__gshared Logger logger;
|
||||||
|
__gshared static this()
|
||||||
|
{
|
||||||
|
logger = new DefaultLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class BirchwoodException : Exception
|
public class BirchwoodException : Exception
|
||||||
{
|
{
|
||||||
@ -146,9 +154,6 @@ public class Client
|
|||||||
this(ConnectionInfo connInfo)
|
this(ConnectionInfo connInfo)
|
||||||
{
|
{
|
||||||
this.connInfo = connInfo;
|
this.connInfo = connInfo;
|
||||||
|
|
||||||
/* Set the client inside IRCEvent so all can access it when handling events */
|
|
||||||
IRCEvent.client = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~this()
|
~this()
|
||||||
@ -156,16 +161,21 @@ public class Client
|
|||||||
//TODO: Do something here, tare downs
|
//TODO: Do something here, tare downs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum EventType : ulong
|
||||||
|
{
|
||||||
|
GENERIC_EVENT = 1,
|
||||||
|
PONG_EVENT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Move to an events.d class */
|
||||||
class IRCEvent : Event
|
class IRCEvent : Event
|
||||||
{
|
{
|
||||||
/* The client itself */
|
|
||||||
private static __gshared Client client;
|
|
||||||
|
|
||||||
private Message msg;
|
private Message msg;
|
||||||
|
|
||||||
this(ulong typeID, Message msg)
|
this(Message msg)
|
||||||
{
|
{
|
||||||
super(typeID, null);
|
super(EventType.GENERIC_EVENT, null);
|
||||||
|
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
}
|
}
|
||||||
@ -181,21 +191,52 @@ public class Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: make PongEvent (id 2 buit-in) */
|
||||||
|
class PongEvent : Event
|
||||||
|
{
|
||||||
|
private string pingID;
|
||||||
|
|
||||||
|
this(string pingID)
|
||||||
|
{
|
||||||
|
super(EventType.PONG_EVENT);
|
||||||
|
this.pingID = pingID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getID()
|
||||||
|
{
|
||||||
|
return pingID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initEvents()
|
private void initEvents()
|
||||||
{
|
{
|
||||||
/* TODO: For now we just register one signal type for all messages */
|
/* TODO: For now we just register one signal type for all messages */
|
||||||
ulong signalDefault = 1;
|
|
||||||
engine.addQueue(signalDefault);
|
/* Register all event types */
|
||||||
|
engine.addQueue(EventType.GENERIC_EVENT);
|
||||||
|
engine.addQueue(EventType.PONG_EVENT);
|
||||||
|
|
||||||
|
|
||||||
|
/* Base signal with IRC client in it */
|
||||||
|
abstract class BaseSignal : Signal
|
||||||
|
{
|
||||||
|
/* ICR client */
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
this(Client client, ulong[] eventIDs)
|
||||||
|
{
|
||||||
|
super(eventIDs);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO: We also add default signal handler which will just print stuff out */
|
/* TODO: We also add default signal handler which will just print stuff out */
|
||||||
class SignalHandler1 : Signal
|
class GenericSignal : BaseSignal
|
||||||
{
|
{
|
||||||
this()
|
this(Client client)
|
||||||
{
|
{
|
||||||
super([1]);
|
super(client, [EventType.GENERIC_EVENT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void handler(Event e)
|
public override void handler(Event e)
|
||||||
@ -204,16 +245,40 @@ public class Client
|
|||||||
IRCEvent ircEvent = cast(IRCEvent)e;
|
IRCEvent ircEvent = cast(IRCEvent)e;
|
||||||
assert(ircEvent); //Should never fail, unless some BOZO regged multiple handles for 1 - wait idk does eventy do that even mmm
|
assert(ircEvent); //Should never fail, unless some BOZO regged multiple handles for 1 - wait idk does eventy do that even mmm
|
||||||
|
|
||||||
writeln("IRCEvent (id): "~to!(string)(ircEvent.id));
|
logger.log("IRCEvent (id): "~to!(string)(ircEvent.id));
|
||||||
writeln("IRCEvent "~ircEvent.getMessage().toString());
|
logger.log("IRCEvent "~ircEvent.getMessage().toString());
|
||||||
|
|
||||||
|
|
||||||
writeln(IRCEvent.client);
|
logger.log(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal j = new SignalHandler1();
|
Signal j = new GenericSignal(this);
|
||||||
engine.addSignalHandler(j);
|
engine.addSignalHandler(j);
|
||||||
|
|
||||||
|
/* TODO: Add Pong signal handler (make it id 2) */
|
||||||
|
class PongSignal : BaseSignal
|
||||||
|
{
|
||||||
|
this(Client client)
|
||||||
|
{
|
||||||
|
super(client, [EventType.PONG_EVENT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Implement me */
|
||||||
|
public override void handler(Event e)
|
||||||
|
{
|
||||||
|
PongEvent pongEvent = cast(PongEvent)e;
|
||||||
|
assert(pongEvent);
|
||||||
|
|
||||||
|
string messageToSend = "PONG "~pongEvent.getID();
|
||||||
|
|
||||||
|
client.sendMessage(messageToSend);
|
||||||
|
|
||||||
|
logger.log("Ponged");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.addSignalHandler(new PongSignal(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,92 +363,6 @@ public class Client
|
|||||||
// return null;
|
// return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Implement me */
|
|
||||||
/* TODO: This should be a static method in `birchwood.messages.Message`
|
|
||||||
* which geneartes a Message object for us
|
|
||||||
*/
|
|
||||||
private void parseReceivedMessage(string message)
|
|
||||||
{
|
|
||||||
/* TODO: testing */
|
|
||||||
|
|
||||||
/* From */
|
|
||||||
string from;
|
|
||||||
|
|
||||||
/* Command */
|
|
||||||
string command;
|
|
||||||
|
|
||||||
/* Params */
|
|
||||||
string params;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check if there is a PREFIX (according to RFC 1459) */
|
|
||||||
if(message[0] == ':')
|
|
||||||
{
|
|
||||||
/* prefix ends after first space (we fetch servername, host/user) */
|
|
||||||
//TODO: make sure not -1
|
|
||||||
long firstSpace = indexOf(message, ' ');
|
|
||||||
|
|
||||||
/* TODO: double check the condition */
|
|
||||||
if(firstSpace > 0)
|
|
||||||
{
|
|
||||||
from = message[1..firstSpace];
|
|
||||||
|
|
||||||
writeln("from: "~from);
|
|
||||||
|
|
||||||
/* TODO: Find next space (what follows `from` is `' ' { ' ' }`) */
|
|
||||||
ulong i = firstSpace;
|
|
||||||
for(; i < message.length; i++)
|
|
||||||
{
|
|
||||||
if(message[i] != ' ')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeln("Yo");
|
|
||||||
|
|
||||||
string rem = message[i..message.length];
|
|
||||||
// writeln("Rem: "~rem);
|
|
||||||
long idx = indexOf(rem, " "); //TOOD: -1 check
|
|
||||||
|
|
||||||
/* Extract the command */
|
|
||||||
command = rem[0..idx];
|
|
||||||
writeln("command: "~command);
|
|
||||||
|
|
||||||
/* Params are everything till the end */
|
|
||||||
i = idx;
|
|
||||||
for(; i < rem.length; i++)
|
|
||||||
{
|
|
||||||
if(rem[i] != ' ')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params = rem[i..rem.length];
|
|
||||||
writeln("params: "~params);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//TODO: handle
|
|
||||||
writeln("Malformed message start after :");
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
import birchwood.messages;
|
|
||||||
|
|
||||||
Message msg = new Message(from, command, message);
|
|
||||||
|
|
||||||
/* TODO: Set static in IRCEvent field for access to Client (and hence socket) */
|
|
||||||
/* TODO: This should be done in reeive handler me thinks, or rather
|
|
||||||
shouild return something not yet TRIGGER an event */
|
|
||||||
Event eTest = new IRCEvent(1, msg);
|
|
||||||
engine.push(eTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Spawn a thread worker that reacts */
|
/* TODO: Spawn a thread worker that reacts */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -406,6 +385,8 @@ public class Client
|
|||||||
/* Lock the receieve queue */
|
/* Lock the receieve queue */
|
||||||
recvQueueLock.lock();
|
recvQueueLock.lock();
|
||||||
|
|
||||||
|
/* Message being analysed */
|
||||||
|
Message curMsg;
|
||||||
|
|
||||||
/* Search for a PING */
|
/* Search for a PING */
|
||||||
ubyte[] pingMessage;
|
ubyte[] pingMessage;
|
||||||
@ -445,22 +426,32 @@ public class Client
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* If we found a PING */
|
/* If we found a PING */
|
||||||
if(pingMessage.length > 0)
|
if(pingMessage.length > 0)
|
||||||
{
|
{
|
||||||
writeln("Found a ping: "~cast(string)pingMessage);
|
/* Decode the message and parse it */
|
||||||
string ogMessage = cast(string)pingMessage;
|
curMsg = Message.parseReceivedMessage(decodeMessage(pingMessage));
|
||||||
long idxSigStart = indexOf(ogMessage, ":")+1;
|
logger.log("Found a ping: "~curMsg.toString());
|
||||||
long idxSigEnd = lastIndexOf(ogMessage, '\r');
|
|
||||||
|
|
||||||
string pingID = ogMessage[idxSigStart..idxSigEnd];
|
// string ogMessage = cast(string)pingMessage;
|
||||||
|
// long idxSigStart = indexOf(ogMessage, ":")+1;
|
||||||
|
// long idxSigEnd = lastIndexOf(ogMessage, '\r');
|
||||||
|
|
||||||
|
// string pingID = ogMessage[idxSigStart..idxSigEnd];
|
||||||
|
string pingID = curMsg.getMessage();
|
||||||
|
|
||||||
|
|
||||||
// this.socket.send(encodeMessage("PONG "~pingID));
|
// this.socket.send(encodeMessage("PONG "~pingID));
|
||||||
|
// string messageToSend = "PONG "~pingID;
|
||||||
|
|
||||||
string messageToSend = "PONG "~pingID;
|
// sendMessage(messageToSend);
|
||||||
|
|
||||||
sendMessage(messageToSend);
|
// logger.log("Ponged");
|
||||||
|
|
||||||
|
/* TODO: Implement */
|
||||||
|
Event pongEvent = new PongEvent(pingID);
|
||||||
|
engine.push(pongEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now let's go message by message */
|
/* Now let's go message by message */
|
||||||
@ -473,12 +464,15 @@ public class Client
|
|||||||
|
|
||||||
recvQueue.linearRemoveElement(recvQueue.front());
|
recvQueue.linearRemoveElement(recvQueue.front());
|
||||||
|
|
||||||
writeln("Normal message: "~messageNormal);
|
// writeln("Normal message: "~messageNormal);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Parse message and call correct handler */
|
/* TODO: Parse message and call correct handler */
|
||||||
parseReceivedMessage(messageNormal);
|
curMsg = Message.parseReceivedMessage(messageNormal);
|
||||||
|
|
||||||
|
Event ircEvent = new IRCEvent(curMsg);
|
||||||
|
engine.push(ircEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -553,8 +547,8 @@ public class Client
|
|||||||
private void processMessage(ubyte[] message)
|
private void processMessage(ubyte[] message)
|
||||||
{
|
{
|
||||||
// import std.stdio;
|
// import std.stdio;
|
||||||
// writeln("Message length: "~to!(string)(message.length));
|
// logger.log("Message length: "~to!(string)(message.length));
|
||||||
// writeln("InterpAsString: "~cast(string)message);
|
// logger.log("InterpAsString: "~cast(string)message);
|
||||||
|
|
||||||
receiveQ(message);
|
receiveQ(message);
|
||||||
|
|
||||||
|
@ -1,5 +1,31 @@
|
|||||||
module birchwood.messages;
|
module birchwood.messages;
|
||||||
|
|
||||||
|
import dlog;
|
||||||
|
|
||||||
|
import std.string;
|
||||||
|
|
||||||
|
// TODO: Before release we should remove this import
|
||||||
|
import std.stdio : writeln;
|
||||||
|
|
||||||
|
/* TODO: We could move these all to `package.d` */
|
||||||
|
|
||||||
|
/* Static is redundant as module is always static , gshared needed */
|
||||||
|
/* Apparebky works without gshared, that is kinda sus ngl */
|
||||||
|
__gshared Logger logger;
|
||||||
|
/**
|
||||||
|
* source/birchwood/messages.d(10,8): Error: variable `birchwood.messages.logger` is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.
|
||||||
|
*
|
||||||
|
* It is complaining that it wopuld static init per thread, static this() for module is required but that would
|
||||||
|
* do a module init per thread, so __gshared static this() is needed, we want one global init - a single logger
|
||||||
|
* variable and also class init
|
||||||
|
*/
|
||||||
|
|
||||||
|
__gshared static this()
|
||||||
|
{
|
||||||
|
logger = new DefaultLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message types
|
* Message types
|
||||||
*/
|
*/
|
||||||
@ -16,8 +42,107 @@ public class Message
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Message parseReceivedMessage(string message)
|
||||||
|
{
|
||||||
|
/* TODO: testing */
|
||||||
|
|
||||||
|
/* From */
|
||||||
|
string from;
|
||||||
|
|
||||||
|
/* Command */
|
||||||
|
string command;
|
||||||
|
|
||||||
|
/* Params */
|
||||||
|
string params;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if there is a PREFIX (according to RFC 1459) */
|
||||||
|
if(message[0] == ':')
|
||||||
|
{
|
||||||
|
/* prefix ends after first space (we fetch servername, host/user) */
|
||||||
|
//TODO: make sure not -1
|
||||||
|
long firstSpace = indexOf(message, ' ');
|
||||||
|
|
||||||
|
/* TODO: double check the condition */
|
||||||
|
if(firstSpace > 0)
|
||||||
|
{
|
||||||
|
from = message[1..firstSpace];
|
||||||
|
|
||||||
|
logger.log("from: "~from);
|
||||||
|
|
||||||
|
/* TODO: Find next space (what follows `from` is `' ' { ' ' }`) */
|
||||||
|
ulong i = firstSpace;
|
||||||
|
for(; i < message.length; i++)
|
||||||
|
{
|
||||||
|
if(message[i] != ' ')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeln("Yo");
|
||||||
|
|
||||||
|
string rem = message[i..message.length];
|
||||||
|
// writeln("Rem: "~rem);
|
||||||
|
long idx = indexOf(rem, " "); //TOOD: -1 check
|
||||||
|
|
||||||
|
/* Extract the command */
|
||||||
|
command = rem[0..idx];
|
||||||
|
logger.log("command: "~command);
|
||||||
|
|
||||||
|
/* Params are everything till the end */
|
||||||
|
i = idx;
|
||||||
|
for(; i < rem.length; i++)
|
||||||
|
{
|
||||||
|
if(rem[i] != ' ')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params = rem[i..rem.length];
|
||||||
|
logger.log("params: "~params);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: handle
|
||||||
|
logger.log("Malformed message start after :");
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/* In this case it is only `<command> <params>` */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
long firstSpace = indexOf(message, " "); //TODO: Not find check
|
||||||
|
|
||||||
|
command = message[0..firstSpace];
|
||||||
|
|
||||||
|
ulong pos = firstSpace;
|
||||||
|
for(; pos < message.length; pos++)
|
||||||
|
{
|
||||||
|
if(message[pos] != ' ')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params = message[pos..message.length];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Message(from, command, params);
|
||||||
|
}
|
||||||
|
|
||||||
public override string toString()
|
public override string toString()
|
||||||
{
|
{
|
||||||
return "(from: "~from~", command: "~command~", message: `"~message~"`)";
|
return "(from: "~from~", command: "~command~", message: `"~message~"`)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string getMessage()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user