mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-11-08 17:05:38 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66c93fe2e1 |
No files matched your search
@@ -0,0 +1,19 @@
|
|||||||
|
# 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
|
||||||
|
```
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Post-display print observers
|
|
||||||
|
|
||||||
Python: `hook_print_after(name, callback, userdata=None, priority=PRI_NORM)`.
|
|
||||||
The callback is `(word, word_eol, userdata, attrs)`, matching hook_print_attrs().
|
|
||||||
It runs after display_event() has handled the text, so prnt() follows the original
|
|
||||||
text. Return values are ignored. Events eaten by a pre-hook or hidden by client
|
|
||||||
preferences do not invoke these observers. This is post-display notification,
|
|
||||||
not a notification that the entire incoming IRC command has finished updating state.
|
|
||||||
|
|
||||||
C: `zoitechat_hook_print_after(ph, name, priority, flags, callback, userdata)`;
|
|
||||||
flags must be zero. Check `get_info("api_hook_print_after")` for "1" before
|
|
||||||
accessing the appended Windows function-table slot. Existing pre-hook timing is
|
|
||||||
unchanged. Unhook/unload use existing lifecycle functions. Recursive emission
|
|
||||||
skips an already-running observer to prevent it immediately invoking itself.
|
|
||||||
|
|
||||||
```python
|
|
||||||
def after(word, word_eol, userdata, attrs):
|
|
||||||
zoitechat.prnt('This follows the original channel message')
|
|
||||||
|
|
||||||
zoitechat.hook_print_after('Channel Message', after)
|
|
||||||
```
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
"""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)
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
"""Opt-in post-display print observers."""
|
|
||||||
import _zoitechat as api
|
|
||||||
from _zoitechat_embedded import ffi, lib
|
|
||||||
|
|
||||||
__all__ = ['hook_print_after']
|
|
||||||
|
|
||||||
|
|
||||||
def hook_print_after(name, callback, userdata=None, priority=api.PRI_NORM):
|
|
||||||
"""callback(word, word_eol, userdata, attrs); its return value is ignored."""
|
|
||||||
if not callable(callback):
|
|
||||||
raise TypeError('callback must be callable')
|
|
||||||
plugin = api.__get_current_plugin()
|
|
||||||
hook = plugin.add_hook(callback, userdata)
|
|
||||||
handle = lib.zoitechat_hook_print_after(lib.ph, name.encode(), priority, 0,
|
|
||||||
lib._on_print_attrs_hook, hook.handle)
|
|
||||||
if handle == ffi.NULL:
|
|
||||||
hook.is_unload = True
|
|
||||||
plugin.remove_hook(id(hook))
|
|
||||||
raise RuntimeError('unable to install post-display hook')
|
|
||||||
hook.zoitechat_hook = handle
|
|
||||||
return id(hook)
|
|
||||||
@@ -38,6 +38,7 @@ 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_hook(char **, char **, void *);
|
||||||
extern "Python" int _on_server_attrs_hook(char **, char **, zoitechat_event_attrs *, 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_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_init(char **, char **, char **, char *, char *);
|
||||||
extern "Python" int _on_plugin_deinit(void);
|
extern "Python" int _on_plugin_deinit(void);
|
||||||
|
|||||||
@@ -304,6 +304,28 @@ def _on_timer_hook(userdata):
|
|||||||
return 0
|
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()
|
@ffi.def_extern()
|
||||||
def _on_say_command(word, word_eol, userdata):
|
def _on_say_command(word, word_eol, userdata):
|
||||||
"""Handle input in the special >>python<< tab.
|
"""Handle input in the special >>python<< tab.
|
||||||
|
|||||||
+1
-41
@@ -143,8 +143,7 @@ enum
|
|||||||
HOOK_PRINT_ATTRS = 1 << 4, /* same as above, with attributes */
|
HOOK_PRINT_ATTRS = 1 << 4, /* same as above, with attributes */
|
||||||
HOOK_TIMER = 1 << 5, /* timeouts */
|
HOOK_TIMER = 1 << 5, /* timeouts */
|
||||||
HOOK_FD = 1 << 6, /* sockets & fds */
|
HOOK_FD = 1 << 6, /* sockets & fds */
|
||||||
HOOK_DELETED = 1 << 7, /* marked for deletion */
|
HOOK_DELETED = 1 << 7 /* marked for deletion */
|
||||||
HOOK_PRINT_AFTER = 1 << 8 /* post-display observers */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -352,7 +351,6 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
|
|||||||
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
||||||
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
||||||
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
||||||
pl->zoitechat_hook_print_after = zoitechat_hook_print_after;
|
|
||||||
|
|
||||||
/* run zoitechat_plugin_init, if it returns 0, close the plugin */
|
/* 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)
|
if (((zoitechat_init_func *)init_func) (pl, &pl->name, &pl->desc, &pl->version, arg) == 0)
|
||||||
@@ -623,13 +621,6 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
|
|||||||
|
|
||||||
hook = list->data;
|
hook = list->data;
|
||||||
next = list->next;
|
next = list->next;
|
||||||
if (type == HOOK_PRINT_AFTER && hook->tag)
|
|
||||||
{
|
|
||||||
list = next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (type == HOOK_PRINT_AFTER)
|
|
||||||
hook->tag = 1;
|
|
||||||
hook->pl->context = sess;
|
hook->pl->context = sess;
|
||||||
|
|
||||||
/* run the plugin's callback function */
|
/* run the plugin's callback function */
|
||||||
@@ -638,7 +629,6 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
|
|||||||
case HOOK_COMMAND:
|
case HOOK_COMMAND:
|
||||||
ret = ((zoitechat_cmd_cb *)hook->callback) (word, word_eol, hook->userdata);
|
ret = ((zoitechat_cmd_cb *)hook->callback) (word, word_eol, hook->userdata);
|
||||||
break;
|
break;
|
||||||
case HOOK_PRINT_AFTER:
|
|
||||||
case HOOK_PRINT_ATTRS:
|
case HOOK_PRINT_ATTRS:
|
||||||
ret = ((zoitechat_print_attrs_cb *)hook->callback) (word, attrs, hook->userdata);
|
ret = ((zoitechat_print_attrs_cb *)hook->callback) (word, attrs, hook->userdata);
|
||||||
break;
|
break;
|
||||||
@@ -653,15 +643,6 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == HOOK_PRINT_AFTER)
|
|
||||||
{
|
|
||||||
hook->tag = 0;
|
|
||||||
if (!is_session (sess))
|
|
||||||
goto xit;
|
|
||||||
list = next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret & ZOITECHAT_EAT_ZOITECHAT) && (ret & ZOITECHAT_EAT_PLUGIN))
|
if ((ret & ZOITECHAT_EAT_ZOITECHAT) && (ret & ZOITECHAT_EAT_PLUGIN))
|
||||||
{
|
{
|
||||||
eat = 1;
|
eat = 1;
|
||||||
@@ -744,15 +725,6 @@ plugin_emit_print (session *sess, char *word[], time_t server_time)
|
|||||||
HOOK_PRINT | HOOK_PRINT_ATTRS);
|
HOOK_PRINT | HOOK_PRINT_ATTRS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
plugin_emit_print_after (session *sess, char *word[], time_t server_time)
|
|
||||||
{
|
|
||||||
zoitechat_event_attrs attrs;
|
|
||||||
attrs.server_time_utc = server_time;
|
|
||||||
if (is_session (sess))
|
|
||||||
plugin_hook_run (sess, word[0], word, NULL, &attrs, HOOK_PRINT_AFTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
plugin_emit_dummy_print (session *sess, char *name)
|
plugin_emit_dummy_print (session *sess, char *name)
|
||||||
{
|
{
|
||||||
@@ -1056,15 +1028,6 @@ zoitechat_unhook (zoitechat_plugin *ph, zoitechat_hook *hook)
|
|||||||
return hook->userdata;
|
return hook->userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
zoitechat_hook *
|
|
||||||
zoitechat_hook_print_after (zoitechat_plugin *ph, const char *name, int pri,
|
|
||||||
int flags, zoitechat_print_attrs_cb *callback, void *userdata)
|
|
||||||
{
|
|
||||||
if (flags != 0 || !name || !callback)
|
|
||||||
return NULL;
|
|
||||||
return plugin_add_hook (ph, HOOK_PRINT_AFTER, pri, name, NULL, callback, 0, userdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
zoitechat_hook *
|
zoitechat_hook *
|
||||||
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
||||||
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
||||||
@@ -1224,9 +1187,6 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
|
|||||||
return text_find_format_string (e);
|
return text_find_format_string (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp (id, "api_hook_print_after") == 0)
|
|
||||||
return "1";
|
|
||||||
|
|
||||||
hash = str_hash (id);
|
hash = str_hash (id);
|
||||||
/* do the session independant ones first */
|
/* do the session independant ones first */
|
||||||
switch (hash)
|
switch (hash)
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ int plugin_emit_command (session *sess, char *name, char *word[], char *word_eol
|
|||||||
int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
|
int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
|
||||||
time_t server_time);
|
time_t server_time);
|
||||||
int plugin_emit_print (session *sess, char *word[], time_t server_time);
|
int plugin_emit_print (session *sess, char *word[], time_t server_time);
|
||||||
void plugin_emit_print_after (session *sess, char *word[], time_t server_time);
|
|
||||||
int plugin_emit_dummy_print (session *sess, char *name);
|
int plugin_emit_dummy_print (session *sess, char *name);
|
||||||
int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gunichar key);
|
int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gunichar key);
|
||||||
GList* plugin_command_list(GList *tmp_list);
|
GList* plugin_command_list(GList *tmp_list);
|
||||||
|
|||||||
@@ -2320,7 +2320,6 @@ text_emit_with_message (int index, session *sess, char *a, char *b, char *c, cha
|
|||||||
if (!prefs.hex_away_omit_alerts || !sess->server->is_away)
|
if (!prefs.hex_away_omit_alerts || !sess->server->is_away)
|
||||||
sound_play_event (index);
|
sound_play_event (index);
|
||||||
display_event (sess, index, word, stripcolor_args, timestamp, message);
|
display_event (sess, index, word, stripcolor_args, timestamp, message);
|
||||||
plugin_emit_print_after (sess, word, timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
|||||||
@@ -206,12 +206,6 @@ struct _zoitechat_plugin
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* api_hook_print_after=1: observer returns are ignored; flags must be zero. */
|
|
||||||
zoitechat_hook *zoitechat_hook_print_after (zoitechat_plugin *ph,
|
|
||||||
const char *name, int pri, int flags,
|
|
||||||
int (*callback) (char *word[], zoitechat_event_attrs *attrs, void *userdata),
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
zoitechat_hook *
|
zoitechat_hook *
|
||||||
zoitechat_hook_command (zoitechat_plugin *ph,
|
zoitechat_hook_command (zoitechat_plugin *ph,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -431,7 +425,6 @@ zoitechat_pluginpref_list (zoitechat_plugin *ph,
|
|||||||
#define zoitechat_hook_server ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server)
|
#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_server_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_attrs)
|
||||||
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
||||||
#define zoitechat_hook_print_after ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_after)
|
|
||||||
#define zoitechat_hook_print_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_attrs)
|
#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_timer ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_timer)
|
||||||
#define zoitechat_hook_fd ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_fd)
|
#define zoitechat_hook_fd ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_fd)
|
||||||
|
|||||||
Reference in new issue
Block a user