mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-11-08 17:05:38 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
668c3cc0d7 |
No files matched your search
@@ -1,19 +0,0 @@
|
||||
# Python descriptor hooks
|
||||
|
||||
`hook_fd(fd, callback, userdata=None, flags=FD_READ)` returns an ordinary hook
|
||||
handle accepted by `unhook()`. Callback arguments are `(fd, ready_flags, userdata)`;
|
||||
return True to retain the watch and False/None to remove it. Exceptions print a
|
||||
traceback and remove the watch. Unloading the script removes its watches.
|
||||
The callback runs in the context captured during registration, and that context
|
||||
is restored afterwards. A closed context removes the watch.
|
||||
|
||||
Use nonblocking IO and bounded reads/writes. The descriptor belongs to the script;
|
||||
unhook before closing it. On Windows socket descriptors use the default flags;
|
||||
CRT descriptors need FD_NOTSOCKET. The existing C API uses int descriptors: values
|
||||
outside its range are rejected rather than truncated. This does not add threads.
|
||||
|
||||
Example:
|
||||
```python
|
||||
watch = zoitechat.hook_fd(sock.fileno(), on_readable, flags=zoitechat.FD_READ)
|
||||
# def on_readable(fd, flags, userdata): ...; return True
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
# Core-filtered hooks
|
||||
|
||||
Python: `hook_server_filtered(name, callback, userdata=None, priority=PRI_NORM,
|
||||
connection_id=None, channel=None)` and `hook_print_filtered(...)`.
|
||||
Callbacks match the existing attrs variants: `(word, word_eol, userdata, attrs)`.
|
||||
The connection ID distinguishes duplicate names; None/-1 means any connection
|
||||
(including connection ID zero). A channel restriction uses that connection's
|
||||
IRC comparator. None means any context; an empty string is an exact restriction.
|
||||
|
||||
C: the corresponding zoitechat_hook_*_filtered functions accept
|
||||
`(ph, name, pri, flags, connection_id, channel, callback, userdata)`;
|
||||
flags=0, ID=-1 for any and NULL channel for any. Check
|
||||
`get_info("api_context_filters")` for "1" before accessing the new Windows slots.
|
||||
|
||||
Filtering takes place before Python/interpreter entry. Existing unrestricted
|
||||
hooks, priority, EAT semantics and unload/unhook handling are unchanged.
|
||||
Filters refer to the core-selected context, not an IRC target parsed from the
|
||||
line: unknown queries/channels can still have a server-tab context, and QUIT
|
||||
has its usual single server-hook context. Connection IDs last only this process.
|
||||
|
||||
```python
|
||||
zoitechat.hook_print_filtered('Channel Message', callback,
|
||||
connection_id=zoitechat.get_prefs('id'), channel='#zoitechat')
|
||||
```
|
||||
@@ -1,39 +0,0 @@
|
||||
"""File descriptor readiness hooks; callbacks execute on the main thread."""
|
||||
import operator
|
||||
import _zoitechat as api
|
||||
from _zoitechat_embedded import ffi, lib
|
||||
|
||||
__all__ = ['FD_READ', 'FD_WRITE', 'FD_EXCEPTION', 'FD_NOTSOCKET', 'hook_fd']
|
||||
FD_READ, FD_WRITE, FD_EXCEPTION, FD_NOTSOCKET = 1, 2, 4, 8
|
||||
|
||||
|
||||
def hook_fd(fd, callback, userdata=None, flags=FD_READ):
|
||||
"""callback(fd, ready_flags, userdata): True keeps the watch, False removes it."""
|
||||
fd = operator.index(fd)
|
||||
flags = operator.index(flags)
|
||||
if fd < 0 or fd > 2147483647:
|
||||
raise ValueError('fd must fit the C API nonnegative int descriptor')
|
||||
if flags & ~15 or not flags & 7:
|
||||
raise ValueError('flags must select READ, WRITE or EXCEPTION')
|
||||
if not callable(callback):
|
||||
raise TypeError('callback must be callable')
|
||||
plugin = api.__get_current_plugin()
|
||||
context = api.get_context()
|
||||
|
||||
def dispatch(descriptor, ready, data):
|
||||
previous = api.get_context()
|
||||
if not context.set():
|
||||
return False
|
||||
try:
|
||||
return callback(descriptor, ready, data)
|
||||
finally:
|
||||
previous.set()
|
||||
|
||||
hook = plugin.add_hook(dispatch, userdata)
|
||||
handle = lib.zoitechat_hook_fd(lib.ph, fd, flags, lib._on_fd_hook, hook.handle)
|
||||
if handle == ffi.NULL:
|
||||
hook.is_unload = True
|
||||
plugin.remove_hook(id(hook))
|
||||
raise RuntimeError('unable to watch descriptor')
|
||||
hook.zoitechat_hook = handle
|
||||
return id(hook)
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Context restrictions evaluated by core before entering Python."""
|
||||
import operator
|
||||
import _zoitechat as api
|
||||
from _zoitechat_embedded import ffi, lib
|
||||
|
||||
__all__ = ['hook_server_filtered', 'hook_print_filtered']
|
||||
|
||||
|
||||
def _register(name, callback, userdata, priority, connection_id, channel, server):
|
||||
if not callable(callback):
|
||||
raise TypeError('callback must be callable')
|
||||
connection_id = -1 if connection_id is None else operator.index(connection_id)
|
||||
if connection_id < -1 or connection_id > 2147483647:
|
||||
raise ValueError('connection_id must fit the C API; -1 means any')
|
||||
plugin = api.__get_current_plugin()
|
||||
hook = plugin.add_hook(callback, userdata)
|
||||
register = lib.zoitechat_hook_server_filtered if server else lib.zoitechat_hook_print_filtered
|
||||
dispatch = lib._on_server_attrs_hook if server else lib._on_print_attrs_hook
|
||||
handle = register(lib.ph, name.encode(), priority, 0, connection_id,
|
||||
ffi.NULL if channel is None else channel.encode(), dispatch, hook.handle)
|
||||
if handle == ffi.NULL:
|
||||
hook.is_unload = True
|
||||
plugin.remove_hook(id(hook))
|
||||
raise RuntimeError('unable to install filtered hook')
|
||||
hook.zoitechat_hook = handle
|
||||
return id(hook)
|
||||
|
||||
|
||||
def hook_server_filtered(name, callback, userdata=None, priority=api.PRI_NORM,
|
||||
connection_id=None, channel=None):
|
||||
return _register(name, callback, userdata, priority, connection_id, channel, True)
|
||||
|
||||
|
||||
def hook_print_filtered(name, callback, userdata=None, priority=api.PRI_NORM,
|
||||
connection_id=None, channel=None):
|
||||
return _register(name, callback, userdata, priority, connection_id, channel, False)
|
||||
@@ -38,7 +38,6 @@ extern "Python" int _on_print_attrs_hook(char **, zoitechat_event_attrs *, void
|
||||
extern "Python" int _on_server_hook(char **, char **, void *);
|
||||
extern "Python" int _on_server_attrs_hook(char **, char **, zoitechat_event_attrs *, void *);
|
||||
extern "Python" int _on_timer_hook(void *);
|
||||
extern "Python" int _on_fd_hook(int, int, void *);
|
||||
|
||||
extern "Python" int _on_plugin_init(char **, char **, char **, char *, char *);
|
||||
extern "Python" int _on_plugin_deinit(void);
|
||||
|
||||
@@ -304,28 +304,6 @@ def _on_timer_hook(userdata):
|
||||
return 0
|
||||
|
||||
|
||||
@ffi.def_extern()
|
||||
def _on_fd_hook(fd, flags, userdata):
|
||||
hook = ffi.from_handle(userdata)
|
||||
keep = False
|
||||
try:
|
||||
keep = bool(hook.callback(fd, flags, hook.userdata))
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
if not keep:
|
||||
# The C watch removes itself on return; do not unhook it a second time.
|
||||
try:
|
||||
hook.is_unload = True
|
||||
# from_handle() yields a weak proxy: id(proxy) is not id(Hook).
|
||||
for existing in hook.plugin.hooks:
|
||||
if existing == hook:
|
||||
hook.plugin.remove_hook(id(existing))
|
||||
break
|
||||
except ReferenceError:
|
||||
pass # the callback already unhooked itself
|
||||
return int(keep)
|
||||
|
||||
|
||||
@ffi.def_extern()
|
||||
def _on_say_command(word, word_eol, userdata):
|
||||
"""Handle input in the special >>python<< tab.
|
||||
|
||||
@@ -99,6 +99,9 @@ struct _zoitechat_hook
|
||||
int tag; /* for timers & FDs only */
|
||||
int type; /* HOOK_* */
|
||||
int pri; /* fd */ /* priority / fd for HOOK_FD only */
|
||||
int connection_filter;
|
||||
char *channel_filter;
|
||||
gboolean context_filtered;
|
||||
};
|
||||
|
||||
struct _zoitechat_list
|
||||
@@ -351,6 +354,8 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
|
||||
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
||||
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
||||
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
||||
pl->zoitechat_hook_server_filtered = zoitechat_hook_server_filtered;
|
||||
pl->zoitechat_hook_print_filtered = zoitechat_hook_print_filtered;
|
||||
|
||||
/* run zoitechat_plugin_init, if it returns 0, close the plugin */
|
||||
if (((zoitechat_init_func *)init_func) (pl, &pl->name, &pl->desc, &pl->version, arg) == 0)
|
||||
@@ -621,6 +626,15 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
|
||||
|
||||
hook = list->data;
|
||||
next = list->next;
|
||||
if (hook->context_filtered &&
|
||||
(!is_session (sess) ||
|
||||
(hook->connection_filter != -1 && hook->connection_filter != sess->server->id) ||
|
||||
(hook->channel_filter && sess->server->p_cmp (hook->channel_filter, sess->channel))))
|
||||
{
|
||||
list = next;
|
||||
continue; /* filter in C before entering an interpreter */
|
||||
}
|
||||
|
||||
hook->pl->context = sess;
|
||||
|
||||
/* run the plugin's callback function */
|
||||
@@ -1024,10 +1038,45 @@ zoitechat_unhook (zoitechat_plugin *ph, zoitechat_hook *hook)
|
||||
|
||||
g_free (hook->name); /* NULL for timers & fds */
|
||||
g_free (hook->help_text); /* NULL for non-commands */
|
||||
g_free (hook->channel_filter);
|
||||
hook->channel_filter = NULL;
|
||||
|
||||
return hook->userdata;
|
||||
}
|
||||
|
||||
static zoitechat_hook *
|
||||
plugin_add_filtered_hook (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
int type, void *callback, void *userdata)
|
||||
{
|
||||
zoitechat_hook *hook;
|
||||
if (flags != 0 || connection_id < -1 || !name || !callback)
|
||||
return NULL;
|
||||
hook = plugin_add_hook (ph, type, pri, name, NULL, callback, 0, userdata);
|
||||
hook->context_filtered = TRUE;
|
||||
hook->connection_filter = connection_id;
|
||||
hook->channel_filter = g_strdup (channel);
|
||||
return hook;
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_server_filtered (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
zoitechat_serv_attrs_cb *callback, void *userdata)
|
||||
{
|
||||
return plugin_add_filtered_hook (ph, name, pri, flags, connection_id, channel,
|
||||
HOOK_SERVER_ATTRS, callback, userdata);
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_print_filtered (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
zoitechat_print_attrs_cb *callback, void *userdata)
|
||||
{
|
||||
return plugin_add_filtered_hook (ph, name, pri, flags, connection_id, channel,
|
||||
HOOK_PRINT_ATTRS, callback, userdata);
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
||||
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
||||
@@ -1187,6 +1236,9 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
|
||||
return text_find_format_string (e);
|
||||
}
|
||||
|
||||
if (strcmp (id, "api_context_filters") == 0)
|
||||
return "1";
|
||||
|
||||
hash = str_hash (id);
|
||||
/* do the session independant ones first */
|
||||
switch (hash)
|
||||
|
||||
@@ -206,6 +206,18 @@ struct _zoitechat_plugin
|
||||
#endif
|
||||
|
||||
|
||||
/* api_context_filters=1: connection_id -1 is any; NULL channel is any. */
|
||||
zoitechat_hook *zoitechat_hook_server_filtered (zoitechat_plugin *ph,
|
||||
const char *name, int pri, int flags, int connection_id, const char *channel,
|
||||
int (*callback) (char *word[], char *word_eol[],
|
||||
zoitechat_event_attrs *attrs, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
zoitechat_hook *zoitechat_hook_print_filtered (zoitechat_plugin *ph,
|
||||
const char *name, int pri, int flags, int connection_id, const char *channel,
|
||||
int (*callback) (char *word[], zoitechat_event_attrs *attrs, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_command (zoitechat_plugin *ph,
|
||||
const char *name,
|
||||
@@ -425,6 +437,8 @@ zoitechat_pluginpref_list (zoitechat_plugin *ph,
|
||||
#define zoitechat_hook_server ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server)
|
||||
#define zoitechat_hook_server_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_attrs)
|
||||
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
||||
#define zoitechat_hook_server_filtered ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_filtered)
|
||||
#define zoitechat_hook_print_filtered ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_filtered)
|
||||
#define zoitechat_hook_print_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_attrs)
|
||||
#define zoitechat_hook_timer ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_timer)
|
||||
#define zoitechat_hook_fd ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_fd)
|
||||
|
||||
Reference in new issue
Block a user