move callbacks into python class, simplify demobot

This commit is contained in:
saces 2026-02-03 21:20:29 +01:00
parent 260386bcac
commit 05020f126e
4 changed files with 103 additions and 72 deletions

View file

@ -16,15 +16,15 @@ import (
/* /*
#include <stdlib.h> #include <stdlib.h>
typedef void (*on_event_handler_ptr) (char*); typedef void (*on_event_handler_ptr) (char*, void*);
typedef void (*on_message_handler_ptr) (char*); typedef void (*on_message_handler_ptr) (char*, void*);
static inline void call_c_on_event_handler(on_event_handler_ptr ptr, char* jsonStr) { static inline void call_c_on_event_handler(on_event_handler_ptr ptr, char* jsonStr, void* pobj) {
(ptr)(jsonStr); (ptr)(jsonStr, pobj);
} }
static inline void call_c_on_message_handler(on_message_handler_ptr ptr, char* jsonStr) { static inline void call_c_on_message_handler(on_message_handler_ptr ptr, char* jsonStr, void* pobj) {
(ptr)(jsonStr); (ptr)(jsonStr, pobj);
} }
*/ */
@ -36,27 +36,31 @@ matrix client with c callback
type CBClient struct { type CBClient struct {
*mxclient.MXClient *mxclient.MXClient
on_event_handler C.on_event_handler_ptr on_event_handler C.on_event_handler_ptr
on_event_handler_pobj unsafe.Pointer
on_message_handler C.on_message_handler_ptr on_message_handler C.on_message_handler_ptr
on_message_handler_pobj unsafe.Pointer
} }
func (cli *CBClient) OnEvent(s string) { func (cli *CBClient) OnEvent(s string) {
cStr := C.CString(s) cStr := C.CString(s)
defer C.free(unsafe.Pointer(cStr)) defer C.free(unsafe.Pointer(cStr))
C.call_c_on_event_handler(cli.on_event_handler, cStr) C.call_c_on_event_handler(cli.on_event_handler, cStr, cli.on_event_handler_pobj)
} }
func (cli *CBClient) OnMessage(s string) { func (cli *CBClient) OnMessage(s string) {
cStr := C.CString(s) cStr := C.CString(s)
defer C.free(unsafe.Pointer(cStr)) defer C.free(unsafe.Pointer(cStr))
C.call_c_on_message_handler(cli.on_message_handler, cStr) C.call_c_on_message_handler(cli.on_message_handler, cStr, cli.on_message_handler_pobj)
} }
func (cli *CBClient) Set_on_event_handler(fn C.on_event_handler_ptr) { func (cli *CBClient) Set_on_event_handler(fn C.on_event_handler_ptr, pobj unsafe.Pointer) {
cli.on_event_handler = fn cli.on_event_handler = fn
cli.on_event_handler_pobj = pobj
} }
func (cli *CBClient) Set_on_message_handler(fn C.on_message_handler_ptr) { func (cli *CBClient) Set_on_message_handler(fn C.on_message_handler_ptr, pobj unsafe.Pointer) {
cli.on_message_handler = fn cli.on_message_handler = fn
cli.on_message_handler_pobj = pobj
} }
// NewCClient creates a new Matrix Client ready for syncing // NewCClient creates a new Matrix Client ready for syncing
@ -65,7 +69,7 @@ func NewCBClient(homeserverURL string, userID id.UserID, accessToken string) (*C
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &CBClient{client, nil, nil}, nil return &CBClient{client, nil, nil, nil, nil}, nil
} }
/* /*
@ -179,7 +183,7 @@ func apiv0_createclient(storage_path *C.char, url *C.char, userID *C.char, acces
if err != nil { if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err)) return C.CString(fmt.Sprintf("ERR: %v", err))
} }
client := &CBClient{mxclient, nil, nil} client := &CBClient{mxclient, nil, nil, nil, nil}
cclients = append(cclients, client) cclients = append(cclients, client)
return C.CString(fmt.Sprintf("{ \"id:\"SUCESS. ID=%d\n", len(cclients))) return C.CString(fmt.Sprintf("{ \"id:\"SUCESS. ID=%d\n", len(cclients)))
} }
@ -190,7 +194,7 @@ func apiv0_createclient_pass(mxpassfile_path *C.char, storage_path *C.char, url
if err != nil { if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err)) return C.CString(fmt.Sprintf("ERR: %v", err))
} }
client := &CBClient{mxclient, nil, nil} client := &CBClient{mxclient, nil, nil, nil, nil}
mxclient.OnEvent = client.OnEvent mxclient.OnEvent = client.OnEvent
mxclient.OnMessage = client.OnMessage mxclient.OnMessage = client.OnMessage
cclients = append(cclients, client) cclients = append(cclients, client)
@ -203,24 +207,24 @@ func apiv0_createclient_pass(mxpassfile_path *C.char, storage_path *C.char, url
} }
//export apiv0_set_on_event_handler //export apiv0_set_on_event_handler
func apiv0_set_on_event_handler(cid C.int, fn C.on_event_handler_ptr) *C.char { func apiv0_set_on_event_handler(cid C.int, fn C.on_event_handler_ptr, pobj unsafe.Pointer) *C.char {
cli, err := getClient(int(cid)) cli, err := getClient(int(cid))
if err != nil { if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err)) return C.CString(fmt.Sprintf("ERR: %v", err))
} }
cli.Set_on_event_handler(fn) cli.Set_on_event_handler(fn, pobj)
return C.CString("SUCCESS.") return C.CString("SUCCESS.")
} }
//export apiv0_set_on_message_handler //export apiv0_set_on_message_handler
func apiv0_set_on_message_handler(cid C.int, fn C.on_message_handler_ptr) *C.char { func apiv0_set_on_message_handler(cid C.int, fn C.on_message_handler_ptr, pobj unsafe.Pointer) *C.char {
cli, err := getClient(int(cid)) cli, err := getClient(int(cid))
if err != nil { if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err)) return C.CString(fmt.Sprintf("ERR: %v", err))
} }
cli.Set_on_message_handler(fn) cli.Set_on_message_handler(fn, pobj)
return C.CString("SUCCESS.") return C.CString("SUCCESS.")
} }

View file

@ -13,8 +13,8 @@ ffibuilder.set_source(
ffibuilder.cdef( ffibuilder.cdef(
csource=""" csource="""
typedef void (*on_event_handler_ptr) (char*); typedef void (*on_event_handler_ptr) (char*, void*);
typedef void (*on_message_handler_ptr) (char*); typedef void (*on_message_handler_ptr) (char*, void*);
extern void FreeCString(char* s); extern void FreeCString(char* s);
extern char* cli_discoverhs(char* mxid); extern char* cli_discoverhs(char* mxid);
extern char* cli_mkmxtoken(char* mxid, char* pw); extern char* cli_mkmxtoken(char* mxid, char* pw);
@ -28,8 +28,8 @@ ffibuilder.cdef(
extern char* apiv0_login(char* data); extern char* apiv0_login(char* data);
extern char* apiv0_createclient(char* storage_path, char* hs, char* mxid, char* accessToken); extern char* apiv0_createclient(char* storage_path, char* hs, char* mxid, char* accessToken);
extern char* apiv0_createclient_pass(char* mxpassfile, char* storage_path, char* hs, char* localpart, char* domain); extern char* apiv0_createclient_pass(char* mxpassfile, char* storage_path, char* hs, char* localpart, char* domain);
extern char* apiv0_set_on_event_handler(int cid, on_event_handler_ptr ptr); extern char* apiv0_set_on_event_handler(int cid, on_event_handler_ptr ptr, void* pobj);
extern char* apiv0_set_on_message_handler(int cid, on_message_handler_ptr ptr); extern char* apiv0_set_on_message_handler(int cid, on_message_handler_ptr ptr, void* pobj);
extern char* apiv0_startclient(int cid); extern char* apiv0_startclient(int cid);
extern char* apiv0_stopclient(int cid); extern char* apiv0_stopclient(int cid);
extern char* apiv0_sendmessage(int cid, char* data); extern char* apiv0_sendmessage(int cid, char* data);

View file

@ -3,7 +3,6 @@ from time import time_ns
import logging import logging
import json import json
from smal.bot import SMALBot from smal.bot import SMALBot
from _pygomx import lib, ffi
# setup logging, we want timestamps # setup logging, we want timestamps
logging.basicConfig( logging.basicConfig(
@ -18,17 +17,12 @@ logger.setLevel(level=logging.INFO)
DEFAULT_PREFIX = "!" DEFAULT_PREFIX = "!"
@ffi.callback("void(char*)") class DemoBot(SMALBot):
def on_event(evt):
e = ffi.string(evt) def on_event(self, evt):
print("Got an event: ", e) print("Got an event: ", e)
def on_message(self, msg):
@ffi.callback("void(char*)")
def on_message(msg):
m = ffi.string(msg).decode("utf-8")
msg = json.loads(m)
if msg["type"] != "m.room.message": if msg["type"] != "m.room.message":
# not a room message # not a room message
@ -64,9 +58,7 @@ def on_message(msg):
def main(): def main():
# create and run the bot # create and run the bot
global bot global bot
bot = SMALBot(DEFAULT_PREFIX) bot = DemoBot(DEFAULT_PREFIX)
bot.SetOnEventHandler(on_event)
bot.SetOnMessageHandler(on_message)
bot.run() bot.run()

View file

@ -15,6 +15,26 @@ class _MXClient:
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._createMXClient() self._createMXClient()
# ffi_selfhandle = ffi.new_handle(self)
# self._ffi_selfhandle = ffi_selfhandle
self._ffi_selfhandle = ffi.new_handle(self)
# self._ffi_selfhandle = ffi_selfhandle
r = lib.apiv0_set_on_event_handler(
self.client_id, on_event_callback, self._ffi_selfhandle
)
result = ffi.string(r)
lib.FreeCString(r)
if result.startswith(b"ERR:"):
raise APIError(result)
r = lib.apiv0_set_on_message_handler(
self.client_id, on_message_callback, self._ffi_selfhandle
)
result = ffi.string(r)
lib.FreeCString(r)
if result.startswith(b"ERR:"):
raise APIError(result)
def _createMXClient(self): def _createMXClient(self):
r = lib.apiv0_createclient_pass(b".mxpass", b".", b"*", b"*", b"*") r = lib.apiv0_createclient_pass(b".mxpass", b".", b"*", b"*", b"*")
@ -27,20 +47,6 @@ class _MXClient:
result_dict = json.loads(result) result_dict = json.loads(result)
self.client_id = result_dict["id"] self.client_id = result_dict["id"]
def SetOnEventHandler(self, fn):
r = lib.apiv0_set_on_event_handler(self.client_id, fn)
result = ffi.string(r)
lib.FreeCString(r)
if result.startswith(b"ERR:"):
raise APIError(result)
def SetOnMessageHandler(self, fn):
r = lib.apiv0_set_on_message_handler(self.client_id, fn)
result = ffi.string(r)
lib.FreeCString(r)
if result.startswith(b"ERR:"):
raise APIError(result)
def _sync(self): def _sync(self):
r = lib.apiv0_startclient(self.client_id) r = lib.apiv0_startclient(self.client_id)
result = ffi.string(r) result = ffi.string(r)
@ -65,3 +71,32 @@ class _MXClient:
# if result.startswith(b"ERR:"): # if result.startswith(b"ERR:"):
# raise APIError(result) # raise APIError(result)
print("_sendmessage: ", result) print("_sendmessage: ", result)
def process_event(self, evt):
if hasattr(self, "on_event") and callable(self.on_event):
self.on_event(evt)
else:
logger.warn(f"got event but on_event not declared: {evt}")
def process_message(self, msg):
if hasattr(self, "on_message") and callable(self.on_message):
self.on_message(msg)
else:
logger.warn(f"got message but on_message not declared: {msg}")
self._stopsync()
@ffi.callback("void(char*, void*)")
def on_event_callback(evt, pobj):
cli = ffi.from_handle(pobj)
e = ffi.string(evt).decode("utf-8")
evt = json.loads(e)
cli.process_event(evt)
@ffi.callback("void(char*, void*)")
def on_message_callback(msg, pobj):
cli = ffi.from_handle(pobj)
m = ffi.string(msg).decode("utf-8")
msg = json.loads(m)
cli.process_message(msg)