diff --git a/libmxclient/mxclientlib.go b/libmxclient/mxclientlib.go index bb1ab03..c2d4928 100644 --- a/libmxclient/mxclientlib.go +++ b/libmxclient/mxclientlib.go @@ -16,15 +16,15 @@ import ( /* #include -typedef void (*on_event_handler_ptr) (char*); -typedef void (*on_message_handler_ptr) (char*); +typedef void (*on_event_handler_ptr) (char*, void*); +typedef void (*on_message_handler_ptr) (char*, void*); -static inline void call_c_on_event_handler(on_event_handler_ptr ptr, char* jsonStr) { - (ptr)(jsonStr); +static inline void call_c_on_event_handler(on_event_handler_ptr ptr, char* jsonStr, void* pobj) { + (ptr)(jsonStr, pobj); } -static inline void call_c_on_message_handler(on_message_handler_ptr ptr, char* jsonStr) { - (ptr)(jsonStr); +static inline void call_c_on_message_handler(on_message_handler_ptr ptr, char* jsonStr, void* pobj) { + (ptr)(jsonStr, pobj); } */ @@ -35,28 +35,32 @@ matrix client with c callback */ type CBClient struct { *mxclient.MXClient - on_event_handler C.on_event_handler_ptr - on_message_handler C.on_message_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_pobj unsafe.Pointer } func (cli *CBClient) OnEvent(s string) { cStr := C.CString(s) 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) { cStr := C.CString(s) 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_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_pobj = pobj } // 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 { 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 { return C.CString(fmt.Sprintf("ERR: %v", err)) } - client := &CBClient{mxclient, nil, nil} + client := &CBClient{mxclient, nil, nil, nil, nil} cclients = append(cclients, client) 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 { 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.OnMessage = client.OnMessage 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 -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)) if err != nil { 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.") } //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)) if err != nil { 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.") } diff --git a/pygomx/build_ffi.py b/pygomx/build_ffi.py index bea8deb..3e260ef 100644 --- a/pygomx/build_ffi.py +++ b/pygomx/build_ffi.py @@ -13,8 +13,8 @@ ffibuilder.set_source( ffibuilder.cdef( csource=""" - typedef void (*on_event_handler_ptr) (char*); - typedef void (*on_message_handler_ptr) (char*); + typedef void (*on_event_handler_ptr) (char*, void*); + typedef void (*on_message_handler_ptr) (char*, void*); extern void FreeCString(char* s); extern char* cli_discoverhs(char* mxid); extern char* cli_mkmxtoken(char* mxid, char* pw); @@ -28,8 +28,8 @@ ffibuilder.cdef( extern char* apiv0_login(char* data); 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_set_on_event_handler(int cid, on_event_handler_ptr ptr); - extern char* apiv0_set_on_message_handler(int cid, on_message_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, void* pobj); extern char* apiv0_startclient(int cid); extern char* apiv0_stopclient(int cid); extern char* apiv0_sendmessage(int cid, char* data); diff --git a/smal/src/demobot/demobot.py b/smal/src/demobot/demobot.py index 03dfae2..d89aa42 100644 --- a/smal/src/demobot/demobot.py +++ b/smal/src/demobot/demobot.py @@ -3,7 +3,6 @@ from time import time_ns import logging import json from smal.bot import SMALBot -from _pygomx import lib, ffi # setup logging, we want timestamps logging.basicConfig( @@ -18,55 +17,48 @@ logger.setLevel(level=logging.INFO) DEFAULT_PREFIX = "!" -@ffi.callback("void(char*)") -def on_event(evt): - e = ffi.string(evt) - print("Got an event: ", e) +class DemoBot(SMALBot): + def on_event(self, evt): + print("Got an event: ", e) -@ffi.callback("void(char*)") -def on_message(msg): - m = ffi.string(msg).decode("utf-8") + def on_message(self, msg): - msg = json.loads(m) + if msg["type"] != "m.room.message": + # not a room message + logger.error(f"not a room message: {msg}") + return - if msg["type"] != "m.room.message": - # not a room message - logger.error(f"not a room message: {msg}") - return + if msg["sender"] == "get own id from missing code": + # ignore own messages + # for now just do not send valid commands by yourself + logger.info(f"ignore own message: {msg}") + return - if msg["sender"] == "get own id from missing code": - # ignore own messages - # for now just do not send valid commands by yourself - logger.info(f"ignore own message: {msg}") - return + if "msgtype" in msg["content"].keys() and msg["content"]["msgtype"] != "m.text": + # only react to messages, not emotes + logger.debug(f"ignore unknown message type: {msg}") + return - if "msgtype" in msg["content"].keys() and msg["content"]["msgtype"] != "m.text": - # only react to messages, not emotes - logger.debug(f"ignore unknown message type: {msg}") - return + if msg["content"]["body"] == "!stop": + logger.info(f"stopping the bot") + bot.stop() + return - if msg["content"]["body"] == "!stop": - logger.info(f"stopping the bot") - bot.stop() - return + if msg["content"]["body"].startswith("!echo"): + logger.error(f"reply to this: {msg}") - if msg["content"]["body"].startswith("!echo"): - logger.error(f"reply to this: {msg}") + bot.sendmessage(msg["roomid"], "huhu") - bot.sendmessage(msg["roomid"], "huhu") + return - return - - logger.info(f"ignored a message: {msg}") + logger.info(f"ignored a message: {msg}") def main(): # create and run the bot global bot - bot = SMALBot(DEFAULT_PREFIX) - bot.SetOnEventHandler(on_event) - bot.SetOnMessageHandler(on_message) + bot = DemoBot(DEFAULT_PREFIX) bot.run() diff --git a/smal/src/smal/pygomx.py b/smal/src/smal/pygomx.py index 78e691d..2f0dfa2 100644 --- a/smal/src/smal/pygomx.py +++ b/smal/src/smal/pygomx.py @@ -15,6 +15,26 @@ class _MXClient: def __init__(self): super().__init__() 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): r = lib.apiv0_createclient_pass(b".mxpass", b".", b"*", b"*", b"*") @@ -27,20 +47,6 @@ class _MXClient: result_dict = json.loads(result) 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): r = lib.apiv0_startclient(self.client_id) result = ffi.string(r) @@ -65,3 +71,32 @@ class _MXClient: # if result.startswith(b"ERR:"): # raise APIError(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)