A blocking module - what is the correct design?
Moderator: Supporters
A blocking module - what is the correct design?
Suppose I write a module that needs to do a fair bit of work in one of its hooks before allowing the message to proceed down the line - say in the HOOKTYPE_NEW_MESSAGE or HOOKTYPE_PRE_CHANMSG. I'm not sure how unrealircd's threading model works. Am I blocking the whole server or other messages from being delivered if my module takes a long time to return from its hook? If so, what would be the correct approach? In the hook, push the message onto a queue to be processed in a thread of my own making, while cancelling the immediate flow in the current message? Is there an established mechanism for doing that or will I have to hack something of my own?
Re: A blocking module - what is the correct design?
There is no dedicated mechanism in UnrealIRCd for such a case. To my knowledge it is also not used in any UnrealIRCd module found online. In UnrealIRCd everything is processed in a single thread, so you rightly point out doing "long" work in a hook (or anywhere else) would be blocking the entire server which is really bad.
There are many hooks where you can't really "undo" an action or reject it (the HOOKTYPE_PRE_xxx ones usually being the exception), so even a workaround like you propose with "cancelling the immediate flow" would not work in some cases. In cases where it is not possible then you would have to resort to an approach like with CommandOverride(), where you handle the command first and then don't pass it on to the original command handler. Downside is.. then you loose all the benefits of UnrealIRCd handling things, since you basically need to do all the command processing on your own.
When you reject it in HOOKTYPE_PRE_xxxx or from CommandOverride(), so the command is not processed, and you are done with the long work, you can re-submit the command through do_cmd() (and then this time don't delay the command / go over all the processing again, otherwise it never ends :D).
You will still have messy problems though, since things will happen out of sequence. Normally on IRC if you submit command A, B, C, they are processed in sequence, if they get processed like B, A, C that can lead to confusing things. Think of channel messages (sentences) out of order, that is fun. You will probably have to patch client_lagged_up() to stop further processing of other items (return 1) while your module is "busy" processing a command from a client, that way other commands are not processed from the client and you maintain order. So, yeah, lots of stuff and workarounds, basically, but it is sortof possible.
There are many hooks where you can't really "undo" an action or reject it (the HOOKTYPE_PRE_xxx ones usually being the exception), so even a workaround like you propose with "cancelling the immediate flow" would not work in some cases. In cases where it is not possible then you would have to resort to an approach like with CommandOverride(), where you handle the command first and then don't pass it on to the original command handler. Downside is.. then you loose all the benefits of UnrealIRCd handling things, since you basically need to do all the command processing on your own.
When you reject it in HOOKTYPE_PRE_xxxx or from CommandOverride(), so the command is not processed, and you are done with the long work, you can re-submit the command through do_cmd() (and then this time don't delay the command / go over all the processing again, otherwise it never ends :D).
You will still have messy problems though, since things will happen out of sequence. Normally on IRC if you submit command A, B, C, they are processed in sequence, if they get processed like B, A, C that can lead to confusing things. Think of channel messages (sentences) out of order, that is fun. You will probably have to patch client_lagged_up() to stop further processing of other items (return 1) while your module is "busy" processing a command from a client, that way other commands are not processed from the client and you maintain order. So, yeah, lots of stuff and workarounds, basically, but it is sortof possible.
Re: A blocking module - what is the correct design?
hmmm yeah ok, thanks for that info. Food for thought, but definitely making me reconsider my life choices
Re: A blocking module - what is the correct design?
Incase you're interested you can see what I've done here: https://github.com/ta-forever/unrealirc ... 38a0ab3993