refactor: c-bindings

This commit is contained in:
richΛrd 2023-08-10 09:30:38 -04:00 committed by GitHub
parent 9f45d271ac
commit 164c92554b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1294 additions and 906 deletions

View File

@ -128,20 +128,22 @@ static-library:
-buildmode=c-archive \
-tags="${BUILD_TAGS}" \
-o ./build/lib/libgowaku.a \
./library/
./library/c/
@echo "Static library built:"
sed -i "s/#include <cgo_utils.h>//gi" ./build/lib/libgowaku.h
@ls -la ./build/lib/libgowaku.*
dynamic-library:
@echo "Building shared library..."
rm -f ./build/lib/libgowaku.$(GOBIN_SHARED_LIB_EXT)*
$(GOBIN_SHARED_LIB_CFLAGS) $(GOBIN_SHARED_LIB_CGO_LDFLAGS) ${GOBIN} build \
-buildmode=c-shared \
-tags="${BUILD_TAGS}" \
-o ./build/lib/libgowaku.$(GOBIN_SHARED_LIB_EXT) \
./library/
./library/c/
sed -i "s/#include <cgo_utils.h>//gi" ./build/lib/libgowaku.h
ifeq ($(detected_OS),Linux)
cd ./build/lib && \
ls -lah . && \
mv ./libgowaku.$(GOBIN_SHARED_LIB_EXT) ./libgowaku.$(GOBIN_SHARED_LIB_EXT).0 && \
ln -s ./libgowaku.$(GOBIN_SHARED_LIB_EXT).0 ./libgowaku.$(GOBIN_SHARED_LIB_EXT)
endif
@ -152,14 +154,14 @@ mobile-android:
@echo "Android target: ${ANDROID_TARGET} (override with ANDROID_TARGET var)"
gomobile init && \
${GOBIN} get -d golang.org/x/mobile/cmd/gomobile && \
gomobile bind -v -target=android -androidapi=${ANDROID_TARGET} -ldflags="-s -w" -tags="${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/gowaku.aar ./mobile
gomobile bind -v -target=android -androidapi=${ANDROID_TARGET} -ldflags="-s -w" -tags="${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/gowaku.aar ./library/mobile
@echo "Android library built:"
@ls -la ./build/lib/*.aar ./build/lib/*.jar
mobile-ios:
gomobile init && \
${GOBIN} get -d golang.org/x/mobile/cmd/gomobile && \
gomobile bind -target=ios -ldflags="-s -w" -tags="nowatchdog ${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/Gowaku.xcframework ./mobile
gomobile bind -target=ios -ldflags="-s -w" -tags="nowatchdog ${BUILD_TAGS}" $(BUILD_FLAGS) -o ./build/lib/Gowaku.xcframework ./library/mobile
@echo "IOS library built:"
@ls -la ./build/lib/*.xcframework

View File

@ -53,7 +53,7 @@ pipeline {
}
stage('Check') {
steps {
sh 'ldd ./result/bin/library'
sh 'ldd ./result/bin/c'
}
}
}

View File

@ -31,7 +31,7 @@ build:
+ mkdir -p build
$(CC) \
-I../../build/lib/ \
main.c \
main.c base64.c \
../../build/lib/libgowaku.a \
-lm \
-pthread \

View File

@ -0,0 +1,152 @@
#include "base64.h"
#include <string.h>
// source: https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/
size_t b64_encoded_size(size_t inlen)
{
size_t ret;
ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *b64_encode(const unsigned char *in, size_t len)
{
char *out;
size_t elen;
size_t i;
size_t j;
size_t v;
if (in == NULL || len == 0)
return NULL;
elen = b64_encoded_size(len);
out = malloc(elen+1);
out[elen] = '\0';
for (i=0, j=0; i<len; i+=3, j+=4) {
v = in[i];
v = i+1 < len ? v << 8 | in[i+1] : v << 8;
v = i+2 < len ? v << 8 | in[i+2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j+1] = b64chars[(v >> 12) & 0x3F];
if (i+1 < len) {
out[j+2] = b64chars[(v >> 6) & 0x3F];
} else {
out[j+2] = '=';
}
if (i+2 < len) {
out[j+3] = b64chars[v & 0x3F];
} else {
out[j+3] = '=';
}
}
return out;
}
size_t b64_decoded_size(const char *in)
{
size_t len;
size_t ret;
size_t i;
if (in == NULL)
return 0;
len = strlen(in);
ret = len / 4 * 3;
for (i=len; i-->0; ) {
if (in[i] == '=') {
ret--;
} else {
break;
}
}
return ret;
}
int b64_isvalidchar(char c)
{
if (c >= '0' && c <= '9')
return 1;
if (c >= 'A' && c <= 'Z')
return 1;
if (c >= 'a' && c <= 'z')
return 1;
if (c == '+' || c == '/' || c == '=')
return 1;
return 0;
}
int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51 };
void b64_generate_decode_table()
{
int inv[80];
size_t i;
memset(inv, -1, sizeof(inv));
for (i=0; i<sizeof(b64chars)-1; i++) {
inv[b64chars[i]-43] = i;
}
}
int b64_decode(const char *in, unsigned char *out, size_t outlen)
{
size_t len;
size_t i;
size_t j;
int v;
if (in == NULL || out == NULL)
return 0;
len = strlen(in);
if (outlen < b64_decoded_size(in) || len % 4 != 0)
return 0;
for (i=0; i<len; i++) {
if (!b64_isvalidchar(in[i])) {
return 0;
}
}
for (i=0, j=0; i<len; i+=4, j+=3) {
v = b64invs[in[i]-43];
v = (v << 6) | b64invs[in[i+1]-43];
v = in[i+2]=='=' ? v << 6 : (v << 6) | b64invs[in[i+2]-43];
v = in[i+3]=='=' ? v << 6 : (v << 6) | b64invs[in[i+3]-43];
out[j] = (v >> 16) & 0xFF;
if (in[i+2] != '=')
out[j+1] = (v >> 8) & 0xFF;
if (in[i+3] != '=')
out[j+2] = v & 0xFF;
}
return 1;
}

View File

@ -0,0 +1,15 @@
#ifndef _BASE64_H_
#define _BASE64_H_
#include <stdlib.h>
size_t b64_encoded_size(size_t inlen);
char *b64_encode(const unsigned char *in, size_t len);
size_t b64_decoded_size(const char *in);
int b64_decode(const char *in, unsigned char *out, size_t outlen);
#endif

View File

@ -8,6 +8,7 @@
#include "libgowaku.h"
#include "nxjson.c"
#include "base64.h"
#include "main.h"
char *alicePrivKey = "0x4f012057e1a1458ce34189cb27daedbbe434f3df0825c1949475dec786e2c64e";
@ -16,7 +17,24 @@ char *alicePubKey = "0x0440f05847c4c7166f57ae8ecaaf72d31bddcbca345e26713ca9e26c9
char *bobPrivKey = "0xb91d6b2df8fb6ef8b53b51b2b30a408c49d5e2b530502d58ac8f94e5c5de1453";
char *bobPubKey = "0x045eef61a98ba1cf44a2736fac91183ea2bd86e67de20fe4bff467a71249a8a0c05f795dd7f28ced7c15eaa69c89d4212cc4f526ca5e9a62e88008f506d850cccd";
void callBack(char *signal)
char* result = NULL;
char* contentTopic;
void handle_ok(const char* msg, size_t len) {
if (result != NULL) {
free(result);
}
result = malloc(len * sizeof(char) + 1);
strcpy(result, msg);
}
void handle_error(const char* msg, size_t len) {
printf("Error: %s\n", msg);
exit(1);
}
void callBack(const char* signal, size_t len_0)
{
// This callback will be executed each time a new message is received
@ -36,29 +54,34 @@ void callBack(char *signal)
}
}*/
const nx_json *json = nx_json_parse(signal, 0);
const nx_json *json = nx_json_parse((char*) signal, 0);
const char *type = nx_json_get(json, "type")->text_value;
if (strcmp(type, "message") == 0)
{
char* msg = utils_extract_wakumessage_from_signal(json);
char *decodedMsg = waku_decode_asymmetric(msg, bobPrivKey);
free(msg);
const nx_json *wakuMsgJson = nx_json_get(nx_json_get(json, "event"), "wakuMessage");
const char *contentTopic = nx_json_get(wakuMsgJson, "contentTopic")->text_value;
if(isError(decodedMsg)) {
free(decodedMsg);
return;
if (strcmp(contentTopic, contentTopic) == 0)
{
char* msg = utils_extract_wakumessage_from_signal(wakuMsgJson);
WAKU_CALL(waku_decode_asymmetric(msg, bobPrivKey, handle_ok, handle_error));
char *decodedMsg = strdup(result);
const nx_json *dataJson = nx_json_parse(decodedMsg, 0);
const char *pubkey = nx_json_get(dataJson, "pubkey")->text_value;
const char *base64data = nx_json_get(dataJson, "data")->text_value;
size_t data_len = b64_decoded_size(base64data);
char *data = malloc(data_len);
b64_decode(base64data, (unsigned char *)data, data_len) ;
printf(">>> Received \"%s\" from %s\n", data, pubkey);
fflush(stdout);
}
const nx_json *dataJson = nx_json_parse(decodedMsg, 0);
const char *pubkey = nx_json_get(nx_json_get(dataJson, "result"), "pubkey")->text_value;
const char *base64data = nx_json_get(nx_json_get(dataJson, "result"), "data")->text_value;
char *data = waku_utils_base64_decode((char*)base64data);
printf(">>> Received \"%s\" from %s\n", utils_get_str(data), pubkey);
fflush(stdout);
free(data);
}
nx_json_free(json);
@ -66,50 +89,39 @@ void callBack(char *signal)
int main(int argc, char *argv[])
{
char *response;
waku_set_event_callback(callBack);
char *configJSON = "{\"host\": \"0.0.0.0\", \"port\": 60000, \"logLevel\":\"error\", \"store\":true}";
response = waku_new(configJSON); // configJSON can be NULL too to use defaults
if (isError(response))
return 1;
WAKU_CALL( waku_new(configJSON, handle_error) ); // configJSON can be NULL too to use defaults
response = waku_start(); // Start the node, enabling the waku protocols
if (isError(response))
return 1;
WAKU_CALL(waku_start(handle_error) ); // Start the node, enabling the waku protocols
response = waku_peerid(); // Obtain the node peerID
if (isError(response))
return 1;
char *nodePeerID = utils_get_str(response);
printf("PeerID: %s\n", nodePeerID);
WAKU_CALL(waku_peerid(handle_ok, handle_error)); // Obtain the node peerID
char *peerID = strdup(result);
printf("PeerID: %s\n", result);
WAKU_CALL(waku_content_topic("example", 1, "default", "rfc26", handle_ok));
contentTopic = strdup(result);
response = waku_connect("/dns4/node-01.gc-us-central1-a.wakuv2.test.statusim.net/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS", 0); // Connect to a node
if (isError(response))
printf("Could not connect to node: %s\n", response);
WAKU_CALL(waku_connect("/dns4/node-01.gc-us-central1-a.wakuv2.test.statusim.net/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS", 0, handle_error)); // Connect to a node
/*
// To use dns discovery, and retrieve nodes from a enrtree url
response = waku_dns_discovery("enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im", "", 0); // Discover Nodes
if (isError(response))
return 1;
printf("Discovered nodes: %s\n", response);
*/
WAKU_CALL( waku_dns_discovery("enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im", "", 0, handle_ok, handle_error)); // Discover Nodes
printf("Discovered nodes: %s\n", result);
/*
WAKU_CALL(waku_default_pubsub_topic(handle_ok));
char *pubsubTopic = strdup(result);
printf("Default pubsub topic: %s\n", pubsubTopic);
// To see a store query in action:
/*
char query[1000];
sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", waku_default_pubsub_topic());
response = waku_store_query(query, NULL, 0);
if (isError(response))
return 1;
printf("%s\n",response);
sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", pubsubTopic);
WAKU_CALL(waku_store_query(query, NULL, 0, handle_ok, handle_error));
printf("%s\n",result);
*/
response = waku_relay_subscribe(NULL);
if (isError(response))
return 1;
WAKU_CALL( waku_relay_subscribe(NULL, handle_error));
int i = 0;
int version = 1;
@ -118,20 +130,18 @@ int main(int argc, char *argv[])
i++;
char wakuMsg[1000];
char *msgPayload = waku_utils_base64_encode("Hello World!");
char *contentTopic = waku_content_topic("example", 1, "default", "rfc26");
char *msgPayload = b64_encode("Hello World!", 12);
sprintf(wakuMsg, "{\"payload\":\"%s\",\"contentTopic\":\"%s\",\"timestamp\":%"PRIu64"}", msgPayload, contentTopic, nowInNanosecs());
free(msgPayload);
free(contentTopic);
WAKU_CALL(waku_relay_publish_enc_asymmetric(wakuMsg, NULL, bobPubKey, alicePrivKey, 0, handle_ok, handle_error)); // Broadcast via waku relay a message encrypting it with Bob's PubK, and signing it with Alice PrivK
printf("C\n");
response = waku_relay_publish_enc_asymmetric(wakuMsg, NULL, bobPubKey, alicePrivKey, 0); // Broadcast via waku relay a message encrypting it with Bob's PubK, and signing it with Alice PrivK
// response = waku_lightpush_publish_enc_asymmetric(wakuMsg, NULL, NULL, bobPubKey, alicePrivKey, 0); // Broadcast via waku lightpush a message encrypting it with Bob's PubK, and signing it with Alice PrivK
if (isError(response))
return 1;
// char *messageID = utils_get_str(response);
// free(messageID);
char *messageID = strdup(result);
printf("MessageID: %s\n",messageID);
free(messageID);
sleep(1);
}
@ -140,16 +150,12 @@ int main(int argc, char *argv[])
// To retrieve messages from local store, set store:true in the node config, and use waku_store_local_query
/*
char query[1000];
sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", waku_default_pubsub_topic());
response = waku_store_local_query(query);
if (isError(response))
return 1;
printf("%s\n",response);
sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", pubsubTopic);
WAKU_CALL(waku_store_local_query(query, handle_ok, handle_error));
printf("%s\n",result);
*/
response = waku_stop();
if (isError(response))
return 1;
WAKU_CALL(waku_stop(handle_error));
return 0;
}

View File

@ -7,6 +7,14 @@
/// Convert seconds to nanoseconds
#define SEC_TO_NS(sec) ((sec)*1000000000)
#define WAKU_CALL(call) \
do { \
int ret = call; \
if (ret != 0) { \
printf("Failed the call to: %s. Returned code: %d\n", #call, ret); \
exit(1); \
} \
} while (0)
uint64_t nowInNanosecs(){
uint64_t nanoseconds;
@ -48,9 +56,8 @@ bool isError(char *input)
}
char *utils_extract_wakumessage_from_signal(const nx_json *signal)
char *utils_extract_wakumessage_from_signal(const nx_json *wakuMsgJson)
{
const nx_json *wakuMsgJson = nx_json_get(nx_json_get(signal, "event"), "wakuMessage");
const char *payload = nx_json_get(wakuMsgJson, "payload")->text_value;
const char *contentTopic = nx_json_get(wakuMsgJson, "contentTopic")->text_value;
int version = nx_json_get(wakuMsgJson, "version")->int_value;
@ -62,38 +69,5 @@ char *utils_extract_wakumessage_from_signal(const nx_json *signal)
return response;
}
long long utils_get_int(char *input)
{
char *jsonStr = malloc(strlen(input) + 1);
strcpy(jsonStr, input);
const nx_json *json = nx_json_parse(jsonStr, 0);
long long result = -1;
if (json)
{
result = nx_json_get(json, "result")->int_value;
}
nx_json_free(json);
free(jsonStr);
return result;
}
char *utils_get_str(char *input)
{
char *jsonStr = malloc(strlen(input) + 1);
strcpy(jsonStr, input);
const nx_json *json = nx_json_parse(jsonStr, 0);
char *result = "";
if (json)
{
const char *text_value = nx_json_get(json, "result")->text_value;
result = strdup(text_value);
}
nx_json_free(json);
free(jsonStr);
return result;
}
#endif /* MAIN_H */

View File

@ -35,7 +35,7 @@
in rec {
packages = forAllSystems (system: {
node = buildPackage system ["cmd/waku"];
library = buildPackage system ["library"];
library = buildPackage system ["library/c"];
});
defaultPackage = forAllSystems (system:

View File

@ -1,42 +0,0 @@
package main
/*
#include <stdlib.h>
#include <stddef.h>
*/
import "C"
import (
"encoding/base64"
"unsafe"
mobile "github.com/waku-org/go-waku/mobile"
)
// Decode a base64 string (useful for reading the payload from waku messages)
//
//export waku_utils_base64_decode
func waku_utils_base64_decode(data *C.char) *C.char {
b, err := base64.StdEncoding.DecodeString(C.GoString(data))
if err != nil {
return C.CString(mobile.MakeJSONResponse(err))
}
return C.CString(mobile.PrepareJSONResponse(string(b), nil))
}
// Encode data to base64 (useful for creating the payload of a waku message in the
// format understood by waku_relay_publish)
//
//export waku_utils_base64_encode
func waku_utils_base64_encode(data *C.char) *C.char {
str := base64.StdEncoding.EncodeToString([]byte(C.GoString(data)))
return C.CString(string(str))
}
// Frees a char* since all strings returned by gowaku are allocated in the C heap using malloc.
//
//export waku_utils_free
func waku_utils_free(data *C.char) {
C.free(unsafe.Pointer(data))
}

File diff suppressed because it is too large Load Diff

View File

@ -4,15 +4,27 @@ package main
/*
#include <stdlib.h>
#include <stddef.h>
// The possible returned values for the functions that return int
#define RET_OK 0
#define RET_ERR 1
#define RET_MISSING_CALLBACK 2
typedef void (*WakuCallBack) (const char* msg, size_t len_0);
*/
import "C"
import (
"fmt"
"unsafe"
mobile "github.com/waku-org/go-waku/mobile"
"github.com/waku-org/go-waku/library"
"github.com/waku-org/go-waku/waku/v2/protocol"
)
const retOk = C.RET_OK
const retErr = C.RET_ERR
const retMissingCallback = C.RET_MISSING_CALLBACK
func main() {}
// Initialize a waku node. Receives a JSON string containing the configuration
@ -80,110 +92,130 @@ func main() {}
// - dns4DomainName: the domain name resolving to the node's public IPv4 address.
//
//export waku_new
func waku_new(configJSON *C.char) *C.char {
response := mobile.NewNode(C.GoString(configJSON))
return C.CString(response)
func waku_new(configJSON *C.char, onErrCb C.WakuCallBack) C.int {
err := library.NewNode(C.GoString(configJSON))
return execErrCB(onErrCb, err)
}
// Starts the waku node
//
//export waku_start
func waku_start() *C.char {
response := mobile.Start()
return C.CString(response)
func waku_start(onErrCb C.WakuCallBack) C.int {
err := library.Start()
return execErrCB(onErrCb, err)
}
// Stops a waku node
//
//export waku_stop
func waku_stop() *C.char {
response := mobile.Stop()
return C.CString(response)
func waku_stop(onErrCb C.WakuCallBack) C.int {
err := library.Stop()
return execErrCB(onErrCb, err)
}
// Determine is a node is started or not
//
//export waku_is_started
func waku_is_started() *C.char {
response := mobile.IsStarted()
return C.CString(response)
func waku_is_started() C.int {
started := library.IsStarted()
if started {
return 1
}
return 0
}
type fn func() (string, error)
func singleFnExec(f fn, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
result, err := f()
if err != nil {
return execErrCB(onErrCb, err)
}
return execOkCB(onOkCb, result)
}
// Obtain the peer ID of the waku node
//
//export waku_peerid
func waku_peerid() *C.char {
response := mobile.PeerID()
return C.CString(response)
func waku_peerid(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.PeerID()
}, onOkCb, onErrCb)
}
// Obtain the multiaddresses the wakunode is listening to
//
//export waku_listen_addresses
func waku_listen_addresses() *C.char {
response := mobile.ListenAddresses()
return C.CString(response)
func waku_listen_addresses(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.ListenAddresses()
}, onOkCb, onErrCb)
}
// Add node multiaddress and protocol to the wakunode peerstore
//
//export waku_add_peer
func waku_add_peer(address *C.char, protocolID *C.char) *C.char {
response := mobile.AddPeer(C.GoString(address), C.GoString(protocolID))
return C.CString(response)
func waku_add_peer(address *C.char, protocolID *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.AddPeer(C.GoString(address), C.GoString(protocolID))
}, onOkCb, onErrCb)
}
// Connect to peer at multiaddress. if ms > 0, cancel the function execution if it takes longer than N milliseconds
//
//export waku_connect
func waku_connect(address *C.char, ms C.int) *C.char {
response := mobile.Connect(C.GoString(address), int(ms))
return C.CString(response)
func waku_connect(address *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.Connect(C.GoString(address), int(ms))
return execErrCB(onErrCb, err)
}
// Connect to known peer by peerID. if ms > 0, cancel the function execution if it takes longer than N milliseconds
//
//export waku_connect_peerid
func waku_connect_peerid(peerID *C.char, ms C.int) *C.char {
response := mobile.ConnectPeerID(C.GoString(peerID), int(ms))
return C.CString(response)
func waku_connect_peerid(peerID *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.ConnectPeerID(C.GoString(peerID), int(ms))
return execErrCB(onErrCb, err)
}
// Close connection to a known peer by peerID
//
//export waku_disconnect
func waku_disconnect(peerID *C.char) *C.char {
response := mobile.Disconnect(C.GoString(peerID))
return C.CString(response)
func waku_disconnect(peerID *C.char, onErrCb C.WakuCallBack) C.int {
err := library.Disconnect(C.GoString(peerID))
return execErrCB(onErrCb, err)
}
// Get number of connected peers
//
//export waku_peer_cnt
func waku_peer_cnt() *C.char {
response := mobile.PeerCnt()
return C.CString(response)
func waku_peer_cnt(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
peerCnt, err := library.PeerCnt()
return fmt.Sprintf("%d", peerCnt), err
}, onOkCb, onErrCb)
}
// Create a content topic string according to RFC 23
//
//export waku_content_topic
func waku_content_topic(applicationName *C.char, applicationVersion C.uint, contentTopicName *C.char, encoding *C.char) *C.char {
return C.CString(protocol.NewContentTopic(C.GoString(applicationName), uint(applicationVersion), C.GoString(contentTopicName), C.GoString(encoding)).String())
func waku_content_topic(applicationName *C.char, applicationVersion C.uint, contentTopicName *C.char, encoding *C.char, onOkCb C.WakuCallBack) C.int {
contentTopic := protocol.NewContentTopic(C.GoString(applicationName), uint(applicationVersion), C.GoString(contentTopicName), C.GoString(encoding)).String()
return execOkCB(onOkCb, contentTopic)
}
// Create a pubsub topic string according to RFC 23
//
//export waku_pubsub_topic
func waku_pubsub_topic(name *C.char, encoding *C.char) *C.char {
return C.CString(mobile.PubsubTopic(C.GoString(name), C.GoString(encoding)))
func waku_pubsub_topic(name *C.char, encoding *C.char, onOkCb C.WakuCallBack) C.int {
topic := library.PubsubTopic(C.GoString(name), C.GoString(encoding))
return execOkCB(onOkCb, topic)
}
// Get the default pubsub topic used in waku2: /waku/2/default-waku/proto
//
//export waku_default_pubsub_topic
func waku_default_pubsub_topic() *C.char {
return C.CString(mobile.DefaultPubsubTopic())
func waku_default_pubsub_topic(onOkCb C.WakuCallBack) C.int {
return execOkCB(onOkCb, library.DefaultPubsubTopic())
}
// Register callback to act as signal handler and receive application signals
@ -191,30 +223,33 @@ func waku_default_pubsub_topic() *C.char {
// signature for the callback should be `void myCallback(char* signalJSON)`
//
//export waku_set_event_callback
func waku_set_event_callback(cb unsafe.Pointer) {
mobile.SetEventCallback(cb)
func waku_set_event_callback(cb C.WakuCallBack) {
library.SetEventCallback(unsafe.Pointer(cb))
}
// Retrieve the list of peers known by the waku node
//
//export waku_peers
func waku_peers() *C.char {
response := mobile.Peers()
return C.CString(response)
func waku_peers(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.Peers()
}, onOkCb, onErrCb)
}
// Decode a waku message using a 32 bytes symmetric key. The key must be a hex encoded string with "0x" prefix
//
//export waku_decode_symmetric
func waku_decode_symmetric(messageJSON *C.char, symmetricKey *C.char) *C.char {
response := mobile.DecodeSymmetric(C.GoString(messageJSON), C.GoString(symmetricKey))
return C.CString(response)
func waku_decode_symmetric(messageJSON *C.char, symmetricKey *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.DecodeSymmetric(C.GoString(messageJSON), C.GoString(symmetricKey))
}, onOkCb, onErrCb)
}
// Decode a waku message using a secp256k1 private key. The key must be a hex encoded string with "0x" prefix
//
//export waku_decode_asymmetric
func waku_decode_asymmetric(messageJSON *C.char, privateKey *C.char) *C.char {
response := mobile.DecodeAsymmetric(C.GoString(messageJSON), C.GoString(privateKey))
return C.CString(response)
func waku_decode_asymmetric(messageJSON *C.char, privateKey *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.DecodeAsymmetric(C.GoString(messageJSON), C.GoString(privateKey))
}, onOkCb, onErrCb)
}

View File

@ -1,10 +1,11 @@
package main
import (
"C"
/*
#include <cgo_utils.h>
*/
import "C"
mobile "github.com/waku-org/go-waku/mobile"
)
import "github.com/waku-org/go-waku/library"
// Returns a list of objects containing the peerID, enr and multiaddresses for each node found
//
@ -16,16 +17,17 @@ import (
// (in milliseconds) is reached, or an error will be returned
//
//export waku_dns_discovery
func waku_dns_discovery(url *C.char, nameserver *C.char, ms C.int) *C.char {
response := mobile.DnsDiscovery(C.GoString(url), C.GoString(nameserver), int(ms))
return C.CString(response)
func waku_dns_discovery(url *C.char, nameserver *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.DNSDiscovery(C.GoString(url), C.GoString(nameserver), int(ms))
}, onOkCb, onErrCb)
}
// Update the bootnode list used for discovering new peers via DiscoveryV5
// The bootnodes param should contain a JSON array containing the bootnode ENRs i.e. `["enr:...", "enr:..."]`
//
//export waku_discv5_update_bootnodes
func waku_discv5_update_bootnodes(bootnodes *C.char) *C.char {
response := mobile.SetBootnodes(C.GoString(bootnodes))
return C.CString(response)
func waku_discv5_update_bootnodes(bootnodes *C.char, onErrCb C.WakuCallBack) C.int {
err := library.SetBootnodes(C.GoString(bootnodes))
return execErrCB(onErrCb, err)
}

View File

@ -1,10 +1,10 @@
package main
import (
"C"
mobile "github.com/waku-org/go-waku/mobile"
)
/*
#include <cgo_utils.h>
*/
import "C"
import "github.com/waku-org/go-waku/library"
// Creates a subscription to a filter full node matching a content filter.
// filterJSON must contain a JSON with this format:
@ -20,9 +20,10 @@ import (
// It returns a json object containing the peerID to which we are subscribed to and the details of the subscription
//
//export waku_filter_subscribe
func waku_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.FilterSubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
return C.CString(response)
func waku_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.FilterSubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
}, onOkCb, onErrCb)
}
// Used to know if a service node has an active subscription for this client
@ -31,9 +32,9 @@ func waku_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int) *C.char
// (in milliseconds) is reached, or an error will be returned
//
//export waku_filter_ping
func waku_filter_ping(peerID *C.char, ms C.int) *C.char {
response := mobile.FilterPing(C.GoString(peerID), int(ms))
return C.CString(response)
func waku_filter_ping(peerID *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.FilterPing(C.GoString(peerID), int(ms))
return execErrCB(onErrCb, err)
}
// Sends a requests to a service node to stop pushing messages matching this filter to this client.
@ -50,9 +51,9 @@ func waku_filter_ping(peerID *C.char, ms C.int) *C.char {
// (in milliseconds) is reached, or an error will be returned
//
//export waku_filter_unsubscribe
func waku_filter_unsubscribe(filterJSON *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.FilterUnsubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
return C.CString(response)
func waku_filter_unsubscribe(filterJSON *C.char, peerID *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.FilterUnsubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
return execErrCB(onErrCb, err)
}
// Sends a requests to a service node (or all service nodes) to stop pushing messages
@ -62,7 +63,8 @@ func waku_filter_unsubscribe(filterJSON *C.char, peerID *C.char, ms C.int) *C.ch
// (in milliseconds) is reached, or an error will be returned
//
//export waku_filter_unsubscribe_all
func waku_filter_unsubscribe_all(peerID *C.char, ms C.int) *C.char {
response := mobile.FilterUnsubscribeAll(C.GoString(peerID), int(ms))
return C.CString(response)
func waku_filter_unsubscribe_all(peerID *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.FilterUnsubscribeAll(C.GoString(peerID), int(ms))
}, onOkCb, onErrCb)
}

View File

@ -1,10 +1,10 @@
package main
import (
"C"
mobile "github.com/waku-org/go-waku/mobile"
)
/*
#include <cgo_utils.h>
*/
import "C"
import "github.com/waku-org/go-waku/library"
// Creates a subscription to a light node matching a content filter and, optionally, a pubSub topic.
// filterJSON must contain a JSON with this format:
@ -23,9 +23,9 @@ import (
// (in milliseconds) is reached, or an error will be returned
//
//export waku_legacy_filter_subscribe
func waku_legacy_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.LegacyFilterSubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
return C.CString(response)
func waku_legacy_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.LegacyFilterSubscribe(C.GoString(filterJSON), C.GoString(peerID), int(ms))
return execErrCB(onErrCb, err)
}
// Removes subscriptions in a light node matching a content filter and, optionally, a pubSub topic.
@ -44,7 +44,7 @@ func waku_legacy_filter_subscribe(filterJSON *C.char, peerID *C.char, ms C.int)
// (in milliseconds) is reached, or an error will be returned
//
//export waku_legacy_filter_unsubscribe
func waku_legacy_filter_unsubscribe(filterJSON *C.char, ms C.int) *C.char {
response := mobile.LegacyFilterUnsubscribe(C.GoString(filterJSON), int(ms))
return C.CString(response)
func waku_legacy_filter_unsubscribe(filterJSON *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
err := library.LegacyFilterUnsubscribe(C.GoString(filterJSON), int(ms))
return execErrCB(onErrCb, err)
}

View File

@ -1,41 +1,47 @@
package main
import (
"C"
/*
#include <cgo_utils.h>
*/
import "C"
import "github.com/waku-org/go-waku/library"
mobile "github.com/waku-org/go-waku/mobile"
)
//export waku_lightpush_publish
// Publish a message using waku lightpush. Use NULL for topic to use the default pubsub topic..
// peerID should contain the ID of a peer supporting the lightpush protocol. Use NULL to automatically select a node
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned
func waku_lightpush_publish(messageJSON *C.char, topic *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.LightpushPublish(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), int(ms))
return C.CString(response)
//
//export waku_lightpush_publish
func waku_lightpush_publish(messageJSON *C.char, topic *C.char, peerID *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.LightpushPublish(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), int(ms))
}, onOkCb, onErrCb)
}
//export waku_lightpush_publish_enc_asymmetric
// Publish a message encrypted with a secp256k1 public key using waku lightpush. Use NULL for topic to use the default pubsub topic.
// peerID should contain the ID of a peer supporting the lightpush protocol. Use NULL to automatically select a node
// publicKey must be a hex string prefixed with "0x" containing a valid secp256k1 public key.
// optionalSigningKey is an optional hex string prefixed with "0x" containing a valid secp256k1 private key for signing the message. Use NULL otherwise
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned.
func waku_lightpush_publish_enc_asymmetric(messageJSON *C.char, topic *C.char, peerID *C.char, publicKey *C.char, optionalSigningKey *C.char, ms C.int) *C.char {
response := mobile.LightpushPublishEncodeAsymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), C.GoString(publicKey), C.GoString(optionalSigningKey), int(ms))
return C.CString(response)
//
//export waku_lightpush_publish_enc_asymmetric
func waku_lightpush_publish_enc_asymmetric(messageJSON *C.char, topic *C.char, peerID *C.char, publicKey *C.char, optionalSigningKey *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.LightpushPublishEncodeAsymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), C.GoString(publicKey), C.GoString(optionalSigningKey), int(ms))
}, onOkCb, onErrCb)
}
//export waku_lightpush_publish_enc_symmetric
// Publish a message encrypted with a 32 bytes symmetric key using waku relay. Use NULL for topic to use the default pubsub topic.
// peerID should contain the ID of a peer supporting the lightpush protocol. Use NULL to automatically select a node
// symmetricKey must be a hex string prefixed with "0x" containing a 32 bytes symmetric key
// optionalSigningKey is an optional hex string prefixed with "0x" containing a valid secp256k1 private key for signing the message. Use NULL otherwise
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned.
func waku_lightpush_publish_enc_symmetric(messageJSON *C.char, topic *C.char, peerID *C.char, symmetricKey *C.char, optionalSigningKey *C.char, ms C.int) *C.char {
response := mobile.LightpushPublishEncodeSymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), C.GoString(symmetricKey), C.GoString(optionalSigningKey), int(ms))
return C.CString(response)
//
//export waku_lightpush_publish_enc_symmetric
func waku_lightpush_publish_enc_symmetric(messageJSON *C.char, topic *C.char, peerID *C.char, symmetricKey *C.char, optionalSigningKey *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.LightpushPublishEncodeSymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(peerID), C.GoString(symmetricKey), C.GoString(optionalSigningKey), int(ms))
}, onOkCb, onErrCb)
}

View File

@ -1,18 +1,23 @@
package main
import (
"C"
mobile "github.com/waku-org/go-waku/mobile"
)
/*
#include <cgo_utils.h>
*/
import "C"
import "github.com/waku-org/go-waku/library"
// Determine if there are enough peers to publish a message on a topic. Use NULL
// to verify the number of peers in the default pubsub topic
//
//export waku_relay_enough_peers
func waku_relay_enough_peers(topic *C.char) *C.char {
response := mobile.RelayEnoughPeers(C.GoString(topic))
return C.CString(response)
func waku_relay_enough_peers(topic *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
result, err := library.RelayEnoughPeers(C.GoString(topic))
if result {
return "true", err
}
return "false", err
}, onOkCb, onErrCb)
}
// Publish a message using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic
@ -20,33 +25,36 @@ func waku_relay_enough_peers(topic *C.char) *C.char {
// (in milliseconds) is reached, or an error will be returned.
//
//export waku_relay_publish
func waku_relay_publish(messageJSON *C.char, topic *C.char, ms C.int) *C.char {
response := mobile.RelayPublish(C.GoString(messageJSON), C.GoString(topic), int(ms))
return C.CString(response)
func waku_relay_publish(messageJSON *C.char, topic *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.RelayPublish(C.GoString(messageJSON), C.GoString(topic), int(ms))
}, onOkCb, onErrCb)
}
// Publish a message encrypted with a secp256k1 public key using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic.
// Publish a message encrypted with a secp256k1 public key using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic.
// publicKey must be a hex string prefixed with "0x" containing a valid secp256k1 public key.
// optionalSigningKey is an optional hex string prefixed with "0x" containing a valid secp256k1 private key for signing the message. Use NULL otherwise
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned.
//
//export waku_relay_publish_enc_asymmetric
func waku_relay_publish_enc_asymmetric(messageJSON *C.char, topic *C.char, publicKey *C.char, optionalSigningKey *C.char, ms C.int) *C.char {
response := mobile.RelayPublishEncodeAsymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(publicKey), C.GoString(optionalSigningKey), int(ms))
return C.CString(response)
func waku_relay_publish_enc_asymmetric(messageJSON *C.char, topic *C.char, publicKey *C.char, optionalSigningKey *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.RelayPublishEncodeAsymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(publicKey), C.GoString(optionalSigningKey), int(ms))
}, onOkCb, onErrCb)
}
// Publish a message encrypted with a 32 bytes symmetric key using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic.
// Publish a message encrypted with a 32 bytes symmetric key using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic.
// symmetricKey must be a hex string prefixed with "0x" containing a 32 bytes symmetric key
// optionalSigningKey is an optional hex string prefixed with "0x" containing a valid secp256k1 private key for signing the message. Use NULL otherwise
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned.
//
//export waku_relay_publish_enc_symmetric
func waku_relay_publish_enc_symmetric(messageJSON *C.char, topic *C.char, symmetricKey *C.char, optionalSigningKey *C.char, ms C.int) *C.char {
response := mobile.RelayPublishEncodeSymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(symmetricKey), C.GoString(optionalSigningKey), int(ms))
return C.CString(response)
func waku_relay_publish_enc_symmetric(messageJSON *C.char, topic *C.char, symmetricKey *C.char, optionalSigningKey *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.RelayPublishEncodeSymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(symmetricKey), C.GoString(optionalSigningKey), int(ms))
}, onOkCb, onErrCb)
}
// Subscribe to a WakuRelay topic. Set the topic to NULL to subscribe
@ -55,24 +63,25 @@ func waku_relay_publish_enc_symmetric(messageJSON *C.char, topic *C.char, symmet
// the message was received
//
//export waku_relay_subscribe
func waku_relay_subscribe(topic *C.char) *C.char {
response := mobile.RelaySubscribe(C.GoString(topic))
return C.CString(response)
func waku_relay_subscribe(topic *C.char, onErrCb C.WakuCallBack) C.int {
err := library.RelaySubscribe(C.GoString(topic))
return execErrCB(onErrCb, err)
}
// Returns a json response with the list of pubsub topics the node
// is subscribed to in WakuRelay
//
//export waku_relay_topics
func waku_relay_topics() *C.char {
response := mobile.RelayTopics()
return C.CString(response)
func waku_relay_topics(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.RelayTopics()
}, onOkCb, onErrCb)
}
// Closes the pubsub subscription to a pubsub topic
//
//export waku_relay_unsubscribe
func waku_relay_unsubscribe(topic *C.char) *C.char {
response := mobile.RelayUnsubscribe(C.GoString(topic))
return C.CString(response)
func waku_relay_unsubscribe(topic *C.char, onErrCb C.WakuCallBack) C.int {
err := library.RelayUnsubscribe(C.GoString(topic))
return execErrCB(onErrCb, err)
}

View File

@ -1,10 +1,10 @@
package main
import (
"C"
mobile "github.com/waku-org/go-waku/mobile"
)
/*
#include <cgo_utils.h>
*/
import "C"
import "github.com/waku-org/go-waku/library"
// Query historic messages using waku store protocol.
// queryJSON must contain a valid json string with the following format:
@ -36,9 +36,10 @@ import (
// (in milliseconds) is reached, or an error will be returned
//
//export waku_store_query
func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.StoreQuery(C.GoString(queryJSON), C.GoString(peerID), int(ms))
return C.CString(response)
func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.StoreQuery(C.GoString(queryJSON), C.GoString(peerID), int(ms))
}, onOkCb, onErrCb)
}
// Query historic messages stored in the localDB using waku store protocol.
@ -69,7 +70,8 @@ func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int) *C.char {
// Requires the `store` option to be passed when setting up the initial configuration
//
//export waku_store_local_query
func waku_store_local_query(queryJSON *C.char) *C.char {
response := mobile.StoreLocalQuery(C.GoString(queryJSON))
return C.CString(response)
func waku_store_local_query(queryJSON *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
return singleFnExec(func() (string, error) {
return library.StoreLocalQuery(C.GoString(queryJSON))
}, onOkCb, onErrCb)
}

9
library/c/cgo_utils.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdlib.h>
#include <stddef.h>
#include <cgo_utils.h>
// This is a bridge function to execute C callbacks.
// It's used internally in go-waku. Do not call directly
void _waku_execCB(WakuCallBack op, char* a, size_t b) {
op(a, b);
}

37
library/c/cgo_utils.go Normal file
View File

@ -0,0 +1,37 @@
package main
/*
#include <stdlib.h>
#include <cgo_utils.h>
extern void _waku_execCB(WakuCallBack op, char* a, size_t b);
*/
import "C"
import "unsafe"
func execOkCB(onOkCb C.WakuCallBack, value string) C.int {
if onOkCb == nil {
return retMissingCallback
}
val := C.CString(value)
len := C.size_t(len(value))
C._waku_execCB(onOkCb, val, len)
C.free(unsafe.Pointer(val))
return retOk
}
func execErrCB(onErrCb C.WakuCallBack, err error) C.int {
if onErrCb == nil {
return retMissingCallback
}
if err != nil {
errMsg := err.Error()
execOkCB(onErrCb, errMsg) // reusing ok cb
return retErr
}
return retOk
}

6
library/c/cgo_utils.h Normal file
View File

@ -0,0 +1,6 @@
#include <stdlib.h>
#include <stdint.h>
typedef void (*WakuCallBack) (const char* msg, size_t len_0);
typedef void (*BytesCallBack) (uint8_t* data, size_t len_0);

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"encoding/json"
@ -308,7 +308,7 @@ func getSeenTTL(cfg WakuConfig) time.Duration {
return time.Duration(*cfg.GossipSubParams.SeenMessagesTTLSeconds)
}
func GetGossipSubParams(cfg *GossipSubParams) pubsub.GossipSubParams {
func getGossipSubParams(cfg *GossipSubParams) pubsub.GossipSubParams {
params := pubsub.DefaultGossipSubParams()
if cfg.D != nil {

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"context"
@ -10,13 +10,14 @@ import (
"github.com/waku-org/go-waku/waku/v2/dnsdisc"
)
type DnsDiscoveryItem struct {
type dnsDiscoveryItem struct {
PeerID string `json:"peerID"`
Addresses []string `json:"multiaddrs"`
ENR string `json:"enr,omitempty"`
}
func DnsDiscovery(url string, nameserver string, ms int) string {
// DNSDiscovery executes dns discovery on an url and returns a list of nodes
func DNSDiscovery(url string, nameserver string, ms int) (string, error) {
var ctx context.Context
var cancel context.CancelFunc
@ -34,12 +35,12 @@ func DnsDiscovery(url string, nameserver string, ms int) string {
nodes, err := dnsdisc.RetrieveNodes(ctx, url, dnsDiscOpt...)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
var response []DnsDiscoveryItem
var response []dnsDiscoveryItem
for _, n := range nodes {
item := DnsDiscoveryItem{
item := dnsDiscoveryItem{
PeerID: n.PeerID.String(),
}
for _, addr := range n.PeerInfo.Addrs {
@ -53,53 +54,51 @@ func DnsDiscovery(url string, nameserver string, ms int) string {
response = append(response, item)
}
return PrepareJSONResponse(response, nil)
return marshalJSON(response)
}
func StartDiscoveryV5() string {
// StartDiscoveryV5 starts discv5 discovery
func StartDiscoveryV5() error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
if wakuState.node.DiscV5() == nil {
return MakeJSONResponse(errors.New("DiscV5 is not mounted"))
return errors.New("DiscV5 is not mounted")
}
err := wakuState.node.DiscV5().Start(context.Background())
if err != nil {
return MakeJSONResponse(err)
}
return MakeJSONResponse(nil)
return wakuState.node.DiscV5().Start(context.Background())
}
func StopDiscoveryV5() string {
// StopDiscoveryV5 stops discv5 discovery
func StopDiscoveryV5() error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
if wakuState.node.DiscV5() == nil {
return MakeJSONResponse(errors.New("DiscV5 is not mounted"))
return errors.New("DiscV5 is not mounted")
}
wakuState.node.DiscV5().Stop()
return MakeJSONResponse(nil)
return nil
}
func SetBootnodes(bootnodes string) string {
// SetBootnodes is used to update the bootnodes receiving a JSON array of ENRs
func SetBootnodes(bootnodes string) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
if wakuState.node.DiscV5() == nil {
return MakeJSONResponse(errors.New("DiscV5 is not mounted"))
return errors.New("DiscV5 is not mounted")
}
var tmp []json.RawMessage
if err := json.Unmarshal([]byte(bootnodes), &tmp); err != nil {
return MakeJSONResponse(err)
return err
}
var enrList []string
for _, el := range tmp {
var enr string
if err := json.Unmarshal(el, &enr); err != nil {
return MakeJSONResponse(err)
return err
}
enrList = append(enrList, enr)
}
@ -108,11 +107,10 @@ func SetBootnodes(bootnodes string) string {
for _, addr := range enrList {
node, err := enode.Parse(enode.ValidSchemes, addr)
if err != nil {
return MakeJSONResponse(err)
return err
}
nodes = append(nodes, node)
}
err := wakuState.node.DiscV5().SetBootnodes(nodes)
return MakeJSONResponse(err)
return wakuState.node.DiscV5().SetBootnodes(nodes)
}

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"encoding/json"

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"context"
@ -10,13 +10,13 @@ import (
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
)
type FilterArgument struct {
type filterArgument struct {
Topic string `json:"pubsubTopic,omitempty"`
ContentTopics []string `json:"contentTopics,omitempty"`
}
func toContentFilter(filterJSON string) (filter.ContentFilter, error) {
var f FilterArgument
var f filterArgument
err := json.Unmarshal([]byte(filterJSON), &f)
if err != nil {
return filter.ContentFilter{}, err
@ -28,14 +28,15 @@ func toContentFilter(filterJSON string) (filter.ContentFilter, error) {
}, nil
}
func FilterSubscribe(filterJSON string, peerID string, ms int) string {
// FilterSubscribe is used to create a subscription to a filter node to receive messages
func FilterSubscribe(filterJSON string, peerID string, ms int) (string, error) {
cf, err := toContentFilter(filterJSON)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
var ctx context.Context
@ -52,7 +53,7 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
fOptions = append(fOptions, filter.WithPeer(p))
} else {
@ -61,7 +62,7 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
subscriptionDetails, err := wakuState.node.FilterLightnode().Subscribe(ctx, cf, fOptions...)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
go func(subscriptionDetails *filter.SubscriptionDetails) {
@ -70,12 +71,13 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
}
}(subscriptionDetails)
return PrepareJSONResponse(subscriptionDetails, nil)
return marshalJSON(subscriptionDetails)
}
func FilterPing(peerID string, ms int) string {
// FilterPing is used to determine if a peer has an active subscription
func FilterPing(peerID string, ms int) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -93,25 +95,24 @@ func FilterPing(peerID string, ms int) string {
if peerID != "" {
pID, err = peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return err
}
} else {
return MakeJSONResponse(errors.New("peerID is required"))
return errors.New("peerID is required")
}
err = wakuState.node.FilterLightnode().Ping(ctx, pID)
return MakeJSONResponse(err)
return wakuState.node.FilterLightnode().Ping(ctx, pID)
}
func FilterUnsubscribe(filterJSON string, peerID string, ms int) string {
// FilterUnsubscribe is used to remove a filter criteria from an active subscription with a filter node
func FilterUnsubscribe(filterJSON string, peerID string, ms int) error {
cf, err := toContentFilter(filterJSON)
if err != nil {
return MakeJSONResponse(err)
return err
}
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -128,21 +129,21 @@ func FilterUnsubscribe(filterJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return err
}
fOptions = append(fOptions, filter.Peer(p))
} else {
return MakeJSONResponse(errors.New("peerID is required"))
return errors.New("peerID is required")
}
pushResult, err := wakuState.node.FilterLightnode().Unsubscribe(ctx, cf, fOptions...)
if err != nil {
return MakeJSONResponse(err)
return err
}
result := <-pushResult
return MakeJSONResponse(result.Err)
return result.Err
}
type unsubscribeAllResult struct {
@ -150,9 +151,10 @@ type unsubscribeAllResult struct {
Error string `json:"error"`
}
func FilterUnsubscribeAll(peerID string, ms int) string {
// FilterUnsubscribeAll is used to remove an active subscription to a peer. If no peerID is defined, it will stop all active filter subscriptions
func FilterUnsubscribeAll(peerID string, ms int) (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
var ctx context.Context
@ -169,7 +171,7 @@ func FilterUnsubscribeAll(peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
fOptions = append(fOptions, filter.Peer(p))
} else {
@ -178,7 +180,7 @@ func FilterUnsubscribeAll(peerID string, ms int) string {
pushResult, err := wakuState.node.FilterLightnode().UnsubscribeAll(ctx, fOptions...)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
var unsubscribeResult []unsubscribeAllResult
@ -193,5 +195,5 @@ func FilterUnsubscribeAll(peerID string, ms int) string {
unsubscribeResult = append(unsubscribeResult, ur)
}
return PrepareJSONResponse(unsubscribeResult, nil)
return marshalJSON(unsubscribeResult)
}

View File

@ -1,13 +1,13 @@
//go:build darwin && cgo
// +build darwin,cgo
package gowaku
package library
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#include <stddef.h>
#include <stdbool.h>
extern bool StatusServiceSignalEvent( const char *jsonEvent );
extern bool ServiceSignalEvent( const char *jsonEvent );
*/
import "C"

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"context"
@ -10,13 +10,13 @@ import (
"github.com/waku-org/go-waku/waku/v2/protocol/legacy_filter/pb"
)
type LegacyFilterArgument struct {
type legacyFilterArgument struct {
Topic string `json:"pubsubTopic,omitempty"`
ContentFilters []*pb.FilterRequest_ContentFilter `json:"contentFilters,omitempty"`
}
func toLegacyContentFilter(filterJSON string) (legacy_filter.ContentFilter, error) {
var f LegacyFilterArgument
var f legacyFilterArgument
err := json.Unmarshal([]byte(filterJSON), &f)
if err != nil {
return legacy_filter.ContentFilter{}, err
@ -32,15 +32,16 @@ func toLegacyContentFilter(filterJSON string) (legacy_filter.ContentFilter, erro
return result, err
}
// LegacyFilterSubscribe is used to create a subscription to a filter node to receive messages
// Deprecated: Use FilterSubscribe instead
func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) string {
func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) error {
cf, err := toLegacyContentFilter(filterJSON)
if err != nil {
return MakeJSONResponse(err)
return err
}
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -57,7 +58,7 @@ func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return err
}
fOptions = append(fOptions, legacy_filter.WithPeer(p))
} else {
@ -66,7 +67,7 @@ func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) string {
_, f, err := wakuState.node.LegacyFilter().Subscribe(ctx, cf, fOptions...)
if err != nil {
return MakeJSONResponse(err)
return err
}
go func(f legacy_filter.Filter) {
@ -75,18 +76,19 @@ func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) string {
}
}(f)
return PrepareJSONResponse(true, nil)
return nil
}
// LegacyFilterUnsubscribe is used to remove a filter criteria from an active subscription with a filter node
// Deprecated: Use FilterUnsubscribe or FilterUnsubscribeAll instead
func LegacyFilterUnsubscribe(filterJSON string, ms int) string {
func LegacyFilterUnsubscribe(filterJSON string, ms int) error {
cf, err := toLegacyContentFilter(filterJSON)
if err != nil {
return MakeJSONResponse(err)
return err
}
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -99,10 +101,5 @@ func LegacyFilterUnsubscribe(filterJSON string, ms int) string {
ctx = context.Background()
}
err = wakuState.node.LegacyFilter().UnsubscribeFilter(ctx, cf)
if err != nil {
return MakeJSONResponse(err)
}
return MakeJSONResponse(nil)
return wakuState.node.LegacyFilter().UnsubscribeFilter(ctx, cf)
}

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"context"
@ -41,34 +41,32 @@ func lightpushPublish(msg *pb.WakuMessage, pubsubTopic string, peerID string, ms
return hexutil.Encode(hash), err
}
func LightpushPublish(messageJSON string, topic string, peerID string, ms int) string {
// LightpushPublish is used to publish a WakuMessage in a pubsub topic using Lightpush protocol
func LightpushPublish(messageJSON string, topic string, peerID string, ms int) (string, error) {
msg, err := wakuMessage(messageJSON)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
return lightpushPublish(msg, getTopic(topic), peerID, ms)
}
func LightpushPublishEncodeAsymmetric(messageJSON string, topic string, peerID string, publicKey string, optionalSigningKey string, ms int) string {
// LightpushPublishEncodeAsymmetric is used to publish a WakuMessage in a pubsub topic using Lightpush protocol, and encrypting the message with some public key
func LightpushPublishEncodeAsymmetric(messageJSON string, topic string, peerID string, publicKey string, optionalSigningKey string, ms int) (string, error) {
msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
return lightpushPublish(msg, getTopic(topic), peerID, ms)
}
func LightpushPublishEncodeSymmetric(messageJSON string, topic string, peerID string, symmetricKey string, optionalSigningKey string, ms int) string {
// LightpushPublishEncodeSymmetric is used to publish a WakuMessage in a pubsub topic using Lightpush protocol, and encrypting the message with a symmetric key
func LightpushPublishEncodeSymmetric(messageJSON string, topic string, peerID string, symmetricKey string, optionalSigningKey string, ms int) (string, error) {
msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
return lightpushPublish(msg, getTopic(topic), peerID, ms)
}

106
library/mobile/api.go Normal file
View File

@ -0,0 +1,106 @@
// Package gowaku implements gomobile bindings for go-waku. Contains a set of functions that
// are exported when go-waku is exported as libraries for mobile devices
package gowaku
import (
"github.com/waku-org/go-waku/library"
"github.com/waku-org/go-waku/waku/v2/protocol"
)
// NewNode initializes a waku node. Receives a JSON string containing the configuration, and use default values for those config items not specified
func NewNode(configJSON string) string {
err := library.NewNode(configJSON)
return makeJSONResponse(err)
}
// Start starts the waku node
func Start() string {
err := library.Start()
return makeJSONResponse(err)
}
// Stop stops a waku node
func Stop() string {
err := library.Stop()
return makeJSONResponse(err)
}
// IsStarted is used to determine is a node is started or not
func IsStarted() string {
return prepareJSONResponse(library.IsStarted(), nil)
}
// PeerID is used to obtain the peer ID of the waku node
func PeerID() string {
peerID, err := library.PeerID()
return prepareJSONResponse(peerID, err)
}
// ListenAddresses returns the multiaddresses the wakunode is listening to
func ListenAddresses() string {
addresses, err := library.ListenAddresses()
return prepareJSONResponse(addresses, err)
}
// AddPeer adds a node multiaddress and protocol to the wakunode peerstore
func AddPeer(address string, protocolID string) string {
peerID, err := library.AddPeer(address, protocolID)
return prepareJSONResponse(peerID, err)
}
// Connect is used to connect to a peer at multiaddress. if ms > 0, cancel the function execution if it takes longer than N milliseconds
func Connect(address string, ms int) string {
err := library.Connect(address, ms)
return makeJSONResponse(err)
}
// ConnectPeerID is usedd to connect to a known peer by peerID. if ms > 0, cancel the function execution if it takes longer than N milliseconds
func ConnectPeerID(peerID string, ms int) string {
err := library.ConnectPeerID(peerID, ms)
return makeJSONResponse(err)
}
// Disconnect closes a connection to a known peer by peerID
func Disconnect(peerID string) string {
err := library.Disconnect(peerID)
return makeJSONResponse(err)
}
// PeerCnt returns the number of connected peers
func PeerCnt() string {
peerCnt, err := library.PeerCnt()
return prepareJSONResponse(peerCnt, err)
}
// ContentTopic creates a content topic string according to RFC 23
func ContentTopic(applicationName string, applicationVersion int, contentTopicName string, encoding string) string {
return protocol.NewContentTopic(applicationName, uint(applicationVersion), contentTopicName, encoding).String()
}
// PubsubTopic creates a pubsub topic string according to RFC 23
func PubsubTopic(name string, encoding string) string {
return protocol.NewNamedShardingPubsubTopic(name + "/" + encoding).String()
}
// DefaultPubsubTopic returns the default pubsub topic used in waku2: /waku/2/default-waku/proto
func DefaultPubsubTopic() string {
return protocol.DefaultPubsubTopic().String()
}
// Peers retrieves the list of peers known by the waku node
func Peers() string {
peers, err := library.Peers()
return prepareJSONResponse(peers, err)
}
// DecodeSymmetric decodes a waku message using a 32 bytes symmetric key. The key must be a hex encoded string with "0x" prefix
func DecodeSymmetric(messageJSON string, symmetricKey string) string {
response, err := library.DecodeSymmetric(messageJSON, symmetricKey)
return prepareJSONResponse(response, err)
}
// DecodeAsymmetric decodes a waku message using a secp256k1 private key. The key must be a hex encoded string with "0x" prefix
func DecodeAsymmetric(messageJSON string, privateKey string) string {
response, err := library.DecodeAsymmetric(messageJSON, privateKey)
return prepareJSONResponse(response, err)
}

View File

@ -0,0 +1,29 @@
package gowaku
import (
"github.com/waku-org/go-waku/library"
)
// DNSDiscovery executes dns discovery on an url and returns a list of nodes
func DNSDiscovery(url string, nameserver string, ms int) string {
response, err := library.DNSDiscovery(url, nameserver, ms)
return prepareJSONResponse(response, err)
}
// StartDiscoveryV5 starts discv5 discovery
func StartDiscoveryV5() string {
err := library.StartDiscoveryV5()
return makeJSONResponse(err)
}
// StopDiscoveryV5 stops discv5 discovery
func StopDiscoveryV5() string {
err := library.StopDiscoveryV5()
return makeJSONResponse(err)
}
// SetBootnodes is used to update the bootnodes receiving a JSON array of ENRs
func SetBootnodes(bootnodes string) string {
err := library.SetBootnodes(bootnodes)
return makeJSONResponse(err)
}

View File

@ -0,0 +1,29 @@
package gowaku
import (
"github.com/waku-org/go-waku/library"
)
// FilterSubscribe is used to create a subscription to a filter node to receive messages
func FilterSubscribe(filterJSON string, peerID string, ms int) string {
response, err := library.FilterSubscribe(filterJSON, peerID, ms)
return prepareJSONResponse(response, err)
}
// FilterPing is used to determine if a peer has an active subscription
func FilterPing(peerID string, ms int) string {
err := library.FilterPing(peerID, ms)
return makeJSONResponse(err)
}
// FilterUnsubscribe is used to remove a filter criteria from an active subscription with a filter node
func FilterUnsubscribe(filterJSON string, peerID string, ms int) string {
err := library.FilterUnsubscribe(filterJSON, peerID, ms)
return makeJSONResponse(err)
}
// FilterUnsubscribeAll is used to remove an active subscription to a peer. If no peerID is defined, it will stop all active filter subscriptions
func FilterUnsubscribeAll(peerID string, ms int) string {
response, err := library.FilterUnsubscribeAll(peerID, ms)
return prepareJSONResponse(response, err)
}

View File

@ -0,0 +1,19 @@
package gowaku
import (
"github.com/waku-org/go-waku/library"
)
// LegacyFilterSubscribe is used to create a subscription to a filter node to receive messages
// Deprecated: Use FilterSubscribe instead
func LegacyFilterSubscribe(filterJSON string, peerID string, ms int) string {
err := library.LegacyFilterSubscribe(filterJSON, peerID, ms)
return makeJSONResponse(err)
}
// LegacyFilterUnsubscribe is used to remove a filter criteria from an active subscription with a filter node
// Deprecated: Use FilterUnsubscribe or FilterUnsubscribeAll instead
func LegacyFilterUnsubscribe(filterJSON string, ms int) string {
err := library.LegacyFilterUnsubscribe(filterJSON, ms)
return makeJSONResponse(err)
}

View File

@ -0,0 +1,21 @@
package gowaku
import "github.com/waku-org/go-waku/library"
// LightpushPublish is used to publish a WakuMessage in a pubsub topic using Lightpush protocol
func LightpushPublish(messageJSON string, topic string, peerID string, ms int) string {
response, err := library.LightpushPublish(messageJSON, topic, peerID, ms)
return prepareJSONResponse(response, err)
}
// LightpushPublishEncodeAsymmetric is used to publish a WakuMessage in a pubsub topic using Lightpush protocol, and encrypting the message with some public key
func LightpushPublishEncodeAsymmetric(messageJSON string, topic string, peerID string, publicKey string, optionalSigningKey string, ms int) string {
response, err := library.LightpushPublishEncodeAsymmetric(messageJSON, topic, peerID, publicKey, optionalSigningKey, ms)
return prepareJSONResponse(response, err)
}
// LightpushPublishEncodeSymmetric is used to publish a WakuMessage in a pubsub topic using Lightpush protocol, and encrypting the message with a symmetric key
func LightpushPublishEncodeSymmetric(messageJSON string, topic string, peerID string, symmetricKey string, optionalSigningKey string, ms int) string {
response, err := library.LightpushPublishEncodeSymmetric(messageJSON, topic, peerID, symmetricKey, optionalSigningKey, ms)
return prepareJSONResponse(response, err)
}

View File

@ -0,0 +1,47 @@
package gowaku
import (
"github.com/waku-org/go-waku/library"
)
// RelayEnoughPeers determines if there are enough peers to publish a message on a topic
func RelayEnoughPeers(topic string) string {
response, err := library.RelayEnoughPeers(topic)
return prepareJSONResponse(response, err)
}
// RelayPublish publishes a message using waku relay and returns the message ID
func RelayPublish(messageJSON string, topic string, ms int) string {
hash, err := library.RelayPublish(messageJSON, topic, ms)
return prepareJSONResponse(hash, err)
}
// RelayPublishEncodeAsymmetric publish a message encrypted with a secp256k1 public key using waku relay and returns the message ID
func RelayPublishEncodeAsymmetric(messageJSON string, topic string, publicKey string, optionalSigningKey string, ms int) string {
hash, err := library.RelayPublishEncodeAsymmetric(messageJSON, topic, publicKey, optionalSigningKey, ms)
return prepareJSONResponse(hash, err)
}
// RelayPublishEncodeSymmetric publishes a message encrypted with a 32 bytes symmetric key using waku relay and returns the message ID
func RelayPublishEncodeSymmetric(messageJSON string, topic string, symmetricKey string, optionalSigningKey string, ms int) string {
hash, err := library.RelayPublishEncodeSymmetric(messageJSON, topic, symmetricKey, optionalSigningKey, ms)
return prepareJSONResponse(hash, err)
}
// RelaySubscribe subscribes to a WakuRelay topic.
func RelaySubscribe(topic string) string {
err := library.RelaySubscribe(topic)
return makeJSONResponse(err)
}
// RelayTopics returns a list of pubsub topics the node is subscribed to in WakuRelay
func RelayTopics() string {
topics, err := library.RelayTopics()
return prepareJSONResponse(topics, err)
}
// RelayUnsubscribe closes the pubsub subscription to a pubsub topic
func RelayUnsubscribe(topic string) string {
err := library.RelayUnsubscribe(topic)
return makeJSONResponse(err)
}

View File

@ -0,0 +1,17 @@
package gowaku
import (
"github.com/waku-org/go-waku/library"
)
// StoreQuery is used to retrieve historic messages using waku store protocol.
func StoreQuery(queryJSON string, peerID string, ms int) string {
response, err := library.StoreQuery(queryJSON, peerID, ms)
return prepareJSONResponse(response, err)
}
// StoreLocalQuery is used to retrieve historic messages stored in the localDB using waku store protocol.
func StoreLocalQuery(queryJSON string) string {
response, err := library.StoreLocalQuery(queryJSON)
return prepareJSONResponse(response, err)
}

View File

@ -10,7 +10,7 @@ type jsonResponseSuccess struct {
Result interface{} `json:"result"`
}
func PrepareJSONResponse(result interface{}, err error) string {
func prepareJSONResponse(result interface{}, err error) string {
if err != nil {
errStr := err.Error()
@ -23,12 +23,12 @@ func PrepareJSONResponse(result interface{}, err error) string {
data, err := json.Marshal(jsonResponseSuccess{Result: result})
if err != nil {
return PrepareJSONResponse(nil, err)
return prepareJSONResponse(nil, err)
}
return string(data)
}
func MakeJSONResponse(err error) string {
func makeJSONResponse(err error) string {
if err != nil {
errStr := err.Error()
outBytes, _ := json.Marshal(jsonResponseError{Error: &errStr})

View File

@ -1,6 +1,4 @@
// Implements gomobile bindings for go-waku. Contains a set of functions that
// are exported when go-waku is exported as libraries for mobile devices
package gowaku
package library
import (
"context"
@ -35,6 +33,7 @@ import (
"github.com/waku-org/go-waku/waku/v2/utils"
)
// WakuState represents the state of the waku node
type WakuState struct {
ctx context.Context
cancel context.CancelFunc
@ -56,35 +55,36 @@ func randomHex(n int) (string, error) {
return hex.EncodeToString(bytes), nil
}
func NewNode(configJSON string) string {
// NewNode initializes a waku node. Receives a JSON string containing the configuration, and use default values for those config items not specified
func NewNode(configJSON string) error {
if wakuState.node != nil {
return MakeJSONResponse(errors.New("go-waku already initialized. stop it first"))
return errors.New("go-waku already initialized. stop it first")
}
config, err := getConfig(configJSON)
if err != nil {
return MakeJSONResponse(err)
return err
}
hostAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", *config.Host, *config.Port))
if err != nil {
return MakeJSONResponse(err)
return err
}
var prvKey *ecdsa.PrivateKey
if config.NodeKey != nil {
prvKey, err = crypto.HexToECDSA(*config.NodeKey)
if err != nil {
return MakeJSONResponse(err)
return err
}
} else {
key, err := randomHex(32)
if err != nil {
return MakeJSONResponse(err)
return err
}
prvKey, err = crypto.HexToECDSA(key)
if err != nil {
return MakeJSONResponse(err)
return err
}
}
@ -97,7 +97,7 @@ func NewNode(configJSON string) string {
if *config.EnableRelay {
var pubsubOpt []pubsub.Option
if config.GossipSubParams != nil {
params := GetGossipSubParams(config.GossipSubParams)
params := getGossipSubParams(config.GossipSubParams)
pubsubOpt = append(pubsubOpt, pubsub.WithGossipSubParams(params))
}
@ -133,7 +133,7 @@ func NewNode(configJSON string) string {
var migrationFn func(*sql.DB) error
db, migrationFn, err = dbutils.ExtractDBAndMigration(*config.DatabaseURL)
if err != nil {
return MakeJSONResponse(err)
return err
}
opts = append(opts, node.WithWakuStore())
dbStore, err := persistence.NewDBStore(utils.Logger(),
@ -142,7 +142,7 @@ func NewNode(configJSON string) string {
persistence.WithRetentionPolicy(*config.RetentionMaxMessages, time.Duration(*config.RetentionTimeSeconds)*time.Second),
)
if err != nil {
return MakeJSONResponse(err)
return err
}
opts = append(opts, node.WithMessageProvider(dbStore))
}
@ -152,7 +152,7 @@ func NewNode(configJSON string) string {
for _, addr := range config.DiscV5BootstrapNodes {
bootnode, err := enode.Parse(enode.ValidSchemes, addr)
if err != nil {
return MakeJSONResponse(err)
return err
}
bootnodes = append(bootnodes, bootnode)
}
@ -163,36 +163,37 @@ func NewNode(configJSON string) string {
lvl, err := zapcore.ParseLevel(*config.LogLevel)
if err != nil {
return MakeJSONResponse(err)
return err
}
opts = append(opts, node.WithLogLevel(lvl))
w, err := node.New(opts...)
if err != nil {
return MakeJSONResponse(err)
return err
}
wakuState.node = w
return MakeJSONResponse(nil)
return nil
}
func Start() string {
// Start starts the waku node
func Start() error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
wakuState.ctx, wakuState.cancel = context.WithCancel(context.Background())
if err := wakuState.node.Start(wakuState.ctx); err != nil {
return MakeJSONResponse(err)
return err
}
if wakuState.node.DiscV5() != nil {
if err := wakuState.node.DiscV5().Start(context.Background()); err != nil {
wakuState.node.Stop()
return MakeJSONResponse(err)
return err
}
}
@ -200,16 +201,17 @@ func Start() string {
err := relaySubscribe(topic)
if err != nil {
wakuState.node.Stop()
return MakeJSONResponse(err)
return err
}
}
return MakeJSONResponse(nil)
return nil
}
func Stop() string {
// Stop stops a waku node
func Stop() error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
wakuState.node.Stop()
@ -218,24 +220,27 @@ func Stop() string {
wakuState.node = nil
return MakeJSONResponse(nil)
return nil
}
func IsStarted() string {
return PrepareJSONResponse(wakuState.node != nil, nil)
// IsStarted is used to determine is a node is started or not
func IsStarted() bool {
return wakuState.node != nil
}
func PeerID() string {
// PeerID is used to obtain the peer ID of the waku node
func PeerID() (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
return PrepareJSONResponse(wakuState.node.ID(), nil)
return wakuState.node.ID(), nil
}
func ListenAddresses() string {
// ListenAddresses returns the multiaddresses the wakunode is listening to
func ListenAddresses() (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
var addresses []string
@ -243,26 +248,32 @@ func ListenAddresses() string {
addresses = append(addresses, addr.String())
}
return PrepareJSONResponse(addresses, nil)
return marshalJSON(addresses)
}
func AddPeer(address string, protocolID string) string {
// AddPeer adds a node multiaddress and protocol to the wakunode peerstore
func AddPeer(address string, protocolID string) (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
ma, err := multiaddr.NewMultiaddr(address)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
peerID, err := wakuState.node.AddPeer(ma, peerstore.Static, libp2pProtocol.ID(protocolID))
return PrepareJSONResponse(peerID, err)
if err != nil {
return "", err
}
return marshalJSON(peerID)
}
func Connect(address string, ms int) string {
// Connect is used to connect to a peer at multiaddress. if ms > 0, cancel the function execution if it takes longer than N milliseconds
func Connect(address string, ms int) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -275,13 +286,13 @@ func Connect(address string, ms int) string {
ctx = context.Background()
}
err := wakuState.node.DialPeer(ctx, address)
return MakeJSONResponse(err)
return wakuState.node.DialPeer(ctx, address)
}
func ConnectPeerID(peerID string, ms int) string {
// ConnectPeerID is usedd to connect to a known peer by peerID. if ms > 0, cancel the function execution if it takes longer than N milliseconds
func ConnectPeerID(peerID string, ms int) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
var ctx context.Context
@ -289,7 +300,7 @@ func ConnectPeerID(peerID string, ms int) string {
pID, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return err
}
if ms > 0 {
@ -299,40 +310,43 @@ func ConnectPeerID(peerID string, ms int) string {
ctx = context.Background()
}
err = wakuState.node.DialPeerByID(ctx, pID)
return MakeJSONResponse(err)
return wakuState.node.DialPeerByID(ctx, pID)
}
func Disconnect(peerID string) string {
// Disconnect closes a connection to a known peer by peerID
func Disconnect(peerID string) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
pID, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return err
}
err = wakuState.node.ClosePeerById(pID)
return MakeJSONResponse(err)
return wakuState.node.ClosePeerById(pID)
}
func PeerCnt() string {
// PeerCnt returns the number of connected peers
func PeerCnt() (int, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return 0, errWakuNodeNotReady
}
return PrepareJSONResponse(wakuState.node.PeerCount(), nil)
return wakuState.node.PeerCount(), nil
}
// ContentTopic creates a content topic string according to RFC 23
func ContentTopic(applicationName string, applicationVersion int, contentTopicName string, encoding string) string {
return protocol.NewContentTopic(applicationName, uint(applicationVersion), contentTopicName, encoding).String()
}
// PubsubTopic creates a pubsub topic string according to RFC 23
func PubsubTopic(name string, encoding string) string {
return protocol.NewNamedShardingPubsubTopic(name + "/" + encoding).String()
}
// DefaultPubsubTopic returns the default pubsub topic used in waku2: /waku/2/default-waku/proto
func DefaultPubsubTopic() string {
return protocol.DefaultPubsubTopic().String()
}
@ -358,13 +372,18 @@ func toSubscriptionMessage(msg *protocol.Envelope) *subscriptionMsg {
}
}
func Peers() string {
// Peers retrieves the list of peers known by the waku node
func Peers() (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
peers, err := wakuState.node.Peers()
return PrepareJSONResponse(peers, err)
if err != nil {
return "", err
}
return marshalJSON(peers)
}
func unmarshalPubkey(pub []byte) (ecdsa.PublicKey, error) {
@ -388,17 +407,18 @@ func extractPubKeyAndSignature(payload *payload.DecodedPayload) (pubkey string,
return
}
func DecodeSymmetric(messageJSON string, symmetricKey string) string {
// DecodeSymmetric decodes a waku message using a 32 bytes symmetric key. The key must be a hex encoded string with "0x" prefix
func DecodeSymmetric(messageJSON string, symmetricKey string) (string, error) {
var msg pb.WakuMessage
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
if msg.Version == 0 {
return PrepareJSONResponse(msg.Payload, nil)
return marshalJSON(msg.Payload)
} else if msg.Version > 1 {
return MakeJSONResponse(errors.New("unsupported wakumessage version"))
return "", errors.New("unsupported wakumessage version")
}
keyInfo := &payload.KeyInfo{
@ -407,12 +427,12 @@ func DecodeSymmetric(messageJSON string, symmetricKey string) string {
keyInfo.SymKey, err = utils.DecodeHexString(symmetricKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
payload, err := payload.DecodePayload(&msg, keyInfo)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
pubkey, signature := extractPubKeyAndSignature(payload)
@ -429,20 +449,21 @@ func DecodeSymmetric(messageJSON string, symmetricKey string) string {
Padding: payload.Padding,
}
return PrepareJSONResponse(response, err)
return marshalJSON(response)
}
func DecodeAsymmetric(messageJSON string, privateKey string) string {
// DecodeAsymmetric decodes a waku message using a secp256k1 private key. The key must be a hex encoded string with "0x" prefix
func DecodeAsymmetric(messageJSON string, privateKey string) (string, error) {
var msg pb.WakuMessage
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
if msg.Version == 0 {
return PrepareJSONResponse(msg.Payload, nil)
return marshalJSON(msg.Payload)
} else if msg.Version > 1 {
return MakeJSONResponse(errors.New("unsupported wakumessage version"))
return "", errors.New("unsupported wakumessage version")
}
keyInfo := &payload.KeyInfo{
@ -451,17 +472,17 @@ func DecodeAsymmetric(messageJSON string, privateKey string) string {
keyBytes, err := utils.DecodeHexString(privateKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
keyInfo.PrivKey, err = crypto.ToECDSA(keyBytes)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
payload, err := payload.DecodePayload(&msg, keyInfo)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
pubkey, signature := extractPubKeyAndSignature(payload)
@ -478,5 +499,5 @@ func DecodeAsymmetric(messageJSON string, privateKey string) string {
Padding: payload.Padding,
}
return PrepareJSONResponse(response, err)
return marshalJSON(response)
}

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"context"
@ -15,9 +15,10 @@ import (
var relaySubscriptions map[string]*relay.Subscription = make(map[string]*relay.Subscription)
var relaySubsMutex sync.Mutex
func RelayEnoughPeers(topic string) string {
// RelayEnoughPeers determines if there are enough peers to publish a message on a topic
func RelayEnoughPeers(topic string) (bool, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return false, errWakuNodeNotReady
}
topicToCheck := protocol.DefaultPubsubTopic().String()
@ -25,7 +26,7 @@ func RelayEnoughPeers(topic string) string {
topicToCheck = topic
}
return PrepareJSONResponse(wakuState.node.Relay().EnoughPeersToPublishToTopic(topicToCheck), nil)
return wakuState.node.Relay().EnoughPeersToPublishToTopic(topicToCheck), nil
}
func relayPublish(msg *pb.WakuMessage, pubsubTopic string, ms int) (string, error) {
@ -47,36 +48,34 @@ func relayPublish(msg *pb.WakuMessage, pubsubTopic string, ms int) (string, erro
return hexutil.Encode(hash), err
}
func RelayPublish(messageJSON string, topic string, ms int) string {
// RelayPublish publishes a message using waku relay and returns the message ID
func RelayPublish(messageJSON string, topic string, ms int) (string, error) {
msg, err := wakuMessage(messageJSON)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
return relayPublish(msg, getTopic(topic), int(ms))
}
func RelayPublishEncodeAsymmetric(messageJSON string, topic string, publicKey string, optionalSigningKey string, ms int) string {
// RelayPublishEncodeAsymmetric publish a message encrypted with a secp256k1 public key using waku relay and returns the message ID
func RelayPublishEncodeAsymmetric(messageJSON string, topic string, publicKey string, optionalSigningKey string, ms int) (string, error) {
msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
return relayPublish(msg, getTopic(topic), int(ms))
}
func RelayPublishEncodeSymmetric(messageJSON string, topic string, symmetricKey string, optionalSigningKey string, ms int) string {
// RelayPublishEncodeSymmetric publishes a message encrypted with a 32 bytes symmetric key using waku relay and returns the message ID
func RelayPublishEncodeSymmetric(messageJSON string, topic string, symmetricKey string, optionalSigningKey string, ms int) (string, error) {
msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
return relayPublish(msg, getTopic(topic), int(ms))
}
func relaySubscribe(topic string) error {
@ -106,25 +105,28 @@ func relaySubscribe(topic string) error {
return nil
}
func RelaySubscribe(topic string) string {
// RelaySubscribe subscribes to a WakuRelay topic.
func RelaySubscribe(topic string) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
return MakeJSONResponse(relaySubscribe(topic))
return relaySubscribe(topic)
}
func RelayTopics() string {
// RelayTopics returns a list of pubsub topics the node is subscribed to in WakuRelay
func RelayTopics() (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
return PrepareJSONResponse(wakuState.node.Relay().Topics(), nil)
return marshalJSON(wakuState.node.Relay().Topics())
}
func RelayUnsubscribe(topic string) string {
// RelayUnsubscribe closes the pubsub subscription to a pubsub topic
func RelayUnsubscribe(topic string) error {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return errWakuNodeNotReady
}
topicToUnsubscribe := getTopic(topic)
@ -134,17 +136,12 @@ func RelayUnsubscribe(topic string) string {
subscription, ok := relaySubscriptions[topicToUnsubscribe]
if ok {
return MakeJSONResponse(nil)
return nil
}
subscription.Unsubscribe()
delete(relaySubscriptions, topicToUnsubscribe)
err := wakuState.node.Relay().Unsubscribe(context.Background(), topicToUnsubscribe)
if err != nil {
return MakeJSONResponse(err)
}
return MakeJSONResponse(nil)
return wakuState.node.Relay().Unsubscribe(context.Background(), topicToUnsubscribe)
}

11
library/response.go Normal file
View File

@ -0,0 +1,11 @@
package library
import "encoding/json"
func marshalJSON(result interface{}) (string, error) {
data, err := json.Marshal(result)
if err != nil {
return "", err
}
return string(data), nil
}

View File

@ -7,12 +7,12 @@
#include <stdbool.h>
#include "_cgo_export.h"
typedef void (*callback)(const char *jsonEvent);
typedef void (*callback)(const char *jsonEvent, size_t len_0);
callback gCallback = 0;
bool StatusServiceSignalEvent(const char *jsonEvent) {
bool ServiceSignalEvent(const char *jsonEvent, size_t len_0) {
if (gCallback) {
gCallback(jsonEvent);
gCallback(jsonEvent, len_0);
}
return true;

View File

@ -1,10 +1,10 @@
package gowaku
package library
/*
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
extern bool StatusServiceSignalEvent(const char *jsonEvent);
extern bool ServiceSignalEvent(const char *jsonEvent, size_t len);
extern void SetEventCallback(void *cb);
*/
import "C"
@ -56,8 +56,9 @@ func send(signalType string, event interface{}) {
mobileSignalHandler(data)
} else {
// ...and fallback to C implementation otherwise.
str := C.CString(string(data))
C.StatusServiceSignalEvent(str)
dataStr := string(data)
str := C.CString(dataStr)
C.ServiceSignalEvent(str, C.size_t(len(data)))
C.free(unsafe.Pointer(str))
}
}

View File

@ -1,4 +1,4 @@
package gowaku
package library
import (
"C"
@ -35,7 +35,7 @@ type storeMessagesReply struct {
Error string `json:"error,omitempty"`
}
func queryResponse(ctx context.Context, args storeMessagesArgs, options []store.HistoryRequestOption) string {
func queryResponse(ctx context.Context, args storeMessagesArgs, options []store.HistoryRequestOption) (string, error) {
var contentTopics []string
for _, ct := range args.ContentFilters {
contentTopics = append(contentTopics, ct.ContentTopic)
@ -56,7 +56,7 @@ func queryResponse(ctx context.Context, args storeMessagesArgs, options []store.
if err != nil {
reply.Error = err.Error()
return PrepareJSONResponse(reply, nil)
return marshalJSON(reply)
}
reply.Messages = res.Messages
reply.PagingInfo = storePagingOptions{
@ -65,18 +65,19 @@ func queryResponse(ctx context.Context, args storeMessagesArgs, options []store.
Forward: args.PagingOptions.Forward,
}
return PrepareJSONResponse(reply, nil)
return marshalJSON(reply)
}
func StoreQuery(queryJSON string, peerID string, ms int) string {
// StoreQuery is used to retrieve historic messages using waku store protocol.
func StoreQuery(queryJSON string, peerID string, ms int) (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
var args storeMessagesArgs
err := json.Unmarshal([]byte(queryJSON), &args)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
options := []store.HistoryRequestOption{
@ -88,7 +89,7 @@ func StoreQuery(queryJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
options = append(options, store.WithPeer(p))
} else {
@ -108,15 +109,16 @@ func StoreQuery(queryJSON string, peerID string, ms int) string {
return queryResponse(ctx, args, options)
}
func StoreLocalQuery(queryJSON string) string {
// StoreLocalQuery is used to retrieve historic messages stored in the localDB using waku store protocol.
func StoreLocalQuery(queryJSON string) (string, error) {
if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady)
return "", errWakuNodeNotReady
}
var args storeMessagesArgs
err := json.Unmarshal([]byte(queryJSON), &args)
if err != nil {
return MakeJSONResponse(err)
return "", err
}
options := []store.HistoryRequestOption{