Removing GetFreePortIfNeeded also removed the allocation StartWakuNode
did, and the library does not treat a zero DiscV5 UDP port as "pick one":
every node tried the same default and all but the first failed to bind.
StartWakuNode is test scaffolding, so it moves to the test helpers along
with the port allocation. Neither is part of the package surface now.
Restore messaging_client.go to its shape before this PR: Subscribe,
Unsubscribe and Send go back on MessagingClient, and the package imports
internal/ffi for the handle rather than reaching the calls through the
kernel. The only change left is what owning a kernel.Node requires — the
node holds the lifecycle and the listeners, and Node() exposes it.
Move the Messaging API back out of pkg/kernel: ffi.Handle becomes a
defined type in the internal package, so kernel can hand the context to
pkg/messaging through kernel.Handle without the kernel layer knowing the
tier exists, and without the type being nameable outside this module.
Split Discovery into DiscV5, PeerExchange and DNSDiscovery, group the
node's identity and health under Debug(), and give every facade a pointer
receiver. Drop the node name, the per-operation logging that duplicates
what the library already writes, and GetFreePortIfNeeded — port 0 already
means "let the OS pick".
Heavy kernel tests now mark themselves with requiresNode and skip under
-short, so the gate runs `go test -short ./...` instead of naming tests
in a regexp.
The Kernel API and the Messaging API each built their own node and kept
the FFI handle private, so a MessagingClient had no way to reach store
queries, peers or metrics. The C library has one context serving both
tiers, so this was only a Go ownership problem.
kernel.Node now owns that context, and the kernel protocols hang off it
as facades: Relay(), Store(), Peers(), Discovery(), plus Messaging() for
the stable tier. MessagingClient drives a Node and hands it over with
Node(), mirroring the Nim MessagingClient's public waku field.
Three bugs the kernel suite never caught, because CI only compiles it.
A peer's addresses were comma-joined into one argument, but the library
inits that argument as a single multiaddress, so StoreQuery and PingPeer
failed against any peer advertising more than one address.
StoreQueryResponse could decode neither the Opt[T] wrapper objects the
library renders results.Opt as, nor the integer arrays it renders
seq[byte] as, so every store reply failed to unmarshal. Both shapes now
decode, and the bare value still does.
A context without a deadline sent timeoutMs=0, which chronos' withTimeout
expires on immediately rather than treating as unbounded. StoreQuery with
context.Background() could never have succeeded.
Consumers resolve liblogosdelivery at the revision these bindings were
written against, instead of pinning it themselves, and build it through
the task here rather than reimplementing logos-delivery's flags.
srcDir points at an empty directory, so nothing is contributed to a
dependent's Nim path.
* feat(messaging): object-oriented Go mirror of the Nim MessagingClient
Adds pkg/messaging: a high-level, idiomatic Go binding for the Messaging
API, mirroring logos-delivery's Nim MessagingClient. A MessagingClient owns
a node and carries the messaging surface as methods on it — New / Start /
Stop / Close, Subscribe / Unsubscribe, Send(ctx, Envelope) (RequestID,
error) — over internal/ffi rather than exposing the raw FFI.
Events arrive on a single Events() <-chan Event with a sealed Event
interface: MessageReceivedEvent, MessageSentEvent, MessagePropagatedEvent,
MessageErrorEvent and ConnectionStatusEvent. Delivery never blocks the
library's event thread; an event is dropped when a consumer falls behind.
Config marshals to the layered configuration JSON (mode / preset /
messagingOverrides / channelsOverrides), with every field omitempty so it
can never be mistaken for the legacy flat blob.
Migrating internal/ffi to the current C ABI comes with it, because the
generated surface has moved on since the bridge was written and no longer
compiles: nim-ffi now generates the header from the {.ffi.} annotations,
argument-taking calls pass a per-call <Name>Req struct and a typed
<Name>ReplyFn, no-argument calls take a raw scalar callback, destroy is
synchronous, and the single set_event_callback has been replaced by a
per-event listener registry. The bridge now also copies every callback
string while it is still borrowed, and ignores the non-terminal
STALE_WARN progress code instead of settling the call on it.
pkg/kernel follows the same listener change, registering the three kernel
events it already consumed.
Verified against a liblogosdelivery built from logos-delivery master:
build / vet / golangci-lint / go mod tidy clean, unit tests green, and the
tagged integration test does a full create-start-subscribe-send round trip
on logos.dev, observing the message back and its propagation confirmation.
Closes#119.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CnzdnSMtHM5aLHLtDGBGR9
* review: address feedback on the MessagingClient API
- Send takes contentTopic / payload / ephemeral directly instead of an
Envelope struct, which drops the Envelope type; ContentTopic and RequestID
move to types.go.
- messagingEvents becomes a function returning the slice, so the set cannot
be mutated by accident.
- Document what seals the Event interface and what that buys callers.
- Document why the received payload is decoded from a JSON integer array:
base64 is only used on the send path and by the channel events, not by the
messaging events.
* ci: stop golangci-lint's config verify from failing on a network timeout
golangci-lint-action runs `golangci-lint config verify` before linting, which
fetches the v2.4 JSON schema from golangci-lint.run on every run. That request
timed out on the runner and failed the gate with no lint finding behind it. An
invalid config still fails the lint run itself, so the pre-check only costs a
network dependency.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* 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>
* refactor: extract libwaku cgo bridge into internal/ffi
Move the C preamble, cgo shims, and callback plumbing from pkg/kernel/nwaku.go
into internal/ffi/libwaku.go, where #111 scaffolded them to live. The bridge
exposes Go-typed Waku* primitives (handle in, strings out) and owns the
handle->event-handler registry, so pkg/kernel is now pure Go: WakuNode keeps
its full API, logging, and error texts, and just calls ffi.
Behavior is unchanged. Dropped four C shims that had no Go callers
(cGoWakuContentTopic, cGoWakuPubsubTopic, cGoWakuDefaultPubsubTopic,
cGoWakuLightpushPublish). CGO flags still come from the environment
(Makefile/CI untouched).
Part of #106.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: move libwaku bridge into internal/ffi/libwaku subpackage
One subpackage per C library so a binary links exactly the libraries it
imports: libwaku and liblogosdelivery carry overlapping symbols and must never
link together (until logos-delivery#3851). With the package named libwaku the
Waku* prefixes became stutter, so the exported primitives drop them
(libwaku.New/Start/RelayPublish/...). internal/ffi keeps an umbrella doc.go
stating the rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* refactor: adopt golang-standards/project-layout
Move the legacy kernel wrapper `waku/*` to `pkg/kernel/*` and rename its
package `waku` -> `kernel`; nothing outside the package imported it, so this is
a mechanical import-path/prefix change. Update the relocated Makefile's
relative dep path, the legacy CI workflows (CI/endurance/repeated) build paths,
README, and .gitignore accordingly (preserving the libwaku-cache CI from #109).
Add scaffolding for the upcoming Messaging API work: `internal/ffi` (cgo
bridge), `pkg/messaging` (high-level Node API), and `examples/`. Document
`pkg/kernel` as legacy until logos-delivery#3851 consolidates the C libraries.
Also stop tracking the accidentally-committed `waku-bindings` build artifact
and gitignore the kernel build output.
No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: cleanup
* fix: repair references to removed utils package
nwaku_test_utils.go now uses pkg/kernel/utils.GetRSSKB; the memory_record
tool is self-contained (local helpers, missing mutex restored).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>