mirror of
https://github.com/logos-messaging/logos-messaging-rust-bindings.git
synced 2026-04-06 03:53:27 +00:00
Merge 9cd5a30cb2b477771c00c0fbc923ce21eb8b6f6f into 95040402feae4ebc3038d66e1168390669bd6942
This commit is contained in:
commit
2d6b7abf0a
@ -2,3 +2,8 @@
|
||||
# when using osx, we need to link against some golang libraries, it did just work with this missing flags
|
||||
# from: https://github.com/golang/go/issues/42459
|
||||
rustflags = ["-C", "link-args=-framework CoreFoundation -framework Security -framework CoreServices -lresolv"]
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
# wasmer v2 references __rust_probestack which lld (Rust's default on Linux) can't resolve.
|
||||
# Force GNU bfd linker to avoid the undefined symbol error.
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=bfd"]
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
||||
[submodule "waku-sys/vendor"]
|
||||
path = waku-sys/vendor
|
||||
url = https://github.com/logos-messaging/logos-messaging-nim
|
||||
url = https://github.com/logos-messaging/logos-delivery
|
||||
|
||||
122
README.md
122
README.md
@ -1,26 +1,108 @@
|
||||
# Waku Rust bindings
|
||||
# logos-delivery Rust Bindings
|
||||
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Documentation][docs-badge]][docs-url]
|
||||
[![Build Status][actions-badge]][actions-url]
|
||||
[![Codecov Status][codecov-badge]][codecov-url]
|
||||
[Crates.io][crates-url]
|
||||
[Documentation][docs-url]
|
||||
[Build Status][actions-url]
|
||||
[Codecov Status][codecov-url]
|
||||
|
||||
Rust bindings for [logos-delivery](https://github.com/logos-messaging/logos-delivery) (Waku) v0.38.0-beta,
|
||||
built on top of the [C FFI](https://github.com/logos-messaging/logos-delivery/blob/master/library/libwaku.h).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Rust** (stable) — [rustup.rs](https://rustup.rs)
|
||||
- **Nim 2.x** — required to compile the native `libwaku` library
|
||||
-
|
||||
- **Make**
|
||||
- **GCC or Clang**
|
||||
|
||||
## Setup
|
||||
|
||||
Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/logos-messaging/logos-delivery-rust-bindings.git
|
||||
cd logos-delivery-rust-bindings
|
||||
```
|
||||
|
||||
The first `cargo build` / `cargo run` automatically:
|
||||
|
||||
1. Initializes and updates git submodules
|
||||
2. Compiles the native `libwaku` static library via `make libwaku STATIC=1`
|
||||
3. Generates Rust FFI bindings via `bindgen`
|
||||
|
||||
## Running the Examples
|
||||
|
||||
### basic
|
||||
|
||||
Two Waku nodes in the same process. Node 1 publishes a message; node 2 receives it via relay subscription.
|
||||
|
||||
```bash
|
||||
cd examples/basic
|
||||
cargo run
|
||||
```
|
||||
|
||||
### toy-chat
|
||||
|
||||
Multi-participant chat room over Waku relay. Pass your nickname as argument.
|
||||
|
||||
```bash
|
||||
cd examples/toy-chat
|
||||
cargo run "Alice"
|
||||
```
|
||||
|
||||
Start another instance in a separate terminal (or on another machine) to chat:
|
||||
|
||||
```bash
|
||||
cargo run "Bob"
|
||||
```
|
||||
|
||||
### tic-tac-toe-gui
|
||||
|
||||
Multiplayer tic-tac-toe with a native GUI (eframe). Start two instances — locally or on separate machines.
|
||||
|
||||
```bash
|
||||
cd examples/tic-tac-toe-gui
|
||||
cargo run
|
||||
```
|
||||
|
||||
## Running the Tests
|
||||
|
||||
Tests start real Waku nodes and bind to local TCP ports, so they **must run serially**:
|
||||
|
||||
```bash
|
||||
# from repo root
|
||||
cargo test -p waku-bindings -- --test-threads=1
|
||||
|
||||
# or from waku-bindings/
|
||||
cd waku-bindings
|
||||
cargo test
|
||||
```
|
||||
|
||||
To see log output:
|
||||
|
||||
```bash
|
||||
cargo test -- --nocapture
|
||||
```
|
||||
|
||||
## Crates
|
||||
|
||||
| Crate | Description |
|
||||
| -------------------------------- | ------------------------------ |
|
||||
| [`waku-bindings`](waku-bindings/) | High-level Rust API |
|
||||
| [`waku-sys`](waku-sys/) | Low-level bindgen FFI bindings |
|
||||
|
||||
## About Waku
|
||||
|
||||
[Waku](https://waku.org/) is a family of robust, censorship-resistant communication protocols for Web3. Private. Secure. Runs anywhere.
|
||||
|
||||
Read the [Waku docs](https://docs.waku.org/)
|
||||
|
||||
[crates-badge]: https://img.shields.io/crates/v/waku-bindings.svg
|
||||
[crates-url]: https://crates.io/crates/waku-bindings
|
||||
[docs-badge]: https://docs.rs/waku-bindings/badge.svg
|
||||
[docs-url]: https://docs.rs/waku-bindings
|
||||
[actions-badge]: https://github.com/logos-messaging/logos-messaging-rust-bindings/workflows/CI/badge.svg
|
||||
[actions-url]: https://github.com/logos-messaging/logos-messaging-rust-bindings/actions/workflows/main.yml?query=workflow%3ACI+branch%3Amaster
|
||||
[codecov-badge]: https://codecov.io/github/logos-messaging/logos-messaging-rust-bindings/branch/main/graph/badge.svg?token=H4CQWRUCUS
|
||||
[codecov-url]: https://codecov.io/github/logos-messaging/logos-messaging-rust-bindings
|
||||
|
||||
Rust layer on top of [`logos-messaging-nim`](https://github.com/logos-messaging/logos-messaging-nim) [C FFI bindings](https://github.com/logos-messaging/logos-messaging-nim/blob/master/library/libwaku.h).
|
||||
|
||||
|
||||
## About Waku
|
||||
|
||||
[Waku](https://waku.org/) is a family of robust and censorship-resistant communication protocols enabling privacy-focused messaging for Web3 applications.
|
||||
|
||||
Private. Secure. Runs anywhere.
|
||||
|
||||
Read the [Waku docs](https://docs.waku.org/)
|
||||
[actions-badge]: https://github.com/logos-messaging/logos-delivery-rust-bindings/workflows/CI/badge.svg
|
||||
[actions-url]: https://github.com/logos-messaging/logos-delivery-rust-bindings/actions/workflows/main.yml?query=workflow%3ACI+branch%3Amaster
|
||||
[codecov-badge]: https://codecov.io/github/logos-messaging/logos-delivery-rust-bindings/branch/main/graph/badge.svg?token=H4CQWRUCUS
|
||||
[codecov-url]: https://codecov.io/github/logos-messaging/logos-delivery-rust-bindings
|
||||
|
||||
3
examples/Cargo.lock
generated
3
examples/Cargo.lock
generated
@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
@ -4733,6 +4733,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
"libc",
|
||||
"prost",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -46,6 +46,7 @@ async fn main() -> Result<(), Error> {
|
||||
WakuEvent::ConnectionChange(_evt) => {
|
||||
// dbg!("Conn change evt", evt);
|
||||
}
|
||||
WakuEvent::NodeHealthChange(_evt) => {}
|
||||
WakuEvent::Unrecognized(err) => panic!("Unrecognized waku event: {:?}", err),
|
||||
_ => panic!("event case not expected"),
|
||||
};
|
||||
@ -75,6 +76,7 @@ async fn main() -> Result<(), Error> {
|
||||
WakuEvent::ConnectionChange(_evt) => {
|
||||
// dbg!("Conn change evt", evt);
|
||||
}
|
||||
WakuEvent::NodeHealthChange(_evt) => {}
|
||||
WakuEvent::Unrecognized(err) => panic!("Unrecognized waku event: {:?}", err),
|
||||
_ => panic!("event case not expected"),
|
||||
};
|
||||
|
||||
@ -7,9 +7,8 @@ use tokio::task;
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use waku::{
|
||||
waku_new, Encoding, WakuEvent, LibwakuResponse, WakuContentTopic,
|
||||
WakuMessage, WakuNodeConfig, WakuNodeHandle, Initialized, Running,
|
||||
general::pubsubtopic::PubsubTopic,
|
||||
general::pubsubtopic::PubsubTopic, waku_new, Encoding, Initialized, LibwakuResponse, Running,
|
||||
WakuContentTopic, WakuEvent, WakuMessage, WakuNodeConfig, WakuNodeHandle,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)]
|
||||
@ -29,7 +28,7 @@ struct TicTacToeApp<State> {
|
||||
game_state: Arc<Mutex<GameState>>,
|
||||
waku: WakuNodeHandle<State>,
|
||||
game_topic: PubsubTopic,
|
||||
tx: mpsc::Sender<String>, // Sender to send `msg` to main thread
|
||||
tx: mpsc::Sender<String>, // Sender to send `msg` to main thread
|
||||
player_role: Option<Player>, // Store the player's role (X or O)
|
||||
}
|
||||
|
||||
@ -51,7 +50,8 @@ impl TicTacToeApp<Initialized> {
|
||||
|
||||
async fn start(self) -> TicTacToeApp<Running> {
|
||||
let tx_clone = self.tx.clone();
|
||||
let game_content_topic = WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
let game_content_topic =
|
||||
WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
|
||||
let my_closure = move |response| {
|
||||
if let LibwakuResponse::Success(v) = response {
|
||||
@ -78,13 +78,13 @@ impl TicTacToeApp<Initialized> {
|
||||
// Handle the error as needed, or just log and skip
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
WakuEvent::RelayTopicHealthChange(_evt) => {
|
||||
// dbg!("Relay topic change evt", evt);
|
||||
},
|
||||
}
|
||||
WakuEvent::ConnectionChange(_evt) => {
|
||||
// dbg!("Conn change evt", evt);
|
||||
},
|
||||
}
|
||||
WakuEvent::Unrecognized(err) => panic!("Unrecognized waku event: {:?}", err),
|
||||
_ => panic!("event case not expected"),
|
||||
};
|
||||
@ -92,13 +92,17 @@ impl TicTacToeApp<Initialized> {
|
||||
};
|
||||
|
||||
// Establish a closure that handles the incoming messages
|
||||
self.waku.set_event_callback(my_closure).expect("set event call back working");
|
||||
self.waku
|
||||
.set_event_callback(my_closure)
|
||||
.expect("set event call back working");
|
||||
|
||||
// Start the waku node
|
||||
let waku = self.waku.start().await.expect("waku should start");
|
||||
|
||||
// Subscribe to desired topic using the relay protocol
|
||||
waku.relay_subscribe(&self.game_topic).await.expect("waku should subscribe");
|
||||
waku.relay_subscribe(&self.game_topic)
|
||||
.await
|
||||
.expect("waku should subscribe");
|
||||
|
||||
// Example filter subscription. This is needed in edge nodes (resource-restricted devices)
|
||||
// Nodes usually use either relay or lightpush/filter protocols
|
||||
@ -138,15 +142,13 @@ impl TicTacToeApp<Running> {
|
||||
let serialized_game_state = serde_json::to_string(game_state).unwrap();
|
||||
let content_topic = WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
|
||||
let message = WakuMessage::new(
|
||||
&serialized_game_state,
|
||||
content_topic,
|
||||
0,
|
||||
Vec::new(),
|
||||
false,
|
||||
);
|
||||
let message = WakuMessage::new(&serialized_game_state, content_topic, 0, Vec::new(), false);
|
||||
|
||||
if let Ok(msg_hash) = self.waku.relay_publish_message(&message, &self.game_topic, None).await {
|
||||
if let Ok(msg_hash) = self
|
||||
.waku
|
||||
.relay_publish_message(&message, &self.game_topic, None)
|
||||
.await
|
||||
{
|
||||
dbg!(format!("message hash published: {}", msg_hash));
|
||||
}
|
||||
|
||||
@ -163,7 +165,6 @@ impl TicTacToeApp<Running> {
|
||||
|
||||
fn make_move(&mut self, row: usize, col: usize) {
|
||||
if let Ok(mut game_state) = self.game_state.try_lock() {
|
||||
|
||||
if let Some(my_role) = self.player_role {
|
||||
if game_state.current_turn != my_role {
|
||||
return; // skip click if not my turn
|
||||
@ -201,27 +202,31 @@ impl TicTacToeApp<Running> {
|
||||
fn check_winner(&self, game_state: &GameState) -> Option<Player> {
|
||||
// Check rows, columns, and diagonals
|
||||
for i in 0..3 {
|
||||
if game_state.board[i][0] == game_state.board[i][1] &&
|
||||
game_state.board[i][1] == game_state.board[i][2] {
|
||||
if game_state.board[i][0] == game_state.board[i][1]
|
||||
&& game_state.board[i][1] == game_state.board[i][2]
|
||||
{
|
||||
if let Some(player) = game_state.board[i][0] {
|
||||
return Some(player);
|
||||
}
|
||||
}
|
||||
if game_state.board[0][i] == game_state.board[1][i] &&
|
||||
game_state.board[1][i] == game_state.board[2][i] {
|
||||
if game_state.board[0][i] == game_state.board[1][i]
|
||||
&& game_state.board[1][i] == game_state.board[2][i]
|
||||
{
|
||||
if let Some(player) = game_state.board[0][i] {
|
||||
return Some(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
if game_state.board[0][0] == game_state.board[1][1] &&
|
||||
game_state.board[1][1] == game_state.board[2][2] {
|
||||
if game_state.board[0][0] == game_state.board[1][1]
|
||||
&& game_state.board[1][1] == game_state.board[2][2]
|
||||
{
|
||||
if let Some(player) = game_state.board[0][0] {
|
||||
return Some(player);
|
||||
}
|
||||
}
|
||||
if game_state.board[0][2] == game_state.board[1][1] &&
|
||||
game_state.board[1][1] == game_state.board[2][0] {
|
||||
if game_state.board[0][2] == game_state.board[1][1]
|
||||
&& game_state.board[1][1] == game_state.board[2][0]
|
||||
{
|
||||
if let Some(player) = game_state.board[0][2] {
|
||||
return Some(player);
|
||||
}
|
||||
@ -241,7 +246,6 @@ impl TicTacToeApp<Running> {
|
||||
|
||||
impl eframe::App for TicTacToeApp<Running> {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
|
||||
// Request a repaint every second
|
||||
ctx.request_repaint_after(Duration::from_secs(1));
|
||||
|
||||
@ -286,13 +290,16 @@ impl eframe::App for TicTacToeApp<Running> {
|
||||
Some(Player::O) => "O",
|
||||
None => "-",
|
||||
};
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
label = "#";
|
||||
}
|
||||
}
|
||||
|
||||
let button = ui.add(egui::Button::new(label).min_size(egui::vec2(cell_size, cell_size)).sense(egui::Sense::click()));
|
||||
let button = ui.add(
|
||||
egui::Button::new(label)
|
||||
.min_size(egui::vec2(cell_size, cell_size))
|
||||
.sense(egui::Sense::click()),
|
||||
);
|
||||
|
||||
if button.clicked() {
|
||||
self.make_move(row, col);
|
||||
@ -384,13 +391,11 @@ async fn main() -> eframe::Result<()> {
|
||||
while let Some(msg) = rx.recv().await {
|
||||
// println!("MSG received: {}", msg);
|
||||
// Handle the received message, e.g., update the UI or game state
|
||||
if let Ok(parsed_value) = serde_json::from_str::<GameState>(&msg)
|
||||
{
|
||||
if let Ok(mut unclocked_game_state) = clone.lock(){
|
||||
if let Ok(parsed_value) = serde_json::from_str::<GameState>(&msg) {
|
||||
if let Ok(mut unclocked_game_state) = clone.lock() {
|
||||
*unclocked_game_state = parsed_value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
eprintln!("Failed to parse JSON");
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,4 +16,5 @@ crossterm = "0.25"
|
||||
unicode-width = "0.1"
|
||||
prost = "0.11"
|
||||
chrono = "0.4"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
libc = "0.2"
|
||||
@ -1,18 +1,19 @@
|
||||
mod protocol;
|
||||
|
||||
use crate::protocol::{Chat2Message, TOY_CHAT_CONTENT_TOPIC};
|
||||
use tokio::task;
|
||||
use chrono::Utc;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use prost::Message;
|
||||
use chrono::Utc;
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{error::Error, io};
|
||||
use std::time::Duration;
|
||||
use std::{error::Error, io};
|
||||
use tokio::task;
|
||||
use tui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
@ -23,8 +24,8 @@ use tui::{
|
||||
};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use waku::{
|
||||
general::pubsubtopic::PubsubTopic, general::Result, waku_new, Initialized, LibwakuResponse, Running, WakuEvent,
|
||||
WakuMessage, WakuNodeConfig, WakuNodeHandle,
|
||||
general::pubsubtopic::PubsubTopic, general::Result, waku_new, Initialized, LibwakuResponse,
|
||||
Running, WakuEvent, WakuMessage, WakuNodeConfig, WakuNodeHandle,
|
||||
};
|
||||
|
||||
enum InputMode {
|
||||
@ -55,23 +56,21 @@ impl App<Initialized> {
|
||||
tcp_port: Some(60010),
|
||||
cluster_id: Some(16),
|
||||
shards: vec![1, 32, 64, 128, 256],
|
||||
num_shards_in_network: Some(1024),
|
||||
// node_key: Some(SecretKey::from_str("2fc0515879e52b7b73297cfd6ab3abf7c344ef84b7a90ff6f4cc19e05a198027").unwrap()),
|
||||
max_message_size: Some("1024KiB".to_string()),
|
||||
relay_topics: vec![String::from(&pubsub_topic)],
|
||||
log_level: Some("FATAL"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL
|
||||
|
||||
keep_alive: Some(true),
|
||||
|
||||
// Discovery
|
||||
dns_discovery: Some(true),
|
||||
dns_discovery_url: Some("enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.prod.status.nodes.status.im"),
|
||||
// discv5_discovery: Some(true),
|
||||
// discv5_udp_port: Some(9001),
|
||||
// discv5_enr_auto_update: Some(false),
|
||||
|
||||
..Default::default()
|
||||
})).await?;
|
||||
|
||||
|
||||
Ok(App {
|
||||
input: String::new(),
|
||||
input_mode: InputMode::Normal,
|
||||
@ -82,17 +81,15 @@ impl App<Initialized> {
|
||||
}
|
||||
|
||||
async fn start_waku_node(self) -> Result<App<Running>> {
|
||||
|
||||
let shared_messages = Arc::clone(&self.messages);
|
||||
|
||||
self.waku.set_event_callback(move|response| {
|
||||
self.waku.set_event_callback(move |response| {
|
||||
if let LibwakuResponse::Success(v) = response {
|
||||
let event: WakuEvent =
|
||||
serde_json::from_str(v.unwrap().as_str()).expect("failed parsing event in set_event_callback");
|
||||
let event: WakuEvent = serde_json::from_str(v.unwrap().as_str())
|
||||
.expect("failed parsing event in set_event_callback");
|
||||
|
||||
match event {
|
||||
WakuEvent::WakuMessage(evt) => {
|
||||
|
||||
if evt.waku_message.content_topic != TOY_CHAT_CONTENT_TOPIC {
|
||||
return; // skip the messages that don't belong to the toy chat
|
||||
}
|
||||
@ -110,13 +107,14 @@ impl App<Initialized> {
|
||||
write!(out, "{e:?}").unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
WakuEvent::RelayTopicHealthChange(_evt) => {
|
||||
// dbg!("Relay topic change evt", evt);
|
||||
},
|
||||
}
|
||||
WakuEvent::ConnectionChange(_evt) => {
|
||||
// dbg!("Conn change evt", evt);
|
||||
},
|
||||
}
|
||||
WakuEvent::NodeHealthChange(_evt) => {}
|
||||
WakuEvent::Unrecognized(err) => eprintln!("Unrecognized waku event: {:?}", err),
|
||||
_ => eprintln!("event case not expected"),
|
||||
};
|
||||
@ -136,32 +134,37 @@ impl App<Initialized> {
|
||||
}
|
||||
|
||||
impl App<Running> {
|
||||
|
||||
async fn retrieve_history(&mut self) {
|
||||
let one_day_in_secs = 60 * 60 * 24;
|
||||
let time_start = (Duration::from_secs(Utc::now().timestamp() as u64)
|
||||
- Duration::from_secs(one_day_in_secs))
|
||||
.as_nanos() as u64;
|
||||
.as_nanos() as u64;
|
||||
|
||||
let include_data = true;
|
||||
|
||||
let messages = self.waku.store_query(None,
|
||||
vec![TOY_CHAT_CONTENT_TOPIC.clone()],
|
||||
STORE_NODE,
|
||||
include_data,
|
||||
Some(time_start),
|
||||
None,
|
||||
None).await.unwrap();
|
||||
let messages = self
|
||||
.waku
|
||||
.store_query(
|
||||
None,
|
||||
vec![TOY_CHAT_CONTENT_TOPIC.clone()],
|
||||
STORE_NODE,
|
||||
include_data,
|
||||
Some(time_start),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let messages: Vec<_> = messages
|
||||
.into_iter()
|
||||
// we expect messages because the query was passed with include_data == true
|
||||
.filter(|item| item.message.is_some())
|
||||
.map(|store_resp_msg| {
|
||||
<Chat2Message as Message>::decode(store_resp_msg.message.unwrap().payload())
|
||||
.expect("Toy chat messages should be decodeable")
|
||||
})
|
||||
.collect();
|
||||
.into_iter()
|
||||
// we expect messages because the query was passed with include_data == true
|
||||
.filter(|item| item.message.is_some())
|
||||
.map(|store_resp_msg| {
|
||||
<Chat2Message as Message>::decode(store_resp_msg.message.unwrap().payload())
|
||||
.expect("Toy chat messages should be decodeable")
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !messages.is_empty() {
|
||||
*self.messages.write().unwrap() = messages;
|
||||
@ -211,14 +214,18 @@ impl App<Running> {
|
||||
handle.block_on(async {
|
||||
// Assuming `self` is available in the current context
|
||||
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
|
||||
if let Err(e) = self.waku.relay_publish_message(
|
||||
&waku_message,
|
||||
&pubsub_topic,
|
||||
None,
|
||||
).await {
|
||||
let mut out = std::io::stderr();
|
||||
write!(out, "{e:?}").unwrap();
|
||||
}
|
||||
if let Err(e) = self
|
||||
.waku
|
||||
.relay_publish_message(
|
||||
&waku_message,
|
||||
&pubsub_topic,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
let mut out = std::io::stderr();
|
||||
write!(out, "{e:?}").unwrap();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -240,7 +247,10 @@ impl App<Running> {
|
||||
}
|
||||
|
||||
async fn stop_app(self) {
|
||||
self.waku.stop().await.expect("the node should stop properly");
|
||||
self.waku
|
||||
.stop()
|
||||
.await
|
||||
.expect("the node should stop properly");
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,6 +261,12 @@ async fn main() -> std::result::Result<(), Box<dyn Error>> {
|
||||
let app = App::new(nick).await?;
|
||||
let mut app = app.start_waku_node().await?;
|
||||
|
||||
// Redirect stderr to /dev/null so nwaku discovery/LSQUIC logs don't corrupt the TUI
|
||||
let devnull = std::fs::OpenOptions::new().write(true).open("/dev/null")?;
|
||||
unsafe {
|
||||
libc::dup2(devnull.into_raw_fd(), 2);
|
||||
}
|
||||
|
||||
// setup terminal
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
@ -258,7 +274,12 @@ async fn main() -> std::result::Result<(), Box<dyn Error>> {
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
app.retrieve_history().await;
|
||||
// Fetch history in the background so the TUI starts immediately
|
||||
tokio::spawn(async move {
|
||||
// small delay so the node has time to connect to peers before querying
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
});
|
||||
|
||||
let res = app.run_main_loop(&mut terminal);
|
||||
app.stop_app().await;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::general::libwaku_response::LibwakuResponse;
|
||||
|
||||
use std::{slice, str};
|
||||
use waku_sys::WakuCallBack;
|
||||
use waku_sys::FFICallBack;
|
||||
|
||||
unsafe extern "C" fn trampoline<F>(
|
||||
ret_code: ::std::os::raw::c_int,
|
||||
@ -26,7 +26,7 @@ unsafe extern "C" fn trampoline<F>(
|
||||
closure(result);
|
||||
}
|
||||
|
||||
pub fn get_trampoline<F>(_closure: &F) -> WakuCallBack
|
||||
pub fn get_trampoline<F>(_closure: &F) -> FFICallBack
|
||||
where
|
||||
F: FnMut(LibwakuResponse),
|
||||
{
|
||||
@ -57,10 +57,10 @@ macro_rules! handle_ffi_call {
|
||||
let code = unsafe {
|
||||
let cb = get_trampoline(&closure);
|
||||
$waku_fn(
|
||||
$ctx, // Pass the context
|
||||
$($($arg),*,)? // Expand the variadic arguments if provided
|
||||
cb, // Pass the callback trampoline
|
||||
&mut closure as *mut _ as *mut c_void
|
||||
$ctx, // Pass the context
|
||||
cb, // Pass the callback trampoline
|
||||
&mut closure as *mut _ as *mut c_void, // Pass the user data
|
||||
$($($arg),*)? // Expand the variadic arguments if provided
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@ -28,8 +28,12 @@ pub struct WakuNodeConfig {
|
||||
#[default(Some(true))]
|
||||
pub relay: Option<bool>,
|
||||
pub relay_topics: Vec<String>,
|
||||
#[default(vec![1])]
|
||||
#[default(vec![0])]
|
||||
pub shards: Vec<usize>,
|
||||
/// Number of shards in the network (for auto-sharding). Shard indices must be < this value.
|
||||
/// Default 8. Must be > max(shards).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_shards_in_network: Option<usize>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_message_size: Option<String>,
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ impl WakuNodeContext {
|
||||
*boxed_closure = Box::new(closure);
|
||||
unsafe {
|
||||
let cb = get_trampoline(&(*boxed_closure));
|
||||
waku_sys::waku_set_event_callback(
|
||||
waku_sys::set_event_callback(
|
||||
self.obj_ptr,
|
||||
cb,
|
||||
&mut (*boxed_closure) as *mut _ as *mut c_void,
|
||||
|
||||
@ -27,6 +27,9 @@ pub enum WakuEvent {
|
||||
#[serde(rename = "connection_change")]
|
||||
ConnectionChange(ConnectionChangeEvent),
|
||||
|
||||
#[serde(rename = "node_health_change")]
|
||||
NodeHealthChange(NodeHealthChangeEvent),
|
||||
|
||||
Unrecognized(serde_json::Value),
|
||||
}
|
||||
|
||||
@ -56,12 +59,17 @@ pub struct TopicHealthEvent {
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConnectionChangeEvent {
|
||||
/// The pubsub topic on which the message was received
|
||||
pub peer_id: String,
|
||||
/// The message hash
|
||||
pub peer_event: String,
|
||||
}
|
||||
|
||||
/// Type of `event` field for a `node_health_change` event
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NodeHealthChangeEvent {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::WakuEvent;
|
||||
|
||||
@ -58,6 +58,9 @@ async fn test_echo_messages(
|
||||
WakuEvent::ConnectionChange(_evt) => {
|
||||
// dbg!("Conn change evt", evt);
|
||||
}
|
||||
WakuEvent::NodeHealthChange(_evt) => {
|
||||
// dbg!("Node health change evt", evt);
|
||||
}
|
||||
WakuEvent::Unrecognized(err) => panic!("Unrecognized waku event: {:?}", err),
|
||||
_ => panic!("event case not expected"),
|
||||
};
|
||||
|
||||
@ -97,8 +97,30 @@ fn generate_bindgen_code(project_dir: &Path) {
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=natpmp");
|
||||
|
||||
// Link librln (built by `make librln` as part of `make libwaku`)
|
||||
// The file is named librln_v<version>.a and lives in the vendor root.
|
||||
if let Ok(entries) = std::fs::read_dir(&nwaku_path) {
|
||||
for entry in entries.flatten() {
|
||||
let name = entry.file_name();
|
||||
let name_str = name.to_string_lossy();
|
||||
if name_str.starts_with("librln_") && name_str.ends_with(".a") {
|
||||
let lib_name = name_str.trim_start_matches("lib").trim_end_matches(".a");
|
||||
println!("cargo:rustc-link-search=native={}", nwaku_path.display());
|
||||
println!("cargo:rustc-link-lib=static={}", lib_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("cargo:rustc-link-lib=dl");
|
||||
println!("cargo:rustc-link-lib=m");
|
||||
// nim-lsquic embeds BoringSSL (C++) — requires C++ runtime
|
||||
let cpp_lib = if cfg!(target_os = "macos") {
|
||||
"c++"
|
||||
} else {
|
||||
"stdc++"
|
||||
};
|
||||
println!("cargo:rustc-link-lib={}", cpp_lib);
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 4117449b9af6c0304a6115dd4bc0d1d745159685
|
||||
Subproject commit 104ce6e5ac16b9c5e818788e2fb2858c36f36bbf
|
||||
Loading…
x
Reference in New Issue
Block a user