Ivan FB 430ebc0bda
feat!: expose the generated bindings, drop the hand-written FFI tier
The generated crate already provides what this tier existed to build:
CBOR marshalling, the callback dance, and a typed method per proc. So
macros.rs (trampoline, handle_ffi_call) and libwaku_response.rs
(RET_OK/RET_ERR, LibwakuResponse) are deleted rather than ported, and
node/events.rs goes with them -- its WakuEvent enum is now one generated
payload struct per event, which is what the typed listeners hand back.

What survives is what the generated crate does not give us: the domain
layer (WakuMessage, WakuContentTopic, MessageHash, pubsubtopic) and
WakuNodeConfig, which still serialises to the JSON create_node takes --
that JSON is unchanged, only its transport moved to CBOR.

BREAKING CHANGE: WakuNodeHandle and its Initialized/Running typestate,
waku_new, and waku_destroy are gone; callers use LogosDeliveryCtx::create
and let Drop tear the node down. set_event_callback is gone too: events
are per-name now, so a whole-stream callback has no equivalent -- use the
typed add_on_*_listener methods, which deliver a payload struct instead
of a JSON string to match on.

Tests and the example move with the API. The event handling gets shorter
rather than longer: no from_str, no matching five variants, no panicking
on Unrecognized -- a listener only receives the event it registered for.
Callers now base64-decode payloads themselves, since that was WakuMessage's
serde doing it before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:08:23 +02:00

81 lines
2.6 KiB
Rust

use base64::Engine;
use serde::Serialize;
use serial_test::serial;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use waku_bindings::{ChannelMessageSentPayload, LogosDeliveryCtx, WakuNodeConfig};
const TEST_CHANNEL_ID: &str = "test-channel";
const TEST_CONTENT_TOPIC: &str = "/test/1/channels/proto";
const TEST_SENDER_ID: &str = "test-sender";
const TIMEOUT: Duration = Duration::from_secs(30);
/// Body of `channel_send`, whose payload travels base64-encoded.
#[derive(Serialize)]
struct ChannelMessage {
payload: String,
ephemeral: bool,
}
#[tokio::test]
#[serial]
async fn channel_create_send_close() {
let config = serde_json::to_string(&WakuNodeConfig {
tcp_port: Some(60070),
..Default::default()
})
.expect("config should serialise");
let node = LogosDeliveryCtx::new_async(config, TIMEOUT)
.await
.expect("node should instantiate");
// Channel traffic is reported through events, so capture them to prove the
// typed listener registers and delivers ChannelMessageSentPayload.
let sent: Arc<Mutex<Vec<ChannelMessageSentPayload>>> = Arc::new(Mutex::new(Vec::new()));
let sent_cloned = sent.clone();
node.add_on_channel_message_sent_listener(move |event| {
sent_cloned.lock().unwrap().push(event.clone());
});
node.start_node_async().await.expect("node should start");
let channel_id = node
.channel_create_async(
TEST_CHANNEL_ID.to_string(),
TEST_CONTENT_TOPIC.to_string(),
TEST_SENDER_ID.to_string(),
)
.await
.expect("channel should be created");
assert_eq!(channel_id, TEST_CHANNEL_ID);
let message = serde_json::to_string(&ChannelMessage {
payload: base64::engine::general_purpose::STANDARD.encode(b"Hi from a reliable channel!"),
ephemeral: false,
})
.expect("message should serialise");
let request_id = node
.channel_send_async(TEST_CHANNEL_ID.to_string(), message)
.await
.expect("channel send should succeed");
assert!(!request_id.is_empty(), "send should return a request id");
// Give the send a moment to finalise and emit its outcome event.
tokio::time::sleep(Duration::from_secs(2)).await;
node.channel_close_async(TEST_CHANNEL_ID.to_string())
.await
.expect("channel should close");
// Scoped so the guard is dropped before the await below.
{
let sent = sent.lock().unwrap();
println!("channel sent events observed: {sent:?}");
}
node.stop_node_async().await.expect("node should stop");
// The context is torn down by LogosDeliveryCtx's Drop impl.
}