mirror of
https://github.com/deavmi/birchwood
synced 2024-09-20 04:43:04 +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",
|
||||
"dependencies": {
|
||||
"dlog": "~>0.0.6",
|
||||
"eventy": "0.2.5"
|
||||
},
|
||||
"description": "A sane IRC framework for the D language",
|
||||
|
@ -12,6 +12,14 @@ import birchwood.messages : Message;
|
||||
|
||||
// TODO: Remove this import
|
||||
import std.stdio : writeln;
|
||||
import dlog;
|
||||
|
||||
__gshared Logger logger;
|
||||
__gshared static this()
|
||||
{
|
||||
logger = new DefaultLogger();
|
||||
}
|
||||
|
||||
|
||||
public class BirchwoodException : Exception
|
||||
{
|
||||
@ -146,9 +154,6 @@ public class Client
|
||||
this(ConnectionInfo connInfo)
|
||||
{
|
||||
this.connInfo = connInfo;
|
||||
|
||||
/* Set the client inside IRCEvent so all can access it when handling events */
|
||||
IRCEvent.client = this;
|
||||
}
|
||||
|
||||
~this()
|
||||
@ -156,16 +161,21 @@ public class Client
|
||||
//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
|
||||
{
|
||||
/* The client itself */
|
||||
private static __gshared Client client;
|
||||
|
||||
private Message msg;
|
||||
|
||||
this(ulong typeID, Message msg)
|
||||
this(Message msg)
|
||||
{
|
||||
super(typeID, null);
|
||||
super(EventType.GENERIC_EVENT, null);
|
||||
|
||||
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()
|
||||
{
|
||||
/* 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 */
|
||||
class SignalHandler1 : Signal
|
||||
class GenericSignal : BaseSignal
|
||||
{
|
||||
this()
|
||||
this(Client client)
|
||||
{
|
||||
super([1]);
|
||||
super(client, [EventType.GENERIC_EVENT]);
|
||||
}
|
||||
|
||||
public override void handler(Event e)
|
||||
@ -204,16 +245,40 @@ public class Client
|
||||
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
|
||||
|
||||
writeln("IRCEvent (id): "~to!(string)(ircEvent.id));
|
||||
writeln("IRCEvent "~ircEvent.getMessage().toString());
|
||||
logger.log("IRCEvent (id): "~to!(string)(ircEvent.id));
|
||||
logger.log("IRCEvent "~ircEvent.getMessage().toString());
|
||||
|
||||
|
||||
writeln(IRCEvent.client);
|
||||
logger.log(client);
|
||||
}
|
||||
}
|
||||
|
||||
Signal j = new SignalHandler1();
|
||||
Signal j = new GenericSignal(this);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
/**
|
||||
@ -406,6 +385,8 @@ public class Client
|
||||
/* Lock the receieve queue */
|
||||
recvQueueLock.lock();
|
||||
|
||||
/* Message being analysed */
|
||||
Message curMsg;
|
||||
|
||||
/* Search for a PING */
|
||||
ubyte[] pingMessage;
|
||||
@ -443,24 +424,34 @@ public class Client
|
||||
* - we can cache or remember stuff when we get 353
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* If we found a PING */
|
||||
if(pingMessage.length > 0)
|
||||
{
|
||||
writeln("Found a ping: "~cast(string)pingMessage);
|
||||
string ogMessage = cast(string)pingMessage;
|
||||
long idxSigStart = indexOf(ogMessage, ":")+1;
|
||||
long idxSigEnd = lastIndexOf(ogMessage, '\r');
|
||||
/* Decode the message and parse it */
|
||||
curMsg = Message.parseReceivedMessage(decodeMessage(pingMessage));
|
||||
logger.log("Found a ping: "~curMsg.toString());
|
||||
|
||||
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));
|
||||
// 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 */
|
||||
@ -473,12 +464,15 @@ public class Client
|
||||
|
||||
recvQueue.linearRemoveElement(recvQueue.front());
|
||||
|
||||
writeln("Normal message: "~messageNormal);
|
||||
// writeln("Normal message: "~messageNormal);
|
||||
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
// import std.stdio;
|
||||
// writeln("Message length: "~to!(string)(message.length));
|
||||
// writeln("InterpAsString: "~cast(string)message);
|
||||
// logger.log("Message length: "~to!(string)(message.length));
|
||||
// logger.log("InterpAsString: "~cast(string)message);
|
||||
|
||||
receiveQ(message);
|
||||
|
||||
|
@ -1,5 +1,31 @@
|
||||
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
|
||||
*/
|
||||
@ -16,8 +42,107 @@ public class 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()
|
||||
{
|
||||
return "(from: "~from~", command: "~command~", message: `"~message~"`)";
|
||||
}
|
||||
|
||||
public string getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user