mirror of
https://github.com/logos-messaging/logos-messaging-go-bindings.git
synced 2026-07-21 18:20:04 +00:00
* refactor: build against the single liblogosdelivery library logos-delivery#4012 unifies the node lifecycle on logosdelivery_* and ships the full API — Messaging, Reliable Channels, and the low-level Kernel (waku_*) tier — in one liblogosdelivery library, retiring the separate libwaku. Migrate the bindings onto it. - internal/ffi: collapse the two bridges into one internal/ffi/liblogosdelivery over the single library. The kernel wrappers keep calling waku_* (kernel header), the lifecycle now uses logosdelivery_create_node/start_node/ stop_node/destroy (waku_new/start/stop/destroy are gone), events use logosdelivery_set_event_callback. Include liblogosdelivery_kernel.h (which re-exports the stable header) and link -llogosdelivery. Remove internal/ffi/libwaku. - pkg/kernel: repoint at internal/ffi/liblogosdelivery; the Makefile links -llogosdelivery. - CI: build only `make liblogosdelivery`, headers from library/, single -llogosdelivery. Pinned to logos-delivery#4012 until it merges (see the TODO/LOGOS_DELIVERY_REF in pr.yml). The high-level MessagingClient (pkg/messaging) lands in a follow-up PR on top. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(kernel): drop removed config keys + add a runnable example Running against the single liblogosdelivery library surfaced a config drift: the consolidated WakuNodeConf strictly rejects unknown keys, and common.WakuConfig still emitted `legacyStore` (removed upstream, and sent unconditionally) and `host` (renamed to `listenAddress`). That failed node creation, so every kernel test that starts a node failed. Reconcile the config: - drop the LegacyStore field (and its two obsolete test references; the already-skipped TestCheckLegacyStore keeps compiling); - map Host to the `listenAddress` JSON key. Add examples/kernel: a small runnable check that drives the unified lifecycle (logosdelivery_create_node/start/stop/destroy) and a few kernel ops (version, listen addresses, is-online, relay subscribe/unsubscribe) over the single library. `go run ./examples/kernel` prints OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(kernel): correct RelayPublish wire format; verify send/receive RelayPublish marshalled the generated protobuf (content_topic), but the library requires the WakuMessage wire format (contentTopic) and rejected it with "Missing required field: contentTopic". Marshal the wire shape explicitly. Turn examples/kernel into an end-to-end send/receive check: two relay nodes on cluster 16 / shard 64, connected via the listen multiaddr, one publishes and the other receives it off MsgChan. Verified against a locally-built liblogosdelivery: prints "send/receive OK". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: build against logos-delivery master (unpin #4012) logos-delivery#4012 merged, so drop the LOGOS_DELIVERY_REF pin and clone the default branch; the cache key tracks master's HEAD again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(ffi): flatten internal/ffi/liblogosdelivery into internal/ffi With a single library there is no bridge to choose between, so the extra subpackage adds nothing: move the bridge to internal/ffi (package ffi) and drop the umbrella doc. pkg/kernel now imports internal/ffi and calls ffi.*. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(kernel): add a two-node relay send/receive integration test TestRelaySendReceive connects two relay nodes, publishes a random payload from one and requires the other to receive it — end-to-end over the single library. Compiled by the PR gate; run under `make test` / locally against a built liblogosdelivery. (Replaces the former examples/kernel, removed alongside the ffi flatten.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(ffi): keep two files in package ffi, one per header The single library still ships two headers — liblogosdelivery.h (stable Messaging/lifecycle) and liblogosdelivery_kernel.h (low-level waku_*). Mirror that with two files in one package instead of one merged ffi.go: keep the messaging bridge and all the shared plumbing (Handle/RetOK/lifecycle/callbacks/ call) in liblogosdelivery.go, and keep the kernel wrappers in libwaku.go, which reuses the shared call + logosGoCallback. This is the same two files we had, moved into package ffi — a much smaller diff than the merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Apply suggestions from code review Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
317 lines
13 KiB
Go
317 lines
13 KiB
Go
// This file holds the low-level Kernel (waku_*) tier of the single
|
|
// liblogosdelivery library (declared in liblogosdelivery_kernel.h). The shared
|
|
// plumbing — Handle, RetOK, EventHandler, the node lifecycle, the response/event
|
|
// callbacks and the call helper — lives in liblogosdelivery.go (same package).
|
|
package ffi
|
|
|
|
/*
|
|
#include <liblogosdelivery_kernel.h>
|
|
#include <stdlib.h>
|
|
|
|
// logosGoCallback (the synchronous response callback) is defined in
|
|
// liblogosdelivery.go; the kernel wrappers below reuse it.
|
|
extern void logosGoCallback(int ret, char* msg, size_t len, void* resp);
|
|
static void cGoWakuStartDiscV5(void* ctx, void* resp) {
|
|
waku_start_discv5(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuStopDiscV5(void* ctx, void* resp) {
|
|
waku_stop_discv5(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuVersion(void* ctx, void* resp) {
|
|
waku_version(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuRelayPublish(void* ctx, const char* pubSubTopic, const char* jsonWakuMessage, int timeoutMs, void* resp) {
|
|
waku_relay_publish(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic, jsonWakuMessage, timeoutMs);
|
|
}
|
|
static void cGoWakuRelaySubscribe(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_subscribe(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuRelayAddProtectedShard(void* ctx, int clusterId, int shardId, char* publicKey, void* resp) {
|
|
waku_relay_add_protected_shard(ctx, (FFICallBack) logosGoCallback, resp, clusterId, shardId, publicKey);
|
|
}
|
|
static void cGoWakuRelayUnsubscribe(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_unsubscribe(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuConnect(void* ctx, const char* peerMultiAddr, int timeoutMs, void* resp) {
|
|
waku_connect(ctx, (FFICallBack) logosGoCallback, resp, peerMultiAddr, timeoutMs);
|
|
}
|
|
static void cGoWakuDialPeer(void* ctx, const char* peerMultiAddr, const char* protocol, int timeoutMs, void* resp) {
|
|
waku_dial_peer(ctx, (FFICallBack) logosGoCallback, resp, peerMultiAddr, protocol, timeoutMs);
|
|
}
|
|
static void cGoWakuDialPeerById(void* ctx, const char* peerId, const char* protocol, int timeoutMs, void* resp) {
|
|
waku_dial_peer_by_id(ctx, (FFICallBack) logosGoCallback, resp, peerId, protocol, timeoutMs);
|
|
}
|
|
static void cGoWakuDisconnectPeerById(void* ctx, const char* peerId, void* resp) {
|
|
waku_disconnect_peer_by_id(ctx, (FFICallBack) logosGoCallback, resp, peerId);
|
|
}
|
|
static void cGoWakuDisconnectAllPeers(void* ctx, void* resp) {
|
|
waku_disconnect_all_peers(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuListenAddresses(void* ctx, void* resp) {
|
|
waku_listen_addresses(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuGetMyENR(void* ctx, void* resp) {
|
|
waku_get_my_enr(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuGetMyPeerId(void* ctx, void* resp) {
|
|
waku_get_my_peerid(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuPingPeer(void* ctx, const char* peerAddr, int timeoutMs, void* resp) {
|
|
waku_ping_peer(ctx, (FFICallBack) logosGoCallback, resp, peerAddr, timeoutMs);
|
|
}
|
|
static void cGoWakuGetPeersInMesh(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_get_peers_in_mesh(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuGetNumPeersInMesh(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_get_num_peers_in_mesh(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuGetNumConnectedRelayPeers(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_get_num_connected_peers(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuGetConnectedRelayPeers(void* ctx, const char* pubSubTopic, void* resp) {
|
|
waku_relay_get_connected_peers(ctx, (FFICallBack) logosGoCallback, resp, pubSubTopic);
|
|
}
|
|
static void cGoWakuGetConnectedPeers(void* ctx, void* resp) {
|
|
waku_get_connected_peers(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuGetPeerIdsFromPeerStore(void* ctx, void* resp) {
|
|
waku_get_peerids_from_peerstore(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuGetConnectedPeersInfo(void* ctx, void* resp) {
|
|
waku_get_connected_peers_info(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuStoreQuery(void* ctx, const char* jsonQuery, const char* peerAddr, int timeoutMs, void* resp) {
|
|
waku_store_query(ctx, (FFICallBack) logosGoCallback, resp, jsonQuery, peerAddr, timeoutMs);
|
|
}
|
|
static void cGoWakuPeerExchangeQuery(void* ctx, uint64_t numPeers, void* resp) {
|
|
waku_peer_exchange_request(ctx, (FFICallBack) logosGoCallback, resp, numPeers);
|
|
}
|
|
static void cGoWakuGetPeerIdsByProtocol(void* ctx, const char* protocol, void* resp) {
|
|
waku_get_peerids_by_protocol(ctx, (FFICallBack) logosGoCallback, resp, protocol);
|
|
}
|
|
static void cGoWakuDnsDiscovery(void* ctx, const char* entTreeUrl, const char* nameDnsServer, int timeoutMs, void* resp) {
|
|
waku_dns_discovery(ctx, (FFICallBack) logosGoCallback, resp, entTreeUrl, nameDnsServer, timeoutMs);
|
|
}
|
|
static void cGoWakuIsOnline(void* ctx, void* resp) {
|
|
waku_is_online(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
static void cGoWakuGetMetrics(void* ctx, void* resp) {
|
|
waku_get_metrics(ctx, (FFICallBack) logosGoCallback, resp);
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import "unsafe"
|
|
|
|
// StartDiscV5 starts DiscV5 peer discovery.
|
|
func StartDiscV5(h Handle) error {
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuStartDiscV5(h, resp) })
|
|
return err
|
|
}
|
|
|
|
// StopDiscV5 stops DiscV5 peer discovery.
|
|
func StopDiscV5(h Handle) error {
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuStopDiscV5(h, resp) })
|
|
return err
|
|
}
|
|
|
|
// Version returns the libwaku version string.
|
|
func Version(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuVersion(h, resp) })
|
|
}
|
|
|
|
// RelayPublish publishes a WakuMessage JSON on a pubsub topic and returns
|
|
// the message hash.
|
|
func RelayPublish(h Handle, pubsubTopic, messageJSON string, timeoutMs int) (string, error) {
|
|
cTopic := C.CString(pubsubTopic)
|
|
cMsg := C.CString(messageJSON)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
defer C.free(unsafe.Pointer(cMsg))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuRelayPublish(h, cTopic, cMsg, C.int(timeoutMs), resp) })
|
|
}
|
|
|
|
// RelaySubscribe subscribes the node to a pubsub topic.
|
|
func RelaySubscribe(h Handle, pubsubTopic string) error {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuRelaySubscribe(h, cTopic, resp) })
|
|
return err
|
|
}
|
|
|
|
// RelayAddProtectedShard registers the hex-encoded public key allowed to
|
|
// sign messages on a protected shard.
|
|
func RelayAddProtectedShard(h Handle, clusterID, shardID int, publicKeyHex string) error {
|
|
cPublicKey := C.CString(publicKeyHex)
|
|
defer C.free(unsafe.Pointer(cPublicKey))
|
|
_, err := call(func(resp unsafe.Pointer) {
|
|
C.cGoWakuRelayAddProtectedShard(h, C.int(clusterID), C.int(shardID), cPublicKey, resp)
|
|
})
|
|
return err
|
|
}
|
|
|
|
// RelayUnsubscribe unsubscribes the node from a pubsub topic.
|
|
func RelayUnsubscribe(h Handle, pubsubTopic string) error {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuRelayUnsubscribe(h, cTopic, resp) })
|
|
return err
|
|
}
|
|
|
|
// Connect dials a peer multiaddress.
|
|
func Connect(h Handle, peerMultiAddr string, timeoutMs int) error {
|
|
cAddr := C.CString(peerMultiAddr)
|
|
defer C.free(unsafe.Pointer(cAddr))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuConnect(h, cAddr, C.int(timeoutMs), resp) })
|
|
return err
|
|
}
|
|
|
|
// DialPeer dials a peer multiaddress over a specific protocol.
|
|
func DialPeer(h Handle, peerMultiAddr, protocol string, timeoutMs int) error {
|
|
cAddr := C.CString(peerMultiAddr)
|
|
cProtocol := C.CString(protocol)
|
|
defer C.free(unsafe.Pointer(cAddr))
|
|
defer C.free(unsafe.Pointer(cProtocol))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuDialPeer(h, cAddr, cProtocol, C.int(timeoutMs), resp) })
|
|
return err
|
|
}
|
|
|
|
// DialPeerByID dials a known peer id over a specific protocol.
|
|
func DialPeerByID(h Handle, peerID, protocol string, timeoutMs int) error {
|
|
cPeerID := C.CString(peerID)
|
|
cProtocol := C.CString(protocol)
|
|
defer C.free(unsafe.Pointer(cPeerID))
|
|
defer C.free(unsafe.Pointer(cProtocol))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuDialPeerById(h, cPeerID, cProtocol, C.int(timeoutMs), resp) })
|
|
return err
|
|
}
|
|
|
|
// DisconnectPeerByID drops the connection to a peer.
|
|
func DisconnectPeerByID(h Handle, peerID string) error {
|
|
cPeerID := C.CString(peerID)
|
|
defer C.free(unsafe.Pointer(cPeerID))
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuDisconnectPeerById(h, cPeerID, resp) })
|
|
return err
|
|
}
|
|
|
|
// DisconnectAllPeers drops all peer connections.
|
|
func DisconnectAllPeers(h Handle) error {
|
|
_, err := call(func(resp unsafe.Pointer) { C.cGoWakuDisconnectAllPeers(h, resp) })
|
|
return err
|
|
}
|
|
|
|
// ListenAddresses returns the node's listen multiaddresses as a
|
|
// comma-separated list.
|
|
func ListenAddresses(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuListenAddresses(h, resp) })
|
|
}
|
|
|
|
// GetMyENR returns the node's ENR record.
|
|
func GetMyENR(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetMyENR(h, resp) })
|
|
}
|
|
|
|
// GetMyPeerID returns the node's peer id.
|
|
func GetMyPeerID(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetMyPeerId(h, resp) })
|
|
}
|
|
|
|
// PingPeer pings a peer (comma-separated multiaddresses) and returns the
|
|
// round-trip time in nanoseconds.
|
|
func PingPeer(h Handle, peerAddrs string, timeoutMs int) (string, error) {
|
|
cAddr := C.CString(peerAddrs)
|
|
defer C.free(unsafe.Pointer(cAddr))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuPingPeer(h, cAddr, C.int(timeoutMs), resp) })
|
|
}
|
|
|
|
// GetPeersInMesh returns the relay mesh peer ids for a pubsub topic as a
|
|
// comma-separated list.
|
|
func GetPeersInMesh(h Handle, pubsubTopic string) (string, error) {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetPeersInMesh(h, cTopic, resp) })
|
|
}
|
|
|
|
// GetNumPeersInMesh returns the relay mesh peer count for a pubsub topic.
|
|
func GetNumPeersInMesh(h Handle, pubsubTopic string) (string, error) {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetNumPeersInMesh(h, cTopic, resp) })
|
|
}
|
|
|
|
// GetNumConnectedRelayPeers returns the connected relay peer count for a
|
|
// pubsub topic.
|
|
func GetNumConnectedRelayPeers(h Handle, pubsubTopic string) (string, error) {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetNumConnectedRelayPeers(h, cTopic, resp) })
|
|
}
|
|
|
|
// GetConnectedRelayPeers returns the connected relay peer ids for a pubsub
|
|
// topic as a comma-separated list.
|
|
func GetConnectedRelayPeers(h Handle, pubsubTopic string) (string, error) {
|
|
cTopic := C.CString(pubsubTopic)
|
|
defer C.free(unsafe.Pointer(cTopic))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetConnectedRelayPeers(h, cTopic, resp) })
|
|
}
|
|
|
|
// GetConnectedPeers returns the connected peer ids as a comma-separated
|
|
// list.
|
|
func GetConnectedPeers(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetConnectedPeers(h, resp) })
|
|
}
|
|
|
|
// GetPeerIDsFromPeerStore returns the peer-store peer ids as a
|
|
// comma-separated list.
|
|
func GetPeerIDsFromPeerStore(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetPeerIdsFromPeerStore(h, resp) })
|
|
}
|
|
|
|
// GetConnectedPeersInfo returns the connected peers' info as JSON.
|
|
func GetConnectedPeersInfo(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetConnectedPeersInfo(h, resp) })
|
|
}
|
|
|
|
// StoreQuery runs a store query (JSON) against a peer (comma-separated
|
|
// multiaddresses) and returns the response JSON.
|
|
func StoreQuery(h Handle, queryJSON, peerAddrs string, timeoutMs int) (string, error) {
|
|
cQuery := C.CString(queryJSON)
|
|
cAddr := C.CString(peerAddrs)
|
|
defer C.free(unsafe.Pointer(cQuery))
|
|
defer C.free(unsafe.Pointer(cAddr))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuStoreQuery(h, cQuery, cAddr, C.int(timeoutMs), resp) })
|
|
}
|
|
|
|
// PeerExchangeRequest asks peer exchange for numPeers peers and returns
|
|
// the number of received peers.
|
|
func PeerExchangeRequest(h Handle, numPeers uint64) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuPeerExchangeQuery(h, C.uint64_t(numPeers), resp) })
|
|
}
|
|
|
|
// GetPeerIDsByProtocol returns the peer ids supporting a protocol as a
|
|
// comma-separated list.
|
|
func GetPeerIDsByProtocol(h Handle, protocol string) (string, error) {
|
|
cProtocol := C.CString(protocol)
|
|
defer C.free(unsafe.Pointer(cProtocol))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetPeerIdsByProtocol(h, cProtocol, resp) })
|
|
}
|
|
|
|
// DnsDiscovery resolves an ENR tree URL via DNS discovery and returns the
|
|
// discovered multiaddresses as a comma-separated list.
|
|
func DnsDiscovery(h Handle, enrTreeURL, nameDNSServer string, timeoutMs int) (string, error) {
|
|
cEnrTree := C.CString(enrTreeURL)
|
|
cDNSServer := C.CString(nameDNSServer)
|
|
defer C.free(unsafe.Pointer(cEnrTree))
|
|
defer C.free(unsafe.Pointer(cDNSServer))
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuDnsDiscovery(h, cEnrTree, cDNSServer, C.int(timeoutMs), resp) })
|
|
}
|
|
|
|
// IsOnline reports the node's online state ("true"/"false").
|
|
func IsOnline(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuIsOnline(h, resp) })
|
|
}
|
|
|
|
// GetMetrics returns the node's metrics in Prometheus text format.
|
|
func GetMetrics(h Handle) (string, error) {
|
|
return call(func(resp unsafe.Pointer) { C.cGoWakuGetMetrics(h, resp) })
|
|
}
|