From 4b8ea80e80c176dc22909890e051092f02777295 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande <ivansete@status.im> Date: Sun, 11 Jun 2023 14:42:14 +0200 Subject: [PATCH 1/4] Adding example of nwaku integration in Go --- examples/golang/libwaku.h | 45 +++ examples/golang/nimbase.h | 602 ++++++++++++++++++++++++++++++++++++++ examples/golang/waku.go | 89 ++++++ 3 files changed, 736 insertions(+) create mode 100644 examples/golang/libwaku.h create mode 100644 examples/golang/nimbase.h create mode 100644 examples/golang/waku.go diff --git a/examples/golang/libwaku.h b/examples/golang/libwaku.h new file mode 100644 index 0000000000..4621ecd320 --- /dev/null +++ b/examples/golang/libwaku.h @@ -0,0 +1,45 @@ +/* Generated by Nim Compiler v1.6.11 */ +#ifndef __libwaku__ +#define __libwaku__ +#define NIM_INTBITS 64 + +#include "nimbase.h" +#undef LANGUAGE_C +#undef MIPSEB +#undef MIPSEL +#undef PPC +#undef R3000 +#undef R4000 +#undef i386 +#undef linux +#undef mips +#undef near +#undef far +#undef powerpc +#undef unix +typedef struct ConfigNode ConfigNode; +typedef struct NimStringDesc NimStringDesc; +typedef struct TGenericSeq TGenericSeq; +struct TGenericSeq {NI len; +NI reserved; +}; +struct NimStringDesc { TGenericSeq Sup;NIM_CHAR data[SEQ_DECL_SIZE]; +}; +typedef N_CDECL_PTR(void, tyProc__5cp59bim9aJ4WupX5aVaD1Sg) (NCSTRING signal_0); +N_LIB_PRIVATE N_NOCONV(void, signalHandler)(int sign); +N_LIB_PRIVATE N_NIMCALL(NI, getRefcount)(void* p); +N_LIB_IMPORT N_CDECL(NIM_BOOL, waku_new)(ConfigNode* config, NimStringDesc** jsonResp); +N_LIB_IMPORT N_CDECL(NCSTRING, waku_version)(void); +N_LIB_IMPORT N_CDECL(void, waku_set_event_callback)(tyProc__5cp59bim9aJ4WupX5aVaD1Sg callback); +N_LIB_IMPORT N_CDECL(void, waku_content_topic)(NCSTRING appName, NU appVersion, NCSTRING contentTopicName, NCSTRING encoding, NimStringDesc** outContentTopic); +N_LIB_IMPORT N_CDECL(void, waku_pubsub_topic)(NCSTRING topicName, NimStringDesc** outPubsubTopic); +N_LIB_IMPORT N_CDECL(void, waku_default_pubsub_topic)(NimStringDesc** defPubsubTopic); +N_LIB_IMPORT N_CDECL(NIM_BOOL, waku_relay_publish)(NCSTRING pubSubTopic, NCSTRING jsonWakuMessage, NI timeoutMs, NimStringDesc** jsonResp); +N_LIB_IMPORT N_CDECL(void, waku_start)(void); +N_LIB_IMPORT N_CDECL(void, waku_stop)(void); +N_LIB_IMPORT N_CDECL(NIM_BOOL, waku_relay_subscribe)(NCSTRING pubSubTopic, NimStringDesc** jsonResp); +N_LIB_IMPORT N_CDECL(NIM_BOOL, waku_relay_unsubscribe)(NCSTRING pubSubTopic, NimStringDesc** jsonResp); +N_LIB_IMPORT N_CDECL(NIM_BOOL, waku_connect)(NCSTRING peerMultiAddr, NU timeoutMs, NimStringDesc** jsonResp); +N_LIB_IMPORT N_CDECL(void, waku_poll)(void); +N_LIB_IMPORT N_CDECL(void, NimMain)(void); +#endif /* __libwaku__ */ diff --git a/examples/golang/nimbase.h b/examples/golang/nimbase.h new file mode 100644 index 0000000000..a83bd30061 --- /dev/null +++ b/examples/golang/nimbase.h @@ -0,0 +1,602 @@ +/* + + Nim's Runtime Library + (c) Copyright 2015 Andreas Rumpf + + See the file "copying.txt", included in this + distribution, for details about the copyright. +*/ + +/* compiler symbols: +__BORLANDC__ +_MSC_VER +__WATCOMC__ +__LCC__ +__GNUC__ +__DMC__ +__POCC__ +__TINYC__ +__clang__ +__AVR__ +*/ + + +#ifndef NIMBASE_H +#define NIMBASE_H + +/*------------ declaring a custom attribute to support using LLVM's Address Sanitizer ------------ */ + +/* + This definition exists to provide support for using the LLVM ASAN (Address SANitizer) tooling with Nim. This + should only be used to mark implementations of the GC system that raise false flags with the ASAN tooling, or + for functions that are hot and need to be disabled for performance reasons. Based on the official ASAN + documentation, both the clang and gcc compilers are supported. In addition to that, a check is performed to + verify that the necessary attribute is supported by the compiler. + + To flag a proc as ignored, append the following code pragma to the proc declaration: + {.codegenDecl: "CLANG_NO_SANITIZE_ADDRESS $# $#$#".} + + For further information, please refer to the official documentation: + https://github.com/google/sanitizers/wiki/AddressSanitizer + */ +#define CLANG_NO_SANITIZE_ADDRESS +#if defined(__clang__) +# if __has_attribute(no_sanitize_address) +# undef CLANG_NO_SANITIZE_ADDRESS +# define CLANG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +# endif +#endif + + +/* ------------ ignore typical warnings in Nim-generated files ------------- */ +#if defined(__GNUC__) || defined(__clang__) +# pragma GCC diagnostic ignored "-Wpragmas" +# pragma GCC diagnostic ignored "-Wwritable-strings" +# pragma GCC diagnostic ignored "-Winvalid-noreturn" +# pragma GCC diagnostic ignored "-Wformat" +# pragma GCC diagnostic ignored "-Wlogical-not-parentheses" +# pragma GCC diagnostic ignored "-Wlogical-op-parentheses" +# pragma GCC diagnostic ignored "-Wshadow" +# pragma GCC diagnostic ignored "-Wunused-function" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +# pragma GCC diagnostic ignored "-Wtautological-compare" +# pragma GCC diagnostic ignored "-Wswitch-bool" +# pragma GCC diagnostic ignored "-Wmacro-redefined" +# pragma GCC diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" +# pragma GCC diagnostic ignored "-Wpointer-bool-conversion" +# pragma GCC diagnostic ignored "-Wconstant-conversion" +#endif + +#if defined(_MSC_VER) +# pragma warning(disable: 4005 4100 4101 4189 4191 4200 4244 4293 4296 4309) +# pragma warning(disable: 4310 4365 4456 4477 4514 4574 4611 4668 4702 4706) +# pragma warning(disable: 4710 4711 4774 4800 4809 4820 4996 4090 4297) +#endif +/* ------------------------------------------------------------------------- */ + +#if defined(__GNUC__) && !defined(__ZEPHYR__) +/* Zephyr does some magic in it's headers that override the GCC stdlib. This breaks that. */ +# define _GNU_SOURCE 1 +#endif + +#if defined(__TINYC__) +/*# define __GNUC__ 3 +# define GCC_MAJOR 4 +# define __GNUC_MINOR__ 4 +# define __GNUC_PATCHLEVEL__ 5 */ +# define __DECLSPEC_SUPPORTED 1 +#endif + +/* calling convention mess ----------------------------------------------- */ +#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \ + || defined(__TINYC__) + /* these should support C99's inline */ + /* the test for __POCC__ has to come before the test for _MSC_VER, + because PellesC defines _MSC_VER too. This is brain-dead. */ +# define N_INLINE(rettype, name) inline rettype name +#elif defined(__BORLANDC__) || defined(_MSC_VER) +/* Borland's compiler is really STRANGE here; note that the __fastcall + keyword cannot be before the return type, but __inline cannot be after + the return type, so we do not handle this mess in the code generator + but rather here. */ +# define N_INLINE(rettype, name) __inline rettype name +#elif defined(__DMC__) +# define N_INLINE(rettype, name) inline rettype name +#elif defined(__WATCOMC__) +# define N_INLINE(rettype, name) __inline rettype name +#else /* others are less picky: */ +# define N_INLINE(rettype, name) rettype __inline name +#endif + +#define N_INLINE_PTR(rettype, name) rettype (*name) + +#if defined(__POCC__) +# define NIM_CONST /* PCC is really picky with const modifiers */ +# undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is + not that compatible. Well done. */ +#elif defined(__cplusplus) +# define NIM_CONST /* C++ is picky with const modifiers */ +#else +# define NIM_CONST const +#endif + +/* + NIM_THREADVAR declaration based on + http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably +*/ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__ +# define NIM_THREADVAR _Thread_local +#elif defined _WIN32 && ( \ + defined _MSC_VER || \ + defined __ICL || \ + defined __DMC__ || \ + defined __BORLANDC__ ) +# define NIM_THREADVAR __declspec(thread) +#elif defined(__TINYC__) || defined(__GENODE__) +# define NIM_THREADVAR +/* note that ICC (linux) and Clang are covered by __GNUC__ */ +#elif defined __GNUC__ || \ + defined __SUNPRO_C || \ + defined __xlC__ +# define NIM_THREADVAR __thread +#else +# error "Cannot define NIM_THREADVAR" +#endif + +#if defined(__cplusplus) + #define NIM_THREAD_LOCAL thread_local +#endif + +/* --------------- how int64 constants should be declared: ----------- */ +#if defined(__GNUC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__DMC__) || defined(_MSC_VER) +# define IL64(x) x##LL +#else /* works only without LL */ +# define IL64(x) ((NI64)x) +#endif + +/* ---------------- casting without correct aliasing rules ----------- */ + +#if defined(__GNUC__) +# define NIM_CAST(type, ptr) (((union{type __x__;}*)(ptr))->__x__) +#else +# define NIM_CAST(type, ptr) ((type)(ptr)) +#endif + + +/* ------------------------------------------------------------------- */ +#ifdef __cplusplus +# define NIM_EXTERNC extern "C" +#else +# define NIM_EXTERNC +#endif + +#if defined(WIN32) || defined(_WIN32) /* only Windows has this mess... */ +# define N_LIB_PRIVATE +# define N_CDECL(rettype, name) rettype __cdecl name +# define N_STDCALL(rettype, name) rettype __stdcall name +# define N_SYSCALL(rettype, name) rettype __syscall name +# define N_FASTCALL(rettype, name) rettype __fastcall name +# define N_THISCALL(rettype, name) rettype __thiscall name +# define N_SAFECALL(rettype, name) rettype __stdcall name +/* function pointers with calling convention: */ +# define N_CDECL_PTR(rettype, name) rettype (__cdecl *name) +# define N_STDCALL_PTR(rettype, name) rettype (__stdcall *name) +# define N_SYSCALL_PTR(rettype, name) rettype (__syscall *name) +# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name) +# define N_THISCALL_PTR(rettype, name) rettype (__thiscall *name) +# define N_SAFECALL_PTR(rettype, name) rettype (__stdcall *name) + +# ifdef __cplusplus +# define N_LIB_EXPORT NIM_EXTERNC __declspec(dllexport) +# else +# define N_LIB_EXPORT NIM_EXTERNC __declspec(dllexport) +# endif +# define N_LIB_EXPORT_VAR __declspec(dllexport) +# define N_LIB_IMPORT extern __declspec(dllimport) +#else +# define N_LIB_PRIVATE __attribute__((visibility("hidden"))) +# if defined(__GNUC__) +# define N_CDECL(rettype, name) rettype name +# define N_STDCALL(rettype, name) rettype name +# define N_SYSCALL(rettype, name) rettype name +# define N_FASTCALL(rettype, name) __attribute__((fastcall)) rettype name +# define N_SAFECALL(rettype, name) rettype name +/* function pointers with calling convention: */ +# define N_CDECL_PTR(rettype, name) rettype (*name) +# define N_STDCALL_PTR(rettype, name) rettype (*name) +# define N_SYSCALL_PTR(rettype, name) rettype (*name) +# define N_FASTCALL_PTR(rettype, name) __attribute__((fastcall)) rettype (*name) +# define N_SAFECALL_PTR(rettype, name) rettype (*name) +# else +# define N_CDECL(rettype, name) rettype name +# define N_STDCALL(rettype, name) rettype name +# define N_SYSCALL(rettype, name) rettype name +# define N_FASTCALL(rettype, name) rettype name +# define N_SAFECALL(rettype, name) rettype name +/* function pointers with calling convention: */ +# define N_CDECL_PTR(rettype, name) rettype (*name) +# define N_STDCALL_PTR(rettype, name) rettype (*name) +# define N_SYSCALL_PTR(rettype, name) rettype (*name) +# define N_FASTCALL_PTR(rettype, name) rettype (*name) +# define N_SAFECALL_PTR(rettype, name) rettype (*name) +# endif +# define N_LIB_EXPORT NIM_EXTERNC __attribute__((visibility("default"))) +# define N_LIB_EXPORT_VAR __attribute__((visibility("default"))) +# define N_LIB_IMPORT extern +#endif + +#define N_NOCONV(rettype, name) rettype name +/* specify no calling convention */ +#define N_NOCONV_PTR(rettype, name) rettype (*name) + +#if defined(__GNUC__) || defined(__ICC__) +# define N_NOINLINE(rettype, name) rettype __attribute__((__noinline__)) name +#elif defined(_MSC_VER) +# define N_NOINLINE(rettype, name) __declspec(noinline) rettype name +#else +# define N_NOINLINE(rettype, name) rettype name +#endif + +#define N_NOINLINE_PTR(rettype, name) rettype (*name) + +#if defined(__BORLANDC__) || defined(__WATCOMC__) || \ + defined(__POCC__) || defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) +/* these compilers have a fastcall so use it: */ +# ifdef __TINYC__ +# define N_NIMCALL(rettype, name) rettype __attribute((__fastcall)) name +# define N_NIMCALL_PTR(rettype, name) rettype (__attribute((__fastcall)) *name) +# define N_RAW_NIMCALL __attribute((__fastcall)) +# else +# define N_NIMCALL(rettype, name) rettype __fastcall name +# define N_NIMCALL_PTR(rettype, name) rettype (__fastcall *name) +# define N_RAW_NIMCALL __fastcall +# endif +#else +# define N_NIMCALL(rettype, name) rettype name /* no modifier */ +# define N_NIMCALL_PTR(rettype, name) rettype (*name) +# define N_RAW_NIMCALL +#endif + +#define N_CLOSURE(rettype, name) N_NIMCALL(rettype, name) +#define N_CLOSURE_PTR(rettype, name) N_NIMCALL_PTR(rettype, name) + +/* ----------------------------------------------------------------------- */ + +#define COMMA , + +#include <limits.h> +#include <stddef.h> + +// define NIM_STATIC_ASSERT +// example use case: CT sizeof for importc types verification +// where we have {.completeStruct.} (or lack of {.incompleteStruct.}) +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) +#define NIM_STATIC_ASSERT(x, msg) _Static_assert((x), msg) +#elif defined(__cplusplus) +#define NIM_STATIC_ASSERT(x, msg) static_assert((x), msg) +#else +#define NIM_STATIC_ASSERT(x, msg) typedef int NIM_STATIC_ASSERT_AUX[(x) ? 1 : -1]; +// On failure, your C compiler will say something like: +// "error: 'NIM_STATIC_ASSERT_AUX' declared as an array with a negative size" +// we could use a better fallback to also show line number, using: +// http://www.pixelbeat.org/programming/gcc/static_assert.html +#endif + +/* C99 compiler? */ +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) +# define HAVE_STDINT_H +#endif + +/* Known compiler with stdint.h that doesn't fit the general pattern? */ +#if defined(__LCC__) || defined(__DMC__) || defined(__POCC__) || \ + defined(__AVR__) || (defined(__cplusplus) && (__cplusplus < 201103)) +# define HAVE_STDINT_H +#endif + +#if (!defined(HAVE_STDINT_H) && defined(__cplusplus) && (__cplusplus >= 201103)) +# define HAVE_CSTDINT +#endif + + +/* wrap all Nim typedefs into namespace Nim */ +#ifdef USE_NIM_NAMESPACE +#ifdef HAVE_CSTDINT +#include <cstdint> +#else +#include <stdint.h> +#endif +namespace USE_NIM_NAMESPACE { +#endif + +// preexisting check, seems paranoid, maybe remove +#if defined(NIM_TRUE) || defined(NIM_FALSE) || defined(NIM_BOOL) +#error "nim reserved preprocessor macros clash" +#endif + +/* bool types (C++ has it): */ +#ifdef __cplusplus +#define NIM_BOOL bool +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>` +#define NIM_BOOL _Bool +#else +typedef unsigned char NIM_BOOL; // best effort +#endif + +NIM_STATIC_ASSERT(sizeof(NIM_BOOL) == 1, ""); // check whether really needed +NIM_STATIC_ASSERT(CHAR_BIT == 8, ""); + // fail fast for (rare) environments where this doesn't hold, as some implicit + // assumptions would need revisiting (e.g. `uint8` or https://github.com/nim-lang/Nim/pull/18505) + +#define NIM_TRUE true +#define NIM_FALSE false + +#ifdef __cplusplus +# if __cplusplus >= 201103L +# /* nullptr is more type safe (less implicit conversions than 0) */ +# define NIM_NIL nullptr +# else +# // both `((void*)0)` and `NULL` would cause codegen to emit +# // error: assigning to 'Foo *' from incompatible type 'void *' +# // but codegen could be fixed if need. See also potential caveat regarding +# // NULL. +# // However, `0` causes other issues, see #13798 +# define NIM_NIL 0 +# endif +#else +# include <stdbool.h> +# define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so + the generated code does not rely on it anymore */ +#endif + +#if defined(__BORLANDC__) || defined(__DMC__) \ + || defined(__WATCOMC__) || defined(_MSC_VER) +typedef signed char NI8; +typedef signed short int NI16; +typedef signed int NI32; +typedef __int64 NI64; +/* XXX: Float128? */ +typedef unsigned char NU8; +typedef unsigned short int NU16; +typedef unsigned int NU32; +typedef unsigned __int64 NU64; +#elif defined(HAVE_STDINT_H) +#ifndef USE_NIM_NAMESPACE +# include <stdint.h> +#endif +typedef int8_t NI8; +typedef int16_t NI16; +typedef int32_t NI32; +typedef int64_t NI64; +typedef uint8_t NU8; +typedef uint16_t NU16; +typedef uint32_t NU32; +typedef uint64_t NU64; +#elif defined(HAVE_CSTDINT) +#ifndef USE_NIM_NAMESPACE +# include <cstdint> +#endif +typedef std::int8_t NI8; +typedef std::int16_t NI16; +typedef std::int32_t NI32; +typedef std::int64_t NI64; +typedef std::uint8_t NU8; +typedef std::uint16_t NU16; +typedef std::uint32_t NU32; +typedef std::uint64_t NU64; +#else +/* Unknown compiler/version, do our best */ +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ NI8; +#else +typedef signed char NI8; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ NI16; +#else +typedef signed short int NI16; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ NI32; +#else +typedef signed int NI32; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ NI64; +#else +typedef long long int NI64; +#endif +/* XXX: Float128? */ +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ NU8; +#else +typedef unsigned char NU8; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ NU16; +#else +typedef unsigned short int NU16; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ NU32; +#else +typedef unsigned int NU32; +#endif +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ NU64; +#else +typedef unsigned long long int NU64; +#endif +#endif + +#ifdef NIM_INTBITS +# if NIM_INTBITS == 64 +typedef NI64 NI; +typedef NU64 NU; +# elif NIM_INTBITS == 32 +typedef NI32 NI; +typedef NU32 NU; +# elif NIM_INTBITS == 16 +typedef NI16 NI; +typedef NU16 NU; +# elif NIM_INTBITS == 8 +typedef NI8 NI; +typedef NU8 NU; +# else +# error "invalid bit width for int" +# endif +#endif + +// for now there isn't an easy way for C code to reach the program result +// when hot code reloading is ON - users will have to: +// load the nimhcr.dll, get the hcrGetGlobal proc from there and use it +#ifndef NIM_HOT_CODE_RELOADING +extern NI nim_program_result; +#endif + +typedef float NF32; +typedef double NF64; +typedef double NF; + +typedef char NIM_CHAR; +typedef char* NCSTRING; + +#ifdef NIM_BIG_ENDIAN +# define NIM_IMAN 1 +#else +# define NIM_IMAN 0 +#endif + +#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */ + +#define STRING_LITERAL(name, str, length) \ + static const struct { \ + TGenericSeq Sup; \ + NIM_CHAR data[(length) + 1]; \ + } name = {{length, (NI) ((NU)length | NIM_STRLIT_FLAG)}, str} + +/* declared size of a sequence/variable length array: */ +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) +# define SEQ_DECL_SIZE /* empty is correct! */ +#else +# define SEQ_DECL_SIZE 1000000 +#endif + +#define ALLOC_0(size) calloc(1, size) +#define DL_ALLOC_0(size) dlcalloc(1, size) + +#define paramCount() cmdCount + +// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0 +#ifndef NAN +# ifndef _HUGE_ENUF +# define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow +# endif +# define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF)) +# define NAN ((float)(NAN_INFINITY * 0.0F)) +#endif + +#ifndef INF +# ifdef INFINITY +# define INF INFINITY +# elif defined(HUGE_VAL) +# define INF HUGE_VAL +# elif defined(_MSC_VER) +# include <float.h> +# define INF (DBL_MAX+DBL_MAX) +# else +# define INF (1.0 / 0.0) +# endif +#endif + +typedef struct TFrame_ TFrame; +struct TFrame_ { + TFrame* prev; + NCSTRING procname; + NI line; + NCSTRING filename; + NI16 len; + NI16 calldepth; + NI frameMsgLen; +}; + +#define NIM_POSIX_INIT __attribute__((constructor)) + +#ifdef __GNUC__ +# define NIM_LIKELY(x) __builtin_expect(x, 1) +# define NIM_UNLIKELY(x) __builtin_expect(x, 0) +/* We need the following for the posix wrapper. In particular it will give us + POSIX_SPAWN_USEVFORK: */ +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +#else +# define NIM_LIKELY(x) (x) +# define NIM_UNLIKELY(x) (x) +#endif + +#if 0 // defined(__GNUC__) || defined(__clang__) +// not needed anymore because the stack marking cares about +// interior pointers now +static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } +# define GC_GUARD __attribute__ ((cleanup(GCGuard))) +#else +# define GC_GUARD +#endif + +// Test to see if Nim and the C compiler agree on the size of a pointer. +NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, ""); + +#ifdef USE_NIM_NAMESPACE +} +#endif + +#if defined(_MSC_VER) +# define NIM_ALIGN(x) __declspec(align(x)) +# define NIM_ALIGNOF(x) __alignof(x) +#else +# define NIM_ALIGN(x) __attribute__((aligned(x))) +# define NIM_ALIGNOF(x) __alignof__(x) +#endif + +/* ---------------- platform specific includes ----------------------- */ + +/* VxWorks related includes */ +#if defined(__VXWORKS__) +# include <sys/types.h> +# include <types/vxWind.h> +# include <tool/gnu/toolMacros.h> +#elif defined(__FreeBSD__) +# include <sys/types.h> +#endif + +/* these exist to make the codegen logic simpler */ +#define nimModInt(a, b, res) (((*res) = (a) % (b)), 0) +#define nimModInt64(a, b, res) (((*res) = (a) % (b)), 0) + +#if (!defined(_MSC_VER) || defined(__clang__)) && !defined(NIM_EmulateOverflowChecks) + /* these exist because we cannot have .compilerProcs that are importc'ed + by a different name */ + + #define nimAddInt64(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) + #define nimSubInt64(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) + #define nimMulInt64(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + + #if NIM_INTBITS == 32 + #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res) + #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res) + #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res) + #else + /* map it to the 'long long' variant */ + #define nimAddInt(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res) + #define nimSubInt(a, b, res) __builtin_ssubll_overflow(a, b, (long long int*)res) + #define nimMulInt(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res) + #endif +#endif + +#define NIM_NOALIAS __restrict +/* __restrict is said to work for all the C(++) compilers out there that we support */ + +#endif /* NIMBASE_H */ diff --git a/examples/golang/waku.go b/examples/golang/waku.go new file mode 100644 index 0000000000..2daba3b8bd --- /dev/null +++ b/examples/golang/waku.go @@ -0,0 +1,89 @@ +package main + +/* + #cgo LDFLAGS: -L./ -lwaku -Wl,--allow-multiple-definition + + #include "libwaku.h" + + static NimStringDesc wakuString; + NimStringDesc* mResp = &wakuString; + + char* data(NimStringDesc* a) { + return a->data; + } + + extern void eventHandler(char* msg); + + void cGoEventHandler(char* msg) { + eventHandler(msg); + } + + void setCallback() { + waku_set_event_callback(cGoEventHandler); + } + + struct ConfigNode { + NCSTRING host; + NU port; + NCSTRING key; + NIM_BOOL relay; + NCSTRING peers; + }; +*/ +import "C" + +import ( + "os" + "fmt" + "runtime" +) + +//export eventHandler +func eventHandler(msg *C.char) { + fmt.Println("Event received: ", C.GoString(msg)) +} + +func main() { + runtime.LockOSThread() + + C.NimMain() + + cfgNode := C.ConfigNode{} + + cfgNode.host = C.CString("0.0.0.0") + cfgNode.port = 60000 + cfgNode.key = C.CString("364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9") + cfgNode.relay = true + cfgNode.peers = nil + + fmt.Println("Git Version: ", C.GoString( C.waku_version() )) + C.waku_default_pubsub_topic(&C.mResp); + defaultPubsubTopic := C.data( C.mResp ) + + fmt.Println("Default pubsub topic: ", C.GoString( defaultPubsubTopic ) ) + fmt.Println("Bind addr: ", C.GoString(cfgNode.host), ":", cfgNode.port) + + if cfgNode.relay { + fmt.Println("Waku Relay enabled") + } else { + fmt.Println("Waku Relay disabled") + } + + if ! C.waku_new(&cfgNode, &C.mResp) { + fmt.Println("Error creating WakuNode: ", C.GoString(C.data(C.mResp))); + os.Exit(-1) + } + + C.setCallback() + C.waku_start() + + if ! C.waku_relay_subscribe(defaultPubsubTopic, &C.mResp) { + fmt.Println("Error subscribing to PubsubTopic: ", + C.GoString(C.data(C.mResp))); + os.Exit(-1) + } + + for { + C.waku_poll() + } +} From f7e7b0b4d5a5138eb2a7067bbe6ff1ae9cec8cbf Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande <ivansete@status.im> Date: Mon, 12 Jun 2023 15:47:32 +0200 Subject: [PATCH 2/4] libwaku.nim: adapting code to latest changes made in 34a926319 --- library/libwaku.nim | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/library/libwaku.nim b/library/libwaku.nim index 995d7f7a37..a608de0dd7 100644 --- a/library/libwaku.nim +++ b/library/libwaku.nim @@ -47,16 +47,12 @@ type var eventCallback:EventCallback = nil -proc relayEventCallback(pubsubTopic: string, data: seq[byte]): Future[void] {.gcsafe, raises: [Defect].} = +proc relayEventCallback(pubsubTopic: string, + msg: WakuMessage): + Future[void] {.gcsafe, raises: [Defect].} = # Callback that hadles the Waku Relay events. i.e. messages or errors. if not isNil(eventCallback): - let msg = WakuMessage.decode(data) - var event: JsonSignal - if msg.isOk(): - event = JsonMessageEvent.new(pubsubTopic, msg.value) - else: - let errorMsg = string("Error decoding message.") & $msg.error - event = JsonErrorEvent.new(errorMsg) + let event = JsonMessageEvent.new(pubsubTopic, msg) try: eventCallback(cstring($event)) @@ -303,7 +299,8 @@ Kindly set it with the 'waku_set_event_callback' function""") jsonResp = errResp("Cannot subscribe without Waku Relay enabled.") return false - node.wakuRelay.subscribe(PubsubTopic($pubSubTopic), PubsubRawHandler(relayEventCallback)) + node.wakuRelay.subscribe(PubsubTopic($pubSubTopic), + WakuRelayHandler(relayEventCallback)) jsonResp = okResp("true") return true @@ -323,7 +320,7 @@ Kindly set it with the 'waku_set_event_callback' function""") jsonResp = errResp("Cannot unsubscribe without Waku Relay enabled.") return false - node.wakuRelay.unsubscribeAll(PubsubTopic($pubSubTopic)) + node.wakuRelay.unsubscribe(PubsubTopic($pubSubTopic)) jsonResp = okResp("true") return true From 256ffeb5315de6b786a6b963daeed0efa064f6d9 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande <ivansete@status.im> Date: Mon, 12 Jun 2023 18:42:40 +0200 Subject: [PATCH 3/4] Makefile: copying libwaku.so to 'examples/golang' when it is built --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 131718d245..806b0e2697 100644 --- a/Makefile +++ b/Makefile @@ -298,6 +298,7 @@ else echo -e $(BUILD_MSG) "build/$@.so" && \ $(ENV_SCRIPT) nim libwakuDynamic $(NIM_PARAMS) $(EXPERIMENTAL_PARAMS) waku.nims endif + cp build/libwaku.so examples/golang/ cwaku_example: | build libwaku echo -e $(BUILD_MSG) "build/$@" && \ From 7d1a8715f4f28374d88f59f1653a32d265b06f09 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande <ivansete@status.im> Date: Mon, 12 Jun 2023 18:51:13 +0200 Subject: [PATCH 4/4] Adding waku.go and README.md to give better insight on how to handle the go example. --- examples/golang/README.md | 59 +++++++++++++++++++++++++++++++++++++++ examples/golang/waku.go | 31 ++++++++++++++++---- 2 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 examples/golang/README.md diff --git a/examples/golang/README.md b/examples/golang/README.md new file mode 100644 index 0000000000..d143659ce4 --- /dev/null +++ b/examples/golang/README.md @@ -0,0 +1,59 @@ + +## Summary + +This is a simple example on how to integrate the `libwaku.so` library in a +Golang app. + +[cgo](https://pkg.go.dev/cmd/cgo) is used in this example. + +There are comments in the file `waku.go` that are considered by the cgo itself and +shouldn't be arbitrarily changed unless required. + +The important comments in the `waku.go` are the ones above the `import "C"` statement and +above the `eventHandler` function. + +## libwaku.so + +Before running the example, make sure to properly export the LD_LIBRARY_PATH +with the path that contains the target `libwaku.so` library. + +e.g. +From the repo's root folder: +```code +export LD_LIBRARY_PATH=build +``` + +In order to build the `libwaku.so`, go to the repo's root folder and +invoke the next command, which will create `libwaku.so` under the `build` folder: + +```code +make libwaku +``` +This will both generate the `libwaku.so` file under the `build` and +the `examples/golang/` fodler. +It is important to notice that there should be a `libwaku.so` at the same level as the `waku.go` file as per how `waku.go` is implemented. + +## libwaku.h & nimbase.h + +This is the header associated with the `libwaku.so`. + +The `libwaku.h` is auto-generated when building the `libwaku.so`. + +Everytime a new `libwaku.so` is built, the `libwaku.h` file gets stored in +<REPO_ROOT_DIR>/nimcache/release/libwaku/libwaku.h. + +However, the `libwaku.h` is kept version-controlled just for commodity. +It might be needed to update the `libwaku.h` header if a new function +is added to the `libwaku.so` or any signature is modified. + +## Running the example + +- Open a terminal +- cd <...>/nwaku/ +- ```code + export LD_LIBRARY_PATH=build + ``` +- ```code + go run examples/golang/waku.go + ``` + note: `--help` can be appended to the end of the previous command to get better insight of possible params diff --git a/examples/golang/waku.go b/examples/golang/waku.go index 2daba3b8bd..f6f118f075 100644 --- a/examples/golang/waku.go +++ b/examples/golang/waku.go @@ -36,6 +36,7 @@ import ( "os" "fmt" "runtime" + "flag" ) //export eventHandler @@ -46,15 +47,33 @@ func eventHandler(msg *C.char) { func main() { runtime.LockOSThread() + // Setup the nim runtime and GC. C.NimMain() - cfgNode := C.ConfigNode{} + var host string + var port int + var key string + var relay int + + flag.StringVar(&host, "host", "0.0.0.0", "Node's host.") + flag.IntVar(&port, "port", 60000, "Node's port.") + flag.StringVar(&key, "key", "", + `P2P node private key as 64 char hex string. +e.g.: 364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9`) + flag.IntVar(&relay, "relay", 1, "1 -> Enable Relay protocol. 0 -> disable.") + flag.Parse() + + if key == "" { + fmt.Println("Please set a valid P2P private node key.") + fmt.Println("Run with --help to get a better insight.") + os.Exit(1) + } - cfgNode.host = C.CString("0.0.0.0") - cfgNode.port = 60000 - cfgNode.key = C.CString("364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9") - cfgNode.relay = true - cfgNode.peers = nil + cfgNode := C.ConfigNode{} + cfgNode.host = C.CString(host) + cfgNode.port = C.ulong(port) + cfgNode.key = C.CString(key) + cfgNode.relay = relay == 1 fmt.Println("Git Version: ", C.GoString( C.waku_version() )) C.waku_default_pubsub_topic(&C.mResp);