mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-10-07 22:41:21 +00:00
add structured IRC event hooks
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Semantic IRC hooks
|
||||
|
||||
`on_join`, `on_part`, `on_quit`, `on_nick`, `on_kick`, `on_message`, and
|
||||
`on_notice` accept `(callback, userdata=None, priority=PRI_NORM)`. The general
|
||||
form is `hook_event(command, callback, userdata=None, priority=PRI_NORM)`.
|
||||
Callbacks receive `(event, userdata)`, where the immutable IRCEvent has
|
||||
command, prefix, nick, user, host, params, context, connection_id and time.
|
||||
`params` preserves the trailing parameter, including spaces; JOIN parameters
|
||||
also retain extended-join account/realname data when supplied by the server.
|
||||
|
||||
These wrappers use existing server hooks, before core command processing;
|
||||
return the ordinary EAT_* constants. EAT_ZOITECHAT suppresses the entire IRC
|
||||
command (including client state updates), not just its text. Use EAT_NONE for
|
||||
observation. Other plugins' priority and eating rules remain unchanged.
|
||||
The context is the core-selected context, which can be the server tab when a
|
||||
query/channel does not yet exist. QUIT is one event per incoming command,
|
||||
not one callback per affected channel. `event.time` is the existing server-time
|
||||
attribute (zero when unavailable); other message tags are not exposed here.
|
||||
|
||||
```python
|
||||
def joined(event, userdata):
|
||||
event.context.prnt('{} joined {}'.format(event.nick, event.params[0]))
|
||||
return zoitechat.EAT_NONE
|
||||
|
||||
zoitechat.on_join(joined)
|
||||
```
|
||||
@@ -0,0 +1,77 @@
|
||||
"""Structured, opt-in hooks before the IRC command's core processing."""
|
||||
from collections import namedtuple
|
||||
import _zoitechat as api
|
||||
|
||||
__all__ = ['IRCEvent', 'hook_event', 'on_join', 'on_part', 'on_quit',
|
||||
'on_nick', 'on_kick', 'on_message', 'on_notice']
|
||||
IRCEvent = namedtuple('IRCEvent', 'command prefix nick user host params context connection_id time')
|
||||
_SUPPORTED = frozenset(('JOIN', 'PART', 'QUIT', 'NICK', 'KICK', 'PRIVMSG', 'NOTICE'))
|
||||
|
||||
|
||||
def _parse(line):
|
||||
prefix = ''
|
||||
if line.startswith(':'):
|
||||
prefix, separator, line = line[1:].partition(' ')
|
||||
if not separator:
|
||||
return None
|
||||
command, separator, rest = line.partition(' ')
|
||||
params = []
|
||||
while rest:
|
||||
rest = rest.lstrip(' ')
|
||||
if rest.startswith(':'):
|
||||
params.append(rest[1:])
|
||||
break
|
||||
param, separator, rest = rest.partition(' ')
|
||||
if param:
|
||||
params.append(param)
|
||||
nick, marker, userhost = prefix.partition('!')
|
||||
user, marker, host = userhost.partition('@')
|
||||
return command.upper(), prefix, nick, user, host, tuple(params)
|
||||
|
||||
|
||||
def hook_event(command, callback, userdata=None, priority=api.PRI_NORM):
|
||||
"""callback(event, userdata) returns existing EAT_* constants."""
|
||||
command = command.upper()
|
||||
if command not in _SUPPORTED:
|
||||
raise ValueError('unsupported semantic event: ' + command)
|
||||
if not callable(callback):
|
||||
raise TypeError('callback must be callable')
|
||||
|
||||
def dispatch(word, word_eol, data, attrs):
|
||||
if not word_eol:
|
||||
return api.EAT_NONE
|
||||
parsed = _parse(word_eol[0])
|
||||
if parsed is None or parsed[0] != command:
|
||||
return api.EAT_NONE
|
||||
event = IRCEvent(*(parsed + (api.get_context(), api.get_prefs('id'), attrs.time)))
|
||||
return callback(event, data)
|
||||
|
||||
return api.hook_server_attrs(command, dispatch, userdata, priority)
|
||||
|
||||
|
||||
def on_join(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('JOIN', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_part(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('PART', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_quit(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('QUIT', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_nick(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('NICK', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_kick(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('KICK', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_message(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('PRIVMSG', callback, userdata, priority)
|
||||
|
||||
|
||||
def on_notice(callback, userdata=None, priority=api.PRI_NORM):
|
||||
return hook_event('NOTICE', callback, userdata, priority)
|
||||
Reference in New Issue
Block a user