First commit

This commit is contained in:
Ivan Folgueira Bande 2025-10-16 13:38:59 +02:00
commit 27de79bda4
No known key found for this signature in database
GPG Key ID: 3C117481F89E24A7
10 changed files with 463 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

3
CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 1.0.0
- Initial version.

2
README.md Normal file
View File

@ -0,0 +1,2 @@
Waku wrapper for Dart projects :)

6
ffigen.yaml Normal file
View File

@ -0,0 +1,6 @@
name: WakuBindings
description: Bindings to Waku C API
output: lib/src/waku_ffi.dart
headers:
entry-points:
- native/libwaku.h

51
lib/bindings.dart Normal file
View File

@ -0,0 +1,51 @@
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
class CallbackResult {
late int callerRet;
late String msg;
}
/// Callback typedef
typedef WakuCallBackC = Void Function(
Int32 callerRet, Pointer<Utf8> msg, IntPtr len, Pointer<Void> userData);
typedef WakuCallBackDart = void Function(
int callerRet, Pointer<Utf8> msg, int len, Pointer<Void> userData);
/// waku_new typedefs
typedef WakuNewC = Pointer<Void> Function(Pointer<Utf8> configJson,
Pointer<NativeFunction<WakuCallBackC>> callback, Pointer<Void> userData);
typedef WakuNewDart = Pointer<Void> Function(Pointer<Utf8> configJson,
Pointer<NativeFunction<WakuCallBackC>> callback, Pointer<Void> userData);
/// no params functions typedefs
typedef WakuNoParamsC = Pointer<Void> Function(Pointer<Void> ctx,
Pointer<NativeFunction<WakuCallBackC>> callback, Pointer<Void> userData);
typedef WakuNoParamsDart = Pointer<Void> Function(Pointer<Void> ctx,
Pointer<NativeFunction<WakuCallBackC>> callback, Pointer<Void> userData);
/// Load the shared library
final DynamicLibrary wakuLib = DynamicLibrary.open(
Platform.isMacOS
? 'libwaku.dylib'
: Platform.isLinux
? 'libwaku.so'
: 'waku.dll',
);
/// Lookup functions
final WakuNewDart waku_new =
wakuLib.lookupFunction<WakuNewC, WakuNewDart>('waku_new');
final WakuNoParamsDart waku_destroy =
wakuLib.lookupFunction<WakuNoParamsC, WakuNoParamsDart>('waku_destroy');
final WakuNoParamsDart waku_start =
wakuLib.lookupFunction<WakuNoParamsC, WakuNoParamsDart>('waku_start');
final WakuNoParamsDart waku_stop =
wakuLib.lookupFunction<WakuNoParamsC, WakuNoParamsDart>('waku_stop');

102
lib/waku.dart Normal file
View File

@ -0,0 +1,102 @@
import 'dart:async';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'bindings.dart';
class Waku {
final Pointer<Void> _context;
Waku._(this._context);
static Future<Waku> newInstance(String configJson) async {
late final NativeCallable<WakuCallBackC> callback;
final completer = Completer<CallbackResult>();
void onCallCompleted(
int callerRet, Pointer<Utf8> msg, int len, Pointer<Void> userData) {
print("instance is created callback");
completer.complete(CallbackResult()
..callerRet = callerRet
..msg = msg.toDartString(length: len));
callback.close();
}
callback = NativeCallable<WakuCallBackC>.listener(onCallCompleted);
final configPtr = configJson.toNativeUtf8();
final context = waku_new(configPtr, callback.nativeFunction, nullptr);
final callResult = await completer.future;
malloc.free(configPtr);
final wakuCompleter = Completer<Waku>();
if (callResult.callerRet != 0) {
print("Could not create instance");
wakuCompleter
.completeError('Failed to create Waku instance: ${callResult.msg}');
} else {
wakuCompleter.complete(Waku._(context));
}
return wakuCompleter.future;
}
Future<CallbackResult> destroyInstance() async {
late final NativeCallable<WakuCallBackC> callback;
final completer = Completer<CallbackResult>();
void onCallCompleted(
int callerRet, Pointer<Utf8> msg, int len, Pointer<Void> userData) {
completer.complete(CallbackResult()
..callerRet = callerRet
..msg = msg.toDartString(length: len));
callback.close();
}
callback = NativeCallable<WakuCallBackC>.listener(onCallCompleted);
waku_destroy(_context, callback.nativeFunction, nullptr);
return completer.future;
}
Future<CallbackResult> start() async {
late final NativeCallable<WakuCallBackC> callback;
final completer = Completer<CallbackResult>();
void onCallCompleted(
int callerRet, Pointer<Utf8> msg, int len, Pointer<Void> userData) {
completer.complete(CallbackResult()
..callerRet = callerRet
..msg = msg.toDartString(length: len));
callback.close();
}
callback = NativeCallable<WakuCallBackC>.listener(onCallCompleted);
waku_start(_context, callback.nativeFunction, nullptr);
return completer.future;
}
Future<CallbackResult> stop() async {
late final NativeCallable<WakuCallBackC> callback;
final completer = Completer<CallbackResult>();
void onCallCompleted(
int callerRet, Pointer<Utf8> msg, int len, Pointer<Void> userData) {
completer.complete(CallbackResult()
..callerRet = callerRet
..msg = msg.toDartString(length: len));
callback.close();
}
callback = NativeCallable<WakuCallBackC>.listener(onCallCompleted);
waku_stop(_context, callback.nativeFunction, nullptr);
return completer.future;
}
}

251
native/libwaku.h Normal file
View File

@ -0,0 +1,251 @@
// Generated manually and inspired by the one generated by the Nim Compiler.
// In order to see the header file generated by Nim just run `make libwaku`
// from the root repo folder and the header should be created in
// nimcache/release/libwaku/libwaku.h
#ifndef __libwaku__
#define __libwaku__
#include <stddef.h>
#include <stdint.h>
// The possible returned values for the functions that return int
#define RET_OK 0
#define RET_ERR 1
#define RET_MISSING_CALLBACK 2
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*WakuCallBack) (int callerRet, const char* msg, size_t len, void* userData);
// Creates a new instance of the waku node.
// Sets up the waku node from the given configuration.
// Returns a pointer to the Context needed by the rest of the API functions.
void* waku_new(
const char* configJson,
WakuCallBack callback,
void* userData);
int waku_start(void* ctx,
WakuCallBack callback,
void* userData);
int waku_stop(void* ctx,
WakuCallBack callback,
void* userData);
// Destroys an instance of a waku node created with waku_new
int waku_destroy(void* ctx,
WakuCallBack callback,
void* userData);
int waku_version(void* ctx,
WakuCallBack callback,
void* userData);
void waku_set_event_callback(void* ctx,
WakuCallBack callback,
void* userData);
int waku_content_topic(void* ctx,
const char* appName,
unsigned int appVersion,
const char* contentTopicName,
const char* encoding,
WakuCallBack callback,
void* userData);
int waku_pubsub_topic(void* ctx,
const char* topicName,
WakuCallBack callback,
void* userData);
int waku_default_pubsub_topic(void* ctx,
WakuCallBack callback,
void* userData);
int waku_relay_publish(void* ctx,
const char* pubSubTopic,
const char* jsonWakuMessage,
unsigned int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_lightpush_publish(void* ctx,
const char* pubSubTopic,
const char* jsonWakuMessage,
WakuCallBack callback,
void* userData);
int waku_relay_subscribe(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_relay_add_protected_shard(void* ctx,
int clusterId,
int shardId,
char* publicKey,
WakuCallBack callback,
void* userData);
int waku_relay_unsubscribe(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_filter_subscribe(void* ctx,
const char* pubSubTopic,
const char* contentTopics,
WakuCallBack callback,
void* userData);
int waku_filter_unsubscribe(void* ctx,
const char* pubSubTopic,
const char* contentTopics,
WakuCallBack callback,
void* userData);
int waku_filter_unsubscribe_all(void* ctx,
WakuCallBack callback,
void* userData);
int waku_relay_get_num_connected_peers(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_relay_get_connected_peers(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_relay_get_num_peers_in_mesh(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_relay_get_peers_in_mesh(void* ctx,
const char* pubSubTopic,
WakuCallBack callback,
void* userData);
int waku_store_query(void* ctx,
const char* jsonQuery,
const char* peerAddr,
int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_connect(void* ctx,
const char* peerMultiAddr,
unsigned int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_disconnect_peer_by_id(void* ctx,
const char* peerId,
WakuCallBack callback,
void* userData);
int waku_disconnect_all_peers(void* ctx,
WakuCallBack callback,
void* userData);
int waku_dial_peer(void* ctx,
const char* peerMultiAddr,
const char* protocol,
int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_dial_peer_by_id(void* ctx,
const char* peerId,
const char* protocol,
int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_get_peerids_from_peerstore(void* ctx,
WakuCallBack callback,
void* userData);
int waku_get_connected_peers_info(void* ctx,
WakuCallBack callback,
void* userData);
int waku_get_peerids_by_protocol(void* ctx,
const char* protocol,
WakuCallBack callback,
void* userData);
int waku_listen_addresses(void* ctx,
WakuCallBack callback,
void* userData);
int waku_get_connected_peers(void* ctx,
WakuCallBack callback,
void* userData);
// Returns a list of multiaddress given a url to a DNS discoverable ENR tree
// Parameters
// char* entTreeUrl: URL containing a discoverable ENR tree
// char* nameDnsServer: The nameserver to resolve the ENR tree url.
// int timeoutMs: Timeout value in milliseconds to execute the call.
int waku_dns_discovery(void* ctx,
const char* entTreeUrl,
const char* nameDnsServer,
int timeoutMs,
WakuCallBack callback,
void* userData);
// Updates the bootnode list used for discovering new peers via DiscoveryV5
// bootnodes - JSON array containing the bootnode ENRs i.e. `["enr:...", "enr:..."]`
int waku_discv5_update_bootnodes(void* ctx,
char* bootnodes,
WakuCallBack callback,
void* userData);
int waku_start_discv5(void* ctx,
WakuCallBack callback,
void* userData);
int waku_stop_discv5(void* ctx,
WakuCallBack callback,
void* userData);
// Retrieves the ENR information
int waku_get_my_enr(void* ctx,
WakuCallBack callback,
void* userData);
int waku_get_my_peerid(void* ctx,
WakuCallBack callback,
void* userData);
int waku_get_metrics(void* ctx,
WakuCallBack callback,
void* userData);
int waku_peer_exchange_request(void* ctx,
int numPeers,
WakuCallBack callback,
void* userData);
int waku_ping_peer(void* ctx,
const char* peerAddr,
int timeoutMs,
WakuCallBack callback,
void* userData);
int waku_is_online(void* ctx,
WakuCallBack callback,
void* userData);
#ifdef __cplusplus
}
#endif
#endif /* __libwaku__ */

BIN
native/libwaku.so Executable file

Binary file not shown.

14
pubspec.yaml Normal file
View File

@ -0,0 +1,14 @@
name: waku_dart_bindings
description: Dart bindings for Waku C API
version: 1.0.0
environment:
sdk: ">3.4.0 <4.0.0"
dependencies:
ffi: ^2.1.0
dev_dependencies:
ffigen: ^19.1.0
lints: ^6.0.0
test: ^1.26.0

27
test/waku_test.dart Normal file
View File

@ -0,0 +1,27 @@
import 'package:test/test.dart';
import 'package:waku_dart_bindings/waku.dart'; // Your high-level wrapper
void main() {
group('Waku FFI Tests', () {
Waku? wakuInstance;
setUp(() async {
// Create a new Waku instance before each test
wakuInstance = await Waku.newInstance(
'{ "clusterId": 16, "shards": [ 1, 32, 64, 128, 256 ], "numShardsInNetwork": 257 }');
});
tearDown(() {
// Optionally: clean up resources if your API exposes a free function
// e.g., waku_free(wakuInstance?.context);
wakuInstance?.destroyInstance();
});
test('Start and stop waku instance', () async {
final startResult = await wakuInstance!.start();
expect(startResult.callerRet, 0);
final stopResult = await wakuInstance!.stop();
expect(stopResult.callerRet, 0);
});
});
}