From 122b75c6a15433ce9021e8de4ddb77cc3db1dd09 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Wed, 28 Feb 2024 17:09:14 -0400 Subject: [PATCH] refactor: add back typestate --- waku-bindings/src/lib.rs | 4 +-- waku-bindings/src/node/events.rs | 11 +++---- waku-bindings/src/node/mod.rs | 50 +++++++++++++++++++++++--------- waku-bindings/src/utils.rs | 7 +++-- waku-bindings/tests/node.rs | 27 ++++++++--------- 5 files changed, 61 insertions(+), 38 deletions(-) diff --git a/waku-bindings/src/lib.rs b/waku-bindings/src/lib.rs index 5f8b648..b5253ec 100644 --- a/waku-bindings/src/lib.rs +++ b/waku-bindings/src/lib.rs @@ -12,8 +12,8 @@ mod utils; use rln; pub use node::{ - waku_create_content_topic, Event, Key, Multiaddr, PublicKey, SecretKey, - WakuMessageEvent, WakuNodeConfig, WakuNodeHandle, + waku_create_content_topic, waku_new, Event, Initialized, Key, Multiaddr, PublicKey, Running, + SecretKey, WakuMessageEvent, WakuNodeConfig, WakuNodeHandle, }; pub use general::{Encoding, MessageId, Result, WakuContentTopic, WakuMessage, WakuMessageVersion}; diff --git a/waku-bindings/src/node/events.rs b/waku-bindings/src/node/events.rs index 8f66c53..e9ead24 100644 --- a/waku-bindings/src/node/events.rs +++ b/waku-bindings/src/node/events.rs @@ -41,13 +41,10 @@ pub struct WakuMessageEvent { /// which are used to react to asynchronous events in Waku pub fn waku_set_event_callback(ctx: &WakuNodeContext, mut f: F) { let cb = |response: LibwakuResponse| { - match response { - LibwakuResponse::Success(v) => { - let data: Event = - serde_json::from_str(v.unwrap().as_str()).expect("Parsing event to succeed"); - f(data); - } - _ => {} // Do nothing + if let LibwakuResponse::Success(v) = response { + let data: Event = + serde_json::from_str(v.unwrap().as_str()).expect("Parsing event to succeed"); + f(data); }; }; diff --git a/waku-bindings/src/node/mod.rs b/waku-bindings/src/node/mod.rs index a8e8e98..2073c4a 100644 --- a/waku-bindings/src/node/mod.rs +++ b/waku-bindings/src/node/mod.rs @@ -11,6 +11,7 @@ mod relay; pub use aes_gcm::Key; pub use multiaddr::Multiaddr; pub use secp256k1::{PublicKey, SecretKey}; +use std::marker::PhantomData; use std::time::Duration; // internal use crate::general::{MessageId, Result, WakuMessage}; @@ -20,31 +21,52 @@ pub use config::WakuNodeConfig; pub use events::{Event, WakuMessageEvent}; pub use relay::waku_create_content_topic; +/// Marker trait to disallow undesired waku node states in the handle +pub trait WakuNodeState {} + +/// Waku node initialized state +pub struct Initialized; + +/// Waku node running state +pub struct Running; + +impl WakuNodeState for Initialized {} +impl WakuNodeState for Running {} + /// Handle to the underliying waku node -pub struct WakuNodeHandle { +pub struct WakuNodeHandle { ctx: WakuNodeContext, + phantom: PhantomData, } -impl WakuNodeHandle { - /// Spawn a new Waku node with the given configuration (default configuration if `None` provided) - /// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig) - pub fn new(config: Option) -> Result { - Ok(WakuNodeHandle { - ctx: management::waku_new(config)?, - }) - } - +/// Spawn a new Waku node with the given configuration (default configuration if `None` provided) +/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig) +pub fn waku_new(config: Option) -> Result> { + Ok(WakuNodeHandle { + ctx: management::waku_new(config)?, + phantom: PhantomData, + }) +} +impl WakuNodeHandle { /// Start a Waku node mounting all the protocols that were enabled during the Waku node instantiation. /// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_start) - pub fn start(&self) -> Result<()> { - management::waku_start(&self.ctx) + pub fn start(self) -> Result> { + management::waku_start(&self.ctx).map(|_| WakuNodeHandle { + ctx: self.ctx, + phantom: PhantomData, + }) } +} +impl WakuNodeHandle { /// Stops a Waku node /// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop) - pub fn stop(&self) -> Result<()> { - management::waku_stop(&self.ctx) + pub fn stop(self) -> Result> { + management::waku_stop(&self.ctx).map(|_| WakuNodeHandle { + ctx: self.ctx, + phantom: PhantomData, + }) } /// Get the multiaddresses the Waku node is listening to diff --git a/waku-bindings/src/utils.rs b/waku-bindings/src/utils.rs index ac5250a..8e50cba 100644 --- a/waku-bindings/src/utils.rs +++ b/waku-bindings/src/utils.rs @@ -22,7 +22,10 @@ impl TryFrom<(u32, &str)> for LibwakuResponse { let opt_value = Some(response.to_string()).filter(|s| !s.is_empty()); match ret_code { RET_OK => Ok(LibwakuResponse::Success(opt_value)), - RET_ERR => Ok(LibwakuResponse::Failure(format!("waku error: {}", response))), + RET_ERR => Ok(LibwakuResponse::Failure(format!( + "waku error: {}", + response + ))), RET_MISSING_CALLBACK => Ok(LibwakuResponse::MissingCallback), _ => Err(format!("undefined return code {}", ret_code)), } @@ -98,7 +101,7 @@ pub fn handle_response(code: i32, result: LibwakuResponse) -> Result LibwakuResponse::Success(v) => v .unwrap_or_default() .parse() - .map_err(|_| format!("could not parse value")), + .map_err(|_| "could not parse value".into()), LibwakuResponse::Failure(v) => Err(v), LibwakuResponse::MissingCallback => panic!("callback is required"), LibwakuResponse::Undefined => panic!( diff --git a/waku-bindings/tests/node.rs b/waku-bindings/tests/node.rs index b612951..9b6467c 100644 --- a/waku-bindings/tests/node.rs +++ b/waku-bindings/tests/node.rs @@ -7,7 +7,7 @@ use tokio::sync::broadcast::{self, Sender}; use tokio::time; use tokio::time::sleep; use waku_bindings::{ - Encoding, Event, MessageId, WakuContentTopic, WakuMessage, WakuNodeConfig, + waku_new, Encoding, Event, MessageId, Running, WakuContentTopic, WakuMessage, WakuNodeConfig, WakuNodeHandle, }; const ECHO_TIMEOUT: u64 = 10; @@ -15,13 +15,14 @@ const ECHO_MESSAGE: &str = "Hi from 🦀!"; const TEST_PUBSUBTOPIC: &str = "test"; fn try_publish_relay_messages( - node: &WakuNodeHandle, + node: &WakuNodeHandle, msg: &WakuMessage, ) -> Result, String> { let topic = TEST_PUBSUBTOPIC.to_string(); Ok(HashSet::from([ node.relay_publish_message(msg, &topic, None)? - ]))} + ])) +} #[derive(Debug, Clone)] struct Response { @@ -29,7 +30,7 @@ struct Response { payload: Vec, } -fn set_callback(node: &WakuNodeHandle, tx: Sender) { +fn set_callback(node: &WakuNodeHandle, tx: Sender) { node.set_event_callback(move |event| { if let Event::WakuMessage(message) = event { let id = message.message_id; @@ -46,8 +47,8 @@ fn set_callback(node: &WakuNodeHandle, tx: Sender) { } async fn test_echo_messages( - node1: &WakuNodeHandle, - node2: &WakuNodeHandle, + node1: &WakuNodeHandle, + node2: &WakuNodeHandle, content: &'static str, content_topic: WakuContentTopic, ) { @@ -86,17 +87,17 @@ async fn test_echo_messages( #[tokio::test] #[serial] async fn default_echo() -> Result<(), String> { - let node1 = WakuNodeHandle::new(Some(WakuNodeConfig { + let node1 = waku_new(Some(WakuNodeConfig { port: Some(60010), ..Default::default() }))?; - let node2 = WakuNodeHandle::new(Some(WakuNodeConfig { + let node2 = waku_new(Some(WakuNodeConfig { port: Some(60020), ..Default::default() }))?; - node1.start()?; - node2.start()?; + let node1 = node1.start()?; + let node2 = node2.start()?; let addresses1 = node1.listen_addresses()?; node2.connect(&addresses1[0], None)?; @@ -140,10 +141,10 @@ fn node_restart() { }; for _ in 0..3 { - let node = WakuNodeHandle::new(config.clone().into()).expect("default config should be valid"); + let node = waku_new(config.clone().into()).expect("default config should be valid"); - node.start().expect("node should start with valid config"); + let node = node.start().expect("node should start with valid config"); - node.stop().expect("node should stop"); + let node = node.stop().expect("node should stop"); } }