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

View File

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

View File

@ -31,7 +31,7 @@ build:
+ mkdir -p build + mkdir -p build
$(CC) \ $(CC) \
-I../../build/lib/ \ -I../../build/lib/ \
main.c \ main.c base64.c \
../../build/lib/libgowaku.a \ ../../build/lib/libgowaku.a \
-lm \ -lm \
-pthread \ -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 "libgowaku.h"
#include "nxjson.c" #include "nxjson.c"
#include "base64.h"
#include "main.h" #include "main.h"
char *alicePrivKey = "0x4f012057e1a1458ce34189cb27daedbbe434f3df0825c1949475dec786e2c64e"; char *alicePrivKey = "0x4f012057e1a1458ce34189cb27daedbbe434f3df0825c1949475dec786e2c64e";
@ -16,7 +17,24 @@ char *alicePubKey = "0x0440f05847c4c7166f57ae8ecaaf72d31bddcbca345e26713ca9e26c9
char *bobPrivKey = "0xb91d6b2df8fb6ef8b53b51b2b30a408c49d5e2b530502d58ac8f94e5c5de1453"; char *bobPrivKey = "0xb91d6b2df8fb6ef8b53b51b2b30a408c49d5e2b530502d58ac8f94e5c5de1453";
char *bobPubKey = "0x045eef61a98ba1cf44a2736fac91183ea2bd86e67de20fe4bff467a71249a8a0c05f795dd7f28ced7c15eaa69c89d4212cc4f526ca5e9a62e88008f506d850cccd"; 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 // 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; const char *type = nx_json_get(json, "type")->text_value;
if (strcmp(type, "message") == 0) if (strcmp(type, "message") == 0)
{ {
char* msg = utils_extract_wakumessage_from_signal(json); const nx_json *wakuMsgJson = nx_json_get(nx_json_get(json, "event"), "wakuMessage");
char *decodedMsg = waku_decode_asymmetric(msg, bobPrivKey); const char *contentTopic = nx_json_get(wakuMsgJson, "contentTopic")->text_value;
free(msg);
if(isError(decodedMsg)) { if (strcmp(contentTopic, contentTopic) == 0)
free(decodedMsg); {
return; 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 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); 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); fflush(stdout);
free(data); }
} }
nx_json_free(json); nx_json_free(json);
@ -66,50 +89,39 @@ void callBack(char *signal)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *response;
waku_set_event_callback(callBack); waku_set_event_callback(callBack);
char *configJSON = "{\"host\": \"0.0.0.0\", \"port\": 60000, \"logLevel\":\"error\", \"store\":true}"; 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 WAKU_CALL( waku_new(configJSON, handle_error) ); // configJSON can be NULL too to use defaults
if (isError(response))
return 1;
response = waku_start(); // Start the node, enabling the waku protocols WAKU_CALL(waku_start(handle_error) ); // Start the node, enabling the waku protocols
if (isError(response))
return 1;
response = waku_peerid(); // Obtain the node peerID WAKU_CALL(waku_peerid(handle_ok, handle_error)); // Obtain the node peerID
if (isError(response)) char *peerID = strdup(result);
return 1; printf("PeerID: %s\n", result);
char *nodePeerID = utils_get_str(response);
printf("PeerID: %s\n", nodePeerID);
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 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
if (isError(response))
printf("Could not connect to node: %s\n", response);
/*
// To use dns discovery, and retrieve nodes from a enrtree url // 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 WAKU_CALL( waku_dns_discovery("enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im", "", 0, handle_ok, handle_error)); // Discover Nodes
if (isError(response)) printf("Discovered nodes: %s\n", result);
return 1;
printf("Discovered nodes: %s\n", response); 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}}", pubsubTopic);
WAKU_CALL(waku_store_query(query, NULL, 0, handle_ok, handle_error));
printf("%s\n",result);
*/ */
/* WAKU_CALL( waku_relay_subscribe(NULL, handle_error));
// 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);
*/
response = waku_relay_subscribe(NULL);
if (isError(response))
return 1;
int i = 0; int i = 0;
int version = 1; int version = 1;
@ -118,20 +130,18 @@ int main(int argc, char *argv[])
i++; i++;
char wakuMsg[1000]; char wakuMsg[1000];
char *msgPayload = waku_utils_base64_encode("Hello World!"); char *msgPayload = b64_encode("Hello World!", 12);
char *contentTopic = waku_content_topic("example", 1, "default", "rfc26");
sprintf(wakuMsg, "{\"payload\":\"%s\",\"contentTopic\":\"%s\",\"timestamp\":%"PRIu64"}", msgPayload, contentTopic, nowInNanosecs()); sprintf(wakuMsg, "{\"payload\":\"%s\",\"contentTopic\":\"%s\",\"timestamp\":%"PRIu64"}", msgPayload, contentTopic, nowInNanosecs());
free(msgPayload); 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 char *messageID = strdup(result);
// 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 printf("MessageID: %s\n",messageID);
if (isError(response))
return 1;
// char *messageID = utils_get_str(response); free(messageID);
// free(messageID);
sleep(1); 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 // To retrieve messages from local store, set store:true in the node config, and use waku_store_local_query
/* /*
char query[1000]; char query[1000];
sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", waku_default_pubsub_topic()); sprintf(query, "{\"pubsubTopic\":\"%s\", \"pagingOptions\":{\"pageSize\": 40, \"forward\":false}}", pubsubTopic);
response = waku_store_local_query(query); WAKU_CALL(waku_store_local_query(query, handle_ok, handle_error));
if (isError(response)) printf("%s\n",result);
return 1;
printf("%s\n",response);
*/ */
response = waku_stop(); WAKU_CALL(waku_stop(handle_error));
if (isError(response))
return 1;
return 0; return 0;
} }

View File

@ -7,6 +7,14 @@
/// Convert seconds to nanoseconds /// Convert seconds to nanoseconds
#define SEC_TO_NS(sec) ((sec)*1000000000) #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 nowInNanosecs(){
uint64_t nanoseconds; 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 *payload = nx_json_get(wakuMsgJson, "payload")->text_value;
const char *contentTopic = nx_json_get(wakuMsgJson, "contentTopic")->text_value; const char *contentTopic = nx_json_get(wakuMsgJson, "contentTopic")->text_value;
int version = nx_json_get(wakuMsgJson, "version")->int_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; 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 */ #endif /* MAIN_H */

View File

@ -35,7 +35,7 @@
in rec { in rec {
packages = forAllSystems (system: { packages = forAllSystems (system: {
node = buildPackage system ["cmd/waku"]; node = buildPackage system ["cmd/waku"];
library = buildPackage system ["library"]; library = buildPackage system ["library/c"];
}); });
defaultPackage = forAllSystems (system: 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 <stdlib.h>
#include <stddef.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 "C"
import ( import (
"fmt"
"unsafe" "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" "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() {} func main() {}
// Initialize a waku node. Receives a JSON string containing the configuration // 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. // - dns4DomainName: the domain name resolving to the node's public IPv4 address.
// //
//export waku_new //export waku_new
func waku_new(configJSON *C.char) *C.char { func waku_new(configJSON *C.char, onErrCb C.WakuCallBack) C.int {
response := mobile.NewNode(C.GoString(configJSON)) err := library.NewNode(C.GoString(configJSON))
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Starts the waku node // Starts the waku node
// //
//export waku_start //export waku_start
func waku_start() *C.char { func waku_start(onErrCb C.WakuCallBack) C.int {
response := mobile.Start() err := library.Start()
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Stops a waku node // Stops a waku node
// //
//export waku_stop //export waku_stop
func waku_stop() *C.char { func waku_stop(onErrCb C.WakuCallBack) C.int {
response := mobile.Stop() err := library.Stop()
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Determine is a node is started or not // Determine is a node is started or not
// //
//export waku_is_started //export waku_is_started
func waku_is_started() *C.char { func waku_is_started() C.int {
response := mobile.IsStarted() started := library.IsStarted()
return C.CString(response) 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 // Obtain the peer ID of the waku node
// //
//export waku_peerid //export waku_peerid
func waku_peerid() *C.char { func waku_peerid(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.PeerID() return singleFnExec(func() (string, error) {
return C.CString(response) return library.PeerID()
}, onOkCb, onErrCb)
} }
// Obtain the multiaddresses the wakunode is listening to // Obtain the multiaddresses the wakunode is listening to
// //
//export waku_listen_addresses //export waku_listen_addresses
func waku_listen_addresses() *C.char { func waku_listen_addresses(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.ListenAddresses() return singleFnExec(func() (string, error) {
return C.CString(response) return library.ListenAddresses()
}, onOkCb, onErrCb)
} }
// Add node multiaddress and protocol to the wakunode peerstore // Add node multiaddress and protocol to the wakunode peerstore
// //
//export waku_add_peer //export waku_add_peer
func waku_add_peer(address *C.char, protocolID *C.char) *C.char { func waku_add_peer(address *C.char, protocolID *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.AddPeer(C.GoString(address), C.GoString(protocolID)) return singleFnExec(func() (string, error) {
return C.CString(response) 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 // Connect to peer at multiaddress. if ms > 0, cancel the function execution if it takes longer than N milliseconds
// //
//export waku_connect //export waku_connect
func waku_connect(address *C.char, ms C.int) *C.char { func waku_connect(address *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
response := mobile.Connect(C.GoString(address), int(ms)) err := library.Connect(C.GoString(address), int(ms))
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Connect to known peer by peerID. if ms > 0, cancel the function execution if it takes longer than N milliseconds // Connect to known peer by peerID. if ms > 0, cancel the function execution if it takes longer than N milliseconds
// //
//export waku_connect_peerid //export waku_connect_peerid
func waku_connect_peerid(peerID *C.char, ms C.int) *C.char { func waku_connect_peerid(peerID *C.char, ms C.int, onErrCb C.WakuCallBack) C.int {
response := mobile.ConnectPeerID(C.GoString(peerID), int(ms)) err := library.ConnectPeerID(C.GoString(peerID), int(ms))
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Close connection to a known peer by peerID // Close connection to a known peer by peerID
// //
//export waku_disconnect //export waku_disconnect
func waku_disconnect(peerID *C.char) *C.char { func waku_disconnect(peerID *C.char, onErrCb C.WakuCallBack) C.int {
response := mobile.Disconnect(C.GoString(peerID)) err := library.Disconnect(C.GoString(peerID))
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Get number of connected peers // Get number of connected peers
// //
//export waku_peer_cnt //export waku_peer_cnt
func waku_peer_cnt() *C.char { func waku_peer_cnt(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.PeerCnt() return singleFnExec(func() (string, error) {
return C.CString(response) peerCnt, err := library.PeerCnt()
return fmt.Sprintf("%d", peerCnt), err
}, onOkCb, onErrCb)
} }
// Create a content topic string according to RFC 23 // Create a content topic string according to RFC 23
// //
//export waku_content_topic //export waku_content_topic
func waku_content_topic(applicationName *C.char, applicationVersion C.uint, contentTopicName *C.char, encoding *C.char) *C.char { func waku_content_topic(applicationName *C.char, applicationVersion C.uint, contentTopicName *C.char, encoding *C.char, onOkCb C.WakuCallBack) C.int {
return C.CString(protocol.NewContentTopic(C.GoString(applicationName), uint(applicationVersion), C.GoString(contentTopicName), C.GoString(encoding)).String()) 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 // Create a pubsub topic string according to RFC 23
// //
//export waku_pubsub_topic //export waku_pubsub_topic
func waku_pubsub_topic(name *C.char, encoding *C.char) *C.char { func waku_pubsub_topic(name *C.char, encoding *C.char, onOkCb C.WakuCallBack) C.int {
return C.CString(mobile.PubsubTopic(C.GoString(name), C.GoString(encoding))) 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 // Get the default pubsub topic used in waku2: /waku/2/default-waku/proto
// //
//export waku_default_pubsub_topic //export waku_default_pubsub_topic
func waku_default_pubsub_topic() *C.char { func waku_default_pubsub_topic(onOkCb C.WakuCallBack) C.int {
return C.CString(mobile.DefaultPubsubTopic()) return execOkCB(onOkCb, library.DefaultPubsubTopic())
} }
// Register callback to act as signal handler and receive application signals // 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)` // signature for the callback should be `void myCallback(char* signalJSON)`
// //
//export waku_set_event_callback //export waku_set_event_callback
func waku_set_event_callback(cb unsafe.Pointer) { func waku_set_event_callback(cb C.WakuCallBack) {
mobile.SetEventCallback(cb) library.SetEventCallback(unsafe.Pointer(cb))
} }
// Retrieve the list of peers known by the waku node // Retrieve the list of peers known by the waku node
// //
//export waku_peers //export waku_peers
func waku_peers() *C.char { func waku_peers(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.Peers() return singleFnExec(func() (string, error) {
return C.CString(response) 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 // 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 //export waku_decode_symmetric
func waku_decode_symmetric(messageJSON *C.char, symmetricKey *C.char) *C.char { func waku_decode_symmetric(messageJSON *C.char, symmetricKey *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.DecodeSymmetric(C.GoString(messageJSON), C.GoString(symmetricKey)) return singleFnExec(func() (string, error) {
return C.CString(response) 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 // Decode a waku message using a secp256k1 private key. The key must be a hex encoded string with "0x" prefix
// //
//export waku_decode_asymmetric //export waku_decode_asymmetric
func waku_decode_asymmetric(messageJSON *C.char, privateKey *C.char) *C.char { func waku_decode_asymmetric(messageJSON *C.char, privateKey *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.DecodeAsymmetric(C.GoString(messageJSON), C.GoString(privateKey)) return singleFnExec(func() (string, error) {
return C.CString(response) return library.DecodeAsymmetric(C.GoString(messageJSON), C.GoString(privateKey))
}, onOkCb, onErrCb)
} }

View File

@ -1,10 +1,11 @@
package main 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 // 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 // (in milliseconds) is reached, or an error will be returned
// //
//export waku_dns_discovery //export waku_dns_discovery
func waku_dns_discovery(url *C.char, nameserver *C.char, ms C.int) *C.char { func waku_dns_discovery(url *C.char, nameserver *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.DnsDiscovery(C.GoString(url), C.GoString(nameserver), int(ms)) return singleFnExec(func() (string, error) {
return C.CString(response) return library.DNSDiscovery(C.GoString(url), C.GoString(nameserver), int(ms))
}, onOkCb, onErrCb)
} }
// Update the bootnode list used for discovering new peers via DiscoveryV5 // 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:..."]` // The bootnodes param should contain a JSON array containing the bootnode ENRs i.e. `["enr:...", "enr:..."]`
// //
//export waku_discv5_update_bootnodes //export waku_discv5_update_bootnodes
func waku_discv5_update_bootnodes(bootnodes *C.char) *C.char { func waku_discv5_update_bootnodes(bootnodes *C.char, onErrCb C.WakuCallBack) C.int {
response := mobile.SetBootnodes(C.GoString(bootnodes)) err := library.SetBootnodes(C.GoString(bootnodes))
return C.CString(response) return execErrCB(onErrCb, err)
} }

View File

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

View File

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

View File

@ -1,41 +1,47 @@
package main 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.. // 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 // 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 // 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 // (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)) //export waku_lightpush_publish
return C.CString(response) 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. // 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 // 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. // 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 // 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 // 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. // (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)) //export waku_lightpush_publish_enc_asymmetric
return C.CString(response) 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. // 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 // 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 // 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 // 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 // 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. // (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)) //export waku_lightpush_publish_enc_symmetric
return C.CString(response) 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 package main
import ( /*
"C" #include <cgo_utils.h>
*/
mobile "github.com/waku-org/go-waku/mobile" 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 // 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 // to verify the number of peers in the default pubsub topic
// //
//export waku_relay_enough_peers //export waku_relay_enough_peers
func waku_relay_enough_peers(topic *C.char) *C.char { func waku_relay_enough_peers(topic *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.RelayEnoughPeers(C.GoString(topic)) return singleFnExec(func() (string, error) {
return C.CString(response) 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 // Publish a message using waku relay and returns the message ID. Use NULL for topic to use the default pubsub topic
@ -20,9 +25,10 @@ func waku_relay_enough_peers(topic *C.char) *C.char {
// (in milliseconds) is reached, or an error will be returned. // (in milliseconds) is reached, or an error will be returned.
// //
//export waku_relay_publish //export waku_relay_publish
func waku_relay_publish(messageJSON *C.char, topic *C.char, ms C.int) *C.char { func waku_relay_publish(messageJSON *C.char, topic *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.RelayPublish(C.GoString(messageJSON), C.GoString(topic), int(ms)) return singleFnExec(func() (string, error) {
return C.CString(response) 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.
@ -32,9 +38,10 @@ func waku_relay_publish(messageJSON *C.char, topic *C.char, ms C.int) *C.char {
// (in milliseconds) is reached, or an error will be returned. // (in milliseconds) is reached, or an error will be returned.
// //
//export waku_relay_publish_enc_asymmetric //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 { 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 {
response := mobile.RelayPublishEncodeAsymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(publicKey), C.GoString(optionalSigningKey), int(ms)) return singleFnExec(func() (string, error) {
return C.CString(response) 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.
@ -44,9 +51,10 @@ func waku_relay_publish_enc_asymmetric(messageJSON *C.char, topic *C.char, publi
// (in milliseconds) is reached, or an error will be returned. // (in milliseconds) is reached, or an error will be returned.
// //
//export waku_relay_publish_enc_symmetric //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 { 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 {
response := mobile.RelayPublishEncodeSymmetric(C.GoString(messageJSON), C.GoString(topic), C.GoString(symmetricKey), C.GoString(optionalSigningKey), int(ms)) return singleFnExec(func() (string, error) {
return C.CString(response) 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 // 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 // the message was received
// //
//export waku_relay_subscribe //export waku_relay_subscribe
func waku_relay_subscribe(topic *C.char) *C.char { func waku_relay_subscribe(topic *C.char, onErrCb C.WakuCallBack) C.int {
response := mobile.RelaySubscribe(C.GoString(topic)) err := library.RelaySubscribe(C.GoString(topic))
return C.CString(response) return execErrCB(onErrCb, err)
} }
// Returns a json response with the list of pubsub topics the node // Returns a json response with the list of pubsub topics the node
// is subscribed to in WakuRelay // is subscribed to in WakuRelay
// //
//export waku_relay_topics //export waku_relay_topics
func waku_relay_topics() *C.char { func waku_relay_topics(onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.RelayTopics() return singleFnExec(func() (string, error) {
return C.CString(response) return library.RelayTopics()
}, onOkCb, onErrCb)
} }
// Closes the pubsub subscription to a pubsub topic // Closes the pubsub subscription to a pubsub topic
// //
//export waku_relay_unsubscribe //export waku_relay_unsubscribe
func waku_relay_unsubscribe(topic *C.char) *C.char { func waku_relay_unsubscribe(topic *C.char, onErrCb C.WakuCallBack) C.int {
response := mobile.RelayUnsubscribe(C.GoString(topic)) err := library.RelayUnsubscribe(C.GoString(topic))
return C.CString(response) return execErrCB(onErrCb, err)
} }

View File

@ -1,10 +1,10 @@
package main package main
import ( /*
"C" #include <cgo_utils.h>
*/
mobile "github.com/waku-org/go-waku/mobile" import "C"
) import "github.com/waku-org/go-waku/library"
// Query historic messages using waku store protocol. // Query historic messages using waku store protocol.
// queryJSON must contain a valid json string with the following format: // 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 // (in milliseconds) is reached, or an error will be returned
// //
//export waku_store_query //export waku_store_query
func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int) *C.char { func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.StoreQuery(C.GoString(queryJSON), C.GoString(peerID), int(ms)) return singleFnExec(func() (string, error) {
return C.CString(response) return library.StoreQuery(C.GoString(queryJSON), C.GoString(peerID), int(ms))
}, onOkCb, onErrCb)
} }
// Query historic messages stored in the localDB using waku store protocol. // 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 // Requires the `store` option to be passed when setting up the initial configuration
// //
//export waku_store_local_query //export waku_store_local_query
func waku_store_local_query(queryJSON *C.char) *C.char { func waku_store_local_query(queryJSON *C.char, onOkCb C.WakuCallBack, onErrCb C.WakuCallBack) C.int {
response := mobile.StoreLocalQuery(C.GoString(queryJSON)) return singleFnExec(func() (string, error) {
return C.CString(response) 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 ( import (
"encoding/json" "encoding/json"
@ -308,7 +308,7 @@ func getSeenTTL(cfg WakuConfig) time.Duration {
return time.Duration(*cfg.GossipSubParams.SeenMessagesTTLSeconds) return time.Duration(*cfg.GossipSubParams.SeenMessagesTTLSeconds)
} }
func GetGossipSubParams(cfg *GossipSubParams) pubsub.GossipSubParams { func getGossipSubParams(cfg *GossipSubParams) pubsub.GossipSubParams {
params := pubsub.DefaultGossipSubParams() params := pubsub.DefaultGossipSubParams()
if cfg.D != nil { if cfg.D != nil {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package gowaku package library
import ( import (
"context" "context"
@ -41,34 +41,32 @@ func lightpushPublish(msg *pb.WakuMessage, pubsubTopic string, peerID string, ms
return hexutil.Encode(hash), err 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) msg, err := wakuMessage(messageJSON)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms) return lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
} }
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) msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms) return lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
} }
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) msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms) return lightpushPublish(msg, getTopic(topic), peerID, ms)
return PrepareJSONResponse(hash, err)
} }

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

View File

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

View File

@ -1,4 +1,4 @@
package gowaku package library
import ( import (
"context" "context"
@ -15,9 +15,10 @@ import (
var relaySubscriptions map[string]*relay.Subscription = make(map[string]*relay.Subscription) var relaySubscriptions map[string]*relay.Subscription = make(map[string]*relay.Subscription)
var relaySubsMutex sync.Mutex 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 { if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady) return false, errWakuNodeNotReady
} }
topicToCheck := protocol.DefaultPubsubTopic().String() topicToCheck := protocol.DefaultPubsubTopic().String()
@ -25,7 +26,7 @@ func RelayEnoughPeers(topic string) string {
topicToCheck = topic 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) { 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 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) msg, err := wakuMessage(messageJSON)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := relayPublish(msg, getTopic(topic), int(ms)) return relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
} }
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) msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := relayPublish(msg, getTopic(topic), int(ms)) return relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
} }
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) msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil { if err != nil {
return MakeJSONResponse(err) return "", err
} }
hash, err := relayPublish(msg, getTopic(topic), int(ms)) return relayPublish(msg, getTopic(topic), int(ms))
return PrepareJSONResponse(hash, err)
} }
func relaySubscribe(topic string) error { func relaySubscribe(topic string) error {
@ -106,25 +105,28 @@ func relaySubscribe(topic string) error {
return nil return nil
} }
func RelaySubscribe(topic string) string { // RelaySubscribe subscribes to a WakuRelay topic.
func RelaySubscribe(topic string) error {
if wakuState.node == nil { 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 { 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 { if wakuState.node == nil {
return MakeJSONResponse(errWakuNodeNotReady) return errWakuNodeNotReady
} }
topicToUnsubscribe := getTopic(topic) topicToUnsubscribe := getTopic(topic)
@ -134,17 +136,12 @@ func RelayUnsubscribe(topic string) string {
subscription, ok := relaySubscriptions[topicToUnsubscribe] subscription, ok := relaySubscriptions[topicToUnsubscribe]
if ok { if ok {
return MakeJSONResponse(nil) return nil
} }
subscription.Unsubscribe() subscription.Unsubscribe()
delete(relaySubscriptions, topicToUnsubscribe) delete(relaySubscriptions, topicToUnsubscribe)
err := wakuState.node.Relay().Unsubscribe(context.Background(), topicToUnsubscribe) return wakuState.node.Relay().Unsubscribe(context.Background(), topicToUnsubscribe)
if err != nil {
return MakeJSONResponse(err)
}
return MakeJSONResponse(nil)
} }

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

View File

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

View File

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