diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eac0912 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv/ +dist/ +waku.egg-info/ +waku/__pycache__/ diff --git a/LICENSE-APACHEv2 b/LICENSE-APACHEv2 new file mode 100644 index 0000000..9682721 --- /dev/null +++ b/LICENSE-APACHEv2 @@ -0,0 +1,205 @@ +Py-Waku is licensed under the Apache License version 2 +Copyright (c) 2024 Status Research & Development GmbH +----------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Status Research & Development GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..b382d4b --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Py-Waku is licensed under the MIT License +Copyright (c) 2024 Status Research & Development GmbH +----------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2024 Status Research & Development GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3aa9a39 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ + +# Py-Waku + +## Introduction + +Py-Waku exposes a Waku module that can be used within Python projects. +It is fundamentally a wrapper around [nwaku](https://github.com/waku-org/nwaku) + +This repo has been tested with Python3 in Ubuntu. + +If need a different setup, don't hesitate con contact us on Discord. The Discord server can be found at https://docs.waku.org/. + +## Prepare the development environment + +Run the following commands from the root folder: +1. mkdir venv +2. python3 -m venv venv/ +3. source venv/bin/activate +4. ./venv/bin/python -m pip install -r requiremets.txt + +## Create a Py-Waku package + +Run the following commands from the root folder: +1. source venv/bin/activate +2. ./venv/bin/python3 -m build + +## Test the package + +For that, we have a very simple example in `tests/waku_example.py`. + +In order to use the waku module, please install it from the local `dist/` folder, that can be created by following the +instructions from the previous section. + +The following command is an example on how to install the local +package to your local virtual env. + +```bash +./venv/bin/python3 -m pip install dist/waku-0.0.1-cp310-cp310-linux_x86_64.whl +``` + +## Update the libwaku.so library + +Given that `Py-Waku` conforms a wrapper around `libwaku.so`, +it is likely that you would need to upgrade it. +For that, you will need to update the submodule pointer +to a more recent nwaku version: + +1. `cd vendor/nwaku` +2. Check out to the commit/tag as you wish + +Then, follow the following steps from the root folder +to rebuild the `libwaku.so` library: + +1. `cd vendor/nwaku` +2. `make libwaku -j8` +3. `cd ../../` +4. `cp vendor/nwaku/build/libwaku.so lib/` + +Notice that the `libwaku.so` library is also distributed within +the `Py-Waku` package. diff --git a/lib/libwaku.so b/lib/libwaku.so new file mode 100755 index 0000000..4cbc2af Binary files /dev/null and b/lib/libwaku.so differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d93274d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[project] +name = "waku" +version = "0.0.1" +authors = [ + { name="Waku Dev Team", email="ivansete@status.im" }, +] +description = "A small example package" +readme = "README.md" +requires-python = ">=3.10" + +[build-system] +requires = ["setuptools", "wheel", "cffi>=1.0.0", "Cython"] + +[tool.setuptools] +py-modules = [] diff --git a/requiremets.txt b/requiremets.txt new file mode 100644 index 0000000..5ed51cb --- /dev/null +++ b/requiremets.txt @@ -0,0 +1,38 @@ +blinker==1.7.0 +build==1.0.3 +certifi==2023.7.22 +cffi==1.16.0 +charset-normalizer==3.3.2 +click==8.1.7 +cryptography==41.0.5 +Cython==3.0.8 +docutils==0.20.1 +Flask==3.0.1 +idna==3.4 +importlib-metadata==6.8.0 +itsdangerous==2.1.2 +jaraco.classes==3.3.0 +jeepney==0.8.0 +Jinja2==3.1.3 +keyring==24.2.0 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +more-itertools==10.1.0 +nh3==0.2.14 +packaging==23.2 +pkginfo==1.9.6 +pycparser==2.21 +Pygments==2.16.1 +pyproject_hooks==1.0.0 +readme-renderer==42.0 +requests==2.31.0 +requests-toolbelt==1.0.0 +rfc3986==2.0.0 +rich==13.6.0 +SecretStorage==3.3.3 +tomli==2.0.1 +twine==4.0.2 +urllib3==2.0.7 +Werkzeug==3.0.1 +zipp==3.17.0 diff --git a/run_py.sh b/run_py.sh new file mode 100644 index 0000000..8aaea4b --- /dev/null +++ b/run_py.sh @@ -0,0 +1,28 @@ +## Helper script that allows to start the `waku_example.py` +## and pass it some typical arguments that made the node to connect to a peer. + +## Notice that the other peer is expected to a native nwaku running with the following +## configuration file: +## ports-shift = 0 + +## pubsub-topic = [ "/waku/2/default-waku/proto" "/waku/2/testing-store" ] +## staticnode = [ "/ip4/0.0.0.0/tcp/60001/p2p/16Uiu2HAm2eqzqp6xn32fzgGi8K4BuF88W4Xy6yxsmDcW8h1gj6ie" ] +## log-level = "DEBUG" +## nodekey = "0d714a1fada214dead6dc9c7274585eca0ff292451866e7d6d677dc818e8ccd2" +## lightpush = true +## store = true +## store-message-db-url = "sqlite://sqlite_folder/store.sqlite3" +## store-message-retention-policy = "capacity:100000000" +## rpc-admin=true +## rest-admin=true +## rest = true +## metrics-server = true +## discv5-discovery = true +## discv5-enr-auto-update = true + +./venv/bin/python3 \ + tests/waku_example.py \ + -p 60001 \ + -k 364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9 \ + -r 1 \ + --peer /ip4/127.0.0.1/tcp/60000/p2p/16Uiu2HAmVFXtAfSj4EiR7mL2KvL4EE2wztuQgUSBoj2Jx2KeXFLN diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6f2971f --- /dev/null +++ b/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup, Extension +from Cython.Build import cythonize + +# Define the Extension object +my_extension = Extension( + 'waku.waku', # Module name in Python (resulting in my_package.my_module.so) + sources=[''], + include_dirs=['include/'], # Directories to search for header files + libraries=['waku'], # Names of libraries to link against (without 'lib' prefix or file extension) + library_dirs=['lib/'], # Directories to search for libraries + runtime_library_dirs=['lib/'], # Directories to search for shared libraries at runtime + # extra_compile_args=['-O3'], # Extra compiler options + # extra_link_args=['-L/path/to/lib', '-Wl,-rpath=/path/to/lib'], # Extra linker options +) + +setup( + name='waku', + version='0.1', + packages=['waku'], + ext_modules=cythonize([my_extension]), +) + +# [project.urls] +# Homepage = "https://github.com/pypa/sampleproject" +# Issues = "https://github.com/pypa/sampleproject/issues" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_functions.py b/tests/test_functions.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/waku_example.py b/tests/waku_example.py new file mode 100644 index 0000000..d88826d --- /dev/null +++ b/tests/waku_example.py @@ -0,0 +1,93 @@ +from flask import Flask +import argparse +import waku + +def handle_event(ret, msg): + if ret == 0: ## RET_OK + print("Ok event received: %s" % msg) + else: + print("Error: %s" % msg) + +def call_waku(func): + ret = func() + if (ret != 0): + print("Error in %s. Error code: %d" % (locals().keys(), ret)) + exit(1) + +# Parse params +parser = argparse.ArgumentParser(description='libwaku integration in Python.') +parser.add_argument('-d', '--host', dest='host', default='0.0.0.0', + help='Address this node will listen to. [=0.0.0.0]') +parser.add_argument('-p', '--port', dest='port', default=60000, required=True, + help='Port this node will listen to. [=60000]') +parser.add_argument('-k', '--key', dest='key', default="", required=True, + help="""P2P node private key as 64 char hex string. +e.g.: 364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9""") +parser.add_argument('-r', '--relay', dest='relay', default="true", + help="Enable relay protocol: true|false [=true]") +parser.add_argument('--peer', dest='peer', default="", + help="Multiqualified libp2p address") + +args = parser.parse_args() + +# The next 'json_config' is the item passed to the 'waku_new'. +json_config = "{ \ + \"host\": \"%s\", \ + \"port\": %d, \ + \"key\": \"%s\", \ + \"relay\": %s \ + }" % (args.host, + int(args.port), + args.key, + "true" if args.relay else "false") + +print("Starting node with config: %s" % json_config) + +ctx = waku.waku_new(json_config.encode('ascii'), + lambda ret, msg: + print("Error creating new waku node: %s" % + msg)) + +# Retrieve the current version of the library +waku.waku_version(ctx, + lambda ret, msg: + # print("Git Version") + # print("Git Version: %s" % + # ctypes.c_char_p(ctypes.addressof(msg)).value.decode('utf-8'))) + print("Git Version: %s" % msg)) + +# Retrieve the default pubsub topic +default_pubsub_topic = "" +waku.waku_default_pubsub_topic( + ctx, + lambda ret, msg: ( + globals().update(default_pubsub_topic = msg), + print("Default pubsub topic: %s" % msg))) + +print("Bind addr: {}:{}".format(args.host, args.port)) +print("Waku Relay enabled: {}".format(args.relay)) + +# Set the event callback +callback = handle_event # This line is important so that the callback is not gc'ed +waku.waku_set_event_callback(callback) + +# Start the node +waku.waku_start(ctx, + lambda ret, msg: + print("Error starting: %s" % msg)) + +waku.waku_connect(ctx, + args.peer.encode('utf-8'), + 10000, + # onErrCb + lambda ret, msg: + print("Error calling waku_connect: %s" % msg)) + +waku.waku_relay_subscribe(ctx, + default_pubsub_topic.encode('utf-8'), + callback) + +# Simply avoid the app to end. We could have a UI in this point or a flask server +# that could attend user actions. +a = input() + diff --git a/waku/__init__.py b/waku/__init__.py new file mode 100644 index 0000000..d5a96b9 --- /dev/null +++ b/waku/__init__.py @@ -0,0 +1 @@ +from .waku import * diff --git a/waku/waku.py b/waku/waku.py new file mode 100644 index 0000000..79c0d2b --- /dev/null +++ b/waku/waku.py @@ -0,0 +1,238 @@ + +## This file contains the definition of the Py-Waku module +## that is going to be delivered when the module is installed. + +import ctypes +from cffi import FFI + +# Create an FFI object +ffi = FFI() + +# Load the C library +libwaku = ffi.dlopen('lib/libwaku.so') + +# Declare the C functions +ffi.cdef(""" +typedef void (*WakuCallBack) (int callerRet, const char* msg, size_t len); + +// Creates a new instance of the waku node. +// Sets up the waku node from the given configuration. +// Returns a pointer to the Context needed by the rest of the API functions. +void* waku_new( + const char* configJson, + WakuCallBack callback, + void* userData); + +int waku_start(void* ctx, + WakuCallBack callback, + void* userData); + +int waku_stop(void* ctx, + WakuCallBack callback, + void* userData); + +int waku_version(void* ctx, + WakuCallBack callback, + void* userData); + +void waku_set_event_callback(WakuCallBack callback); + +int waku_content_topic(void* ctx, + const char* appName, + unsigned int appVersion, + const char* contentTopicName, + const char* encoding, + WakuCallBack callback, + void* userData); + +int waku_pubsub_topic(void* ctx, + const char* topicName, + WakuCallBack callback, + void* userData); + +int waku_default_pubsub_topic(void* ctx, + WakuCallBack callback, + void* userData); + +int waku_relay_publish(void* ctx, + const char* pubSubTopic, + const char* jsonWakuMessage, + unsigned int timeoutMs, + WakuCallBack callback, + void* userData); + +int waku_relay_subscribe(void* ctx, + const char* pubSubTopic, + WakuCallBack callback, + void* userData); + +int waku_relay_unsubscribe(void* ctx, + const char* pubSubTopic, + WakuCallBack callback, + void* userData); + +int waku_connect(void* ctx, + const char* peerMultiAddr, + unsigned int timeoutMs, + WakuCallBack callback, + void* userData); +""") + +################################################################## +## helpers + +def process_callback(ret, char_p, len, callback): + ## Converts the data from C space (char* + len) into Python string + ## and then, calls the Python callback which should only have two parameters: + ## First param - integer. 0 means OK. Otherwise, means error, with error code (see libwaku.h) + ## Second param - string. Gives detail of the feedback returned by the libwaku + + byte_string = ffi.buffer(char_p, len)[:] # Use ffi.buffer to access memory directly + callback(ret, byte_string.decode('utf-8')) + +################################################################## + +# Define the callback function type within the module +CallbackType = ffi.callback("void(int, char*, size_t)") + +# Python wrapper functions +def waku_new(config_json, callback): + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_new(config_json, + CallbackType(cb), # Convert the Python callback to a C callback + ffi.cast("void*", 0)) + +def waku_start(ctx, callback): + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_start(ctx, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_stop(ctx, callback): + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_stop(ctx, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_version(ctx, callback): + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_version(ctx, + CallbackType(cb), + ffi.cast("void*", 0)) + +my_python_callback = None + +@ffi.callback("void(int, char*, size_t)") +def handle_event(ret, char_p, len): + ## Handle the event from the C layer + process_callback(ret, char_p, len, my_python_callback) + +def waku_set_event_callback(callback): + global my_python_callback + my_python_callback = callback + + libwaku.waku_set_event_callback(handle_event) + +def waku_content_topic(ctx, + appName, + appVersion, + contentTopicName, + encoding, + callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_content_topic(ctx, + appName, + appVersion, + contentTopicName, + encoding, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_pubsub_topic(ctx, topicName, callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_pubsub_topic(ctx, + topicName, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_default_pubsub_topic(ctx, callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_default_pubsub_topic(ctx, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_relay_publish(ctx, + pubSubTopic, + jsonWakuMessage, + timeoutMs, + callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_relay_publish(ctx, + pubSubTopic, + jsonWakuMessage, + timeoutMs, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_relay_subscribe(ctx, + pubSubTopic, + callback): + + @ffi.callback("void(int, char*, size_t)") + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_relay_subscribe( + ctx, + pubSubTopic, + cb, + ffi.cast("void*", 0)) + +def waku_relay_unsubscribe(ctx, + pubSubTopic, + callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_relay_unsubscribe( + ctx, + pubSubTopic, + CallbackType(cb), + ffi.cast("void*", 0)) + +def waku_connect(ctx, + peerMultiAddr, + timeoutMs, + callback): + + def cb(ret, char_p, len): + process_callback(ret, char_p, len, callback) + + return libwaku.waku_connect( + ctx, + peerMultiAddr, + timeoutMs, + CallbackType(cb), + ffi.cast("void*", 0)) +