From 456b3d273d2adad910fd8d77ef35822bda89d7aa Mon Sep 17 00:00:00 2001 From: Aya Hassan Date: Thu, 19 Feb 2026 02:13:55 +0100 Subject: [PATCH 1/5] Add wrapper for first function --- waku/wrapper.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 waku/wrapper.py diff --git a/waku/wrapper.py b/waku/wrapper.py new file mode 100644 index 0000000..e69de29 From 0f401533274f3248c07ccb29bac6346c7826eadd Mon Sep 17 00:00:00 2001 From: Aya Hassan Date: Thu, 19 Feb 2026 13:22:44 +0100 Subject: [PATCH 2/5] Add first function wrapper --- waku/wrapper.py | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/waku/wrapper.py b/waku/wrapper.py index e69de29..f2cba26 100644 --- a/waku/wrapper.py +++ b/waku/wrapper.py @@ -0,0 +1,52 @@ +from cffi import FFI +from pathlib import Path +import json + + +config = { + "relay": True, + "discv5Discovery": True, + "peerExchange": True, + "clusterId": 3, + "shard": 0, + "rlnRelay": False +} +config_json1 = json.dumps(config) +ffi = FFI() + +_repo_root = Path(__file__).resolve().parents[1] +lib = ffi.dlopen(str(_repo_root / "lib" / "liblogosdelivery.so")) + +ffi.cdef(""" + typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData); + + void *logosdelivery_create_node( + const char *configJson, + FFICallBack callback, + void *userData + ); +""") + +def process_callback(ret, char_p, length, callback): + byte_string = ffi.buffer(char_p, length)[:] if char_p != ffi.NULL and length else b"" + callback(ret, byte_string) + +CallbackType = ffi.callback("void(int, const char*, size_t, void*)") + +def logosdelivery_create_node(config_json, callback): + def cb(ret, char_p, length, userData): + process_callback(ret, char_p, length, callback) + + return lib.logosdelivery_create_node( + config_json.encode("utf-8"), + CallbackType(cb), + ffi.cast("void*", 0), + ) + +if __name__ == "__main__": + def cb(ret, msg): + print("ret:", ret) + print("msg:", msg) + + ctx = logosdelivery_create_node(config_json1, cb) + print("ctx:", ctx) \ No newline at end of file From cab26c889fc3abb82487a520ec9a143be52a5c93 Mon Sep 17 00:00:00 2001 From: Aya Hassan Date: Thu, 19 Feb 2026 14:47:08 +0100 Subject: [PATCH 3/5] test create node API and add start node API --- waku/wrapper.py | 91 +++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/waku/wrapper.py b/waku/wrapper.py index f2cba26..3403270 100644 --- a/waku/wrapper.py +++ b/waku/wrapper.py @@ -1,52 +1,75 @@ +import json from cffi import FFI from pathlib import Path -import json - -config = { - "relay": True, - "discv5Discovery": True, - "peerExchange": True, - "clusterId": 3, - "shard": 0, - "rlnRelay": False -} -config_json1 = json.dumps(config) ffi = FFI() +ffi.cdef(""" +typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData); + +void *logosdelivery_create_node( + const char *configJson, + FFICallBack callback, + void *userData +); + +int logosdelivery_start_node( + void *ctx, + FFICallBack callback, + void *userData +); +""") + _repo_root = Path(__file__).resolve().parents[1] lib = ffi.dlopen(str(_repo_root / "lib" / "liblogosdelivery.so")) -ffi.cdef(""" - typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData); - - void *logosdelivery_create_node( - const char *configJson, - FFICallBack callback, - void *userData - ); -""") - -def process_callback(ret, char_p, length, callback): - byte_string = ffi.buffer(char_p, length)[:] if char_p != ffi.NULL and length else b"" - callback(ret, byte_string) - CallbackType = ffi.callback("void(int, const char*, size_t, void*)") -def logosdelivery_create_node(config_json, callback): - def cb(ret, char_p, length, userData): - process_callback(ret, char_p, length, callback) +class NodeHandle: + def __init__(self, ctx, cb_handle): + self.ctx = ctx + self._cb_handle = cb_handle # keep callback alive - return lib.logosdelivery_create_node( - config_json.encode("utf-8"), - CallbackType(cb), - ffi.cast("void*", 0), +def logosdelivery_create_node(config: dict, py_callback): + config_json = json.dumps(config, separators=(",", ":"), ensure_ascii=False) + cnfig_bytes = config_json.encode("utf-8") + + def c_cb(ret, char_p, length, userData): + if char_p != ffi.NULL and length : + msg = ffi.buffer(char_p, length)[:] + else : + msg = b"" + py_callback(ret, msg) + + cb_handle = CallbackType(c_cb) + ctx = lib.logosdelivery_create_node( + cnfig_bytes, + cb_handle, + ffi.NULL, ) + return NodeHandle(ctx, cb_handle) if __name__ == "__main__": + config = { + "logLevel": "DEBUG", + "mode": "Core", + "protocolsConfig": { + "entryNodes": [ + "/dns4/node-01.do-ams3.misc.logos-chat.status.im/tcp/30303/p2p/16Uiu2HAkxoqUTud5LUPQBRmkeL2xP4iKx2kaABYXomQRgmLUgf78" + ], + "clusterId": 3, + "autoShardingConfig": {"numShardsInCluster": 8}, + }, + "networkingConfig": { + "listenIpv4": "0.0.0.0", + "p2pTcpPort": 60000, + "discv5UdpPort": 9000, + }, + } + def cb(ret, msg): print("ret:", ret) print("msg:", msg) - ctx = logosdelivery_create_node(config_json1, cb) - print("ctx:", ctx) \ No newline at end of file + h = logosdelivery_create_node(config, cb) + print("ctx:", h.ctx) From 36a8b2945d3592d3dd77fd240623a1116efcc92c Mon Sep 17 00:00:00 2001 From: Aya Hassan Date: Sun, 22 Feb 2026 19:55:07 +0100 Subject: [PATCH 4/5] Add rest of wrappers --- waku/wrapper.py | 176 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 24 deletions(-) diff --git a/waku/wrapper.py b/waku/wrapper.py index 3403270..f338942 100644 --- a/waku/wrapper.py +++ b/waku/wrapper.py @@ -18,6 +18,38 @@ int logosdelivery_start_node( FFICallBack callback, void *userData ); + +int logosdelivery_stop_node( + void *ctx, + FFICallBack callback, + void *userData +); + +void logosdelivery_set_event_callback( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_destroy( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_subscribe( + void *ctx, + FFICallBack callback, + void *userData, + const char *contentTopic +); + +int logosdelivery_unsubscribe( + void *ctx, + FFICallBack callback, + void *userData, + const char *contentTopic +); """) _repo_root = Path(__file__).resolve().parents[1] @@ -25,29 +57,112 @@ lib = ffi.dlopen(str(_repo_root / "lib" / "liblogosdelivery.so")) CallbackType = ffi.callback("void(int, const char*, size_t, void*)") -class NodeHandle: - def __init__(self, ctx, cb_handle): + +class NodeWrapper: + def __init__(self, ctx, config_buffer): self.ctx = ctx - self._cb_handle = cb_handle # keep callback alive + self._config_buffer = config_buffer + self._event_cb_handler = None -def logosdelivery_create_node(config: dict, py_callback): - config_json = json.dumps(config, separators=(",", ":"), ensure_ascii=False) - cnfig_bytes = config_json.encode("utf-8") - - def c_cb(ret, char_p, length, userData): - if char_p != ffi.NULL and length : + @staticmethod + def _make_cb(py_callback): + def c_cb(ret, char_p, length, userData): msg = ffi.buffer(char_p, length)[:] - else : - msg = b"" - py_callback(ret, msg) + py_callback(ret, msg) + + return CallbackType(c_cb) + + @classmethod + def create_node(cls, config: dict, py_callback): + config_json = json.dumps(config, separators=(",", ":"), ensure_ascii=False) + config_buffer = ffi.new("char[]", config_json.encode("utf-8")) + + cb = cls._make_cb(py_callback) + + ctx = lib.logosdelivery_create_node( + config_buffer, + cb, + ffi.NULL, + ) + + return cls(ctx, config_buffer) + + def start_node(self, py_callback): + cb = self._make_cb(py_callback) + + ret = lib.logosdelivery_start_node( + self.ctx, + cb, + ffi.NULL, + ) + + return int(ret) + + @classmethod + def create_and_start(cls, config: dict, create_cb, start_cb): + node = cls.create_node(config, create_cb) + rc = node.start_node(start_cb) + return node, rc + + def stop_node(self, py_callback): + cb = self._make_cb(py_callback) + + ret = lib.logosdelivery_stop_node( + self.ctx, + cb, + ffi.NULL, + ) + + return int(ret) + + self._event_cb_handler = cb + + def destroy(self, py_callback): + cb = self._make_cb(py_callback) + + ret = lib.logosdelivery_destroy( + self.ctx, + cb, + ffi.NULL, + ) + + return int(ret) + + def stop_and_destroy(self, callback): + stop_rc = self.stop_node(callback) + if stop_rc != 0: + raise RuntimeError(f"Stop failed (ret={stop_rc})") + + destroy_rc = self.destroy(callback) + if destroy_rc != 0: + raise RuntimeError(f"Destroy failed (ret={destroy_rc})") + + return 0 + + def subscribe_content_topic(self, content_topic: str, py_callback): + cb = self._make_cb(py_callback) + + ret = lib.logosdelivery_subscribe( + self.ctx, + cb, + ffi.NULL, + content_topic.encode("utf-8"), + ) + + return int(ret) + + def unsubscribe_content_topic(self, content_topic: str, py_callback): + cb = self._make_cb(py_callback) + + ret = lib.logosdelivery_unsubscribe( + self.ctx, + cb, + ffi.NULL, + content_topic.encode("utf-8"), + ) + + return int(ret) - cb_handle = CallbackType(c_cb) - ctx = lib.logosdelivery_create_node( - cnfig_bytes, - cb_handle, - ffi.NULL, - ) - return NodeHandle(ctx, cb_handle) if __name__ == "__main__": config = { @@ -57,7 +172,7 @@ if __name__ == "__main__": "entryNodes": [ "/dns4/node-01.do-ams3.misc.logos-chat.status.im/tcp/30303/p2p/16Uiu2HAkxoqUTud5LUPQBRmkeL2xP4iKx2kaABYXomQRgmLUgf78" ], - "clusterId": 3, + "clusterId": 42, "autoShardingConfig": {"numShardsInCluster": 8}, }, "networkingConfig": { @@ -68,8 +183,21 @@ if __name__ == "__main__": } def cb(ret, msg): - print("ret:", ret) - print("msg:", msg) + print("ret:", ret, "msg:", msg) - h = logosdelivery_create_node(config, cb) - print("ctx:", h.ctx) + node = NodeWrapper.create_node(config, cb) + rc = node.start_node(cb) + print("start rc:", rc) + + topic = "/myapp/1/chat/proto" + rc = node.subscribe(topic, cb) + print("subscribe rc:", rc) + + rc = node.unsubscribe(topic, cb) + print("unsubscribe rc:", rc) + + rc = node.stop_node(cb) + print("stop rc:", rc) + + rc = node.destroy(cb) + print("destroy rc:", rc) \ No newline at end of file From 1f67f2ee5b93ae3a8b61e73ac9ba7edb2bd8f2f6 Mon Sep 17 00:00:00 2001 From: Aya Hassan Date: Tue, 24 Feb 2026 06:44:14 +0100 Subject: [PATCH 5/5] Finalize wrappers --- waku/wrapper.py | 46 +++++++++++----------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/waku/wrapper.py b/waku/wrapper.py index f338942..a354320 100644 --- a/waku/wrapper.py +++ b/waku/wrapper.py @@ -163,41 +163,17 @@ class NodeWrapper: return int(ret) + def set_event_callback(self, py_callback): + def c_cb(ret, char_p, length, userData): + msg = ffi.buffer(char_p, length)[:] + py_callback(ret, msg) -if __name__ == "__main__": - config = { - "logLevel": "DEBUG", - "mode": "Core", - "protocolsConfig": { - "entryNodes": [ - "/dns4/node-01.do-ams3.misc.logos-chat.status.im/tcp/30303/p2p/16Uiu2HAkxoqUTud5LUPQBRmkeL2xP4iKx2kaABYXomQRgmLUgf78" - ], - "clusterId": 42, - "autoShardingConfig": {"numShardsInCluster": 8}, - }, - "networkingConfig": { - "listenIpv4": "0.0.0.0", - "p2pTcpPort": 60000, - "discv5UdpPort": 9000, - }, - } + cb = CallbackType(c_cb) - def cb(ret, msg): - print("ret:", ret, "msg:", msg) + lib.logosdelivery_set_event_callback( + self.ctx, + cb, + ffi.NULL, + ) - node = NodeWrapper.create_node(config, cb) - rc = node.start_node(cb) - print("start rc:", rc) - - topic = "/myapp/1/chat/proto" - rc = node.subscribe(topic, cb) - print("subscribe rc:", rc) - - rc = node.unsubscribe(topic, cb) - print("unsubscribe rc:", rc) - - rc = node.stop_node(cb) - print("stop rc:", rc) - - rc = node.destroy(cb) - print("destroy rc:", rc) \ No newline at end of file + self._event_cb_handler = cb