refactor: add back typestate

This commit is contained in:
Richard Ramos 2024-02-28 17:09:14 -04:00
parent cdfac7fdfb
commit 122b75c6a1
No known key found for this signature in database
GPG Key ID: 1CE87DB518195760
5 changed files with 61 additions and 38 deletions

View File

@ -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};

View File

@ -41,13 +41,10 @@ pub struct WakuMessageEvent {
/// which are used to react to asynchronous events in Waku
pub fn waku_set_event_callback<F: FnMut(Event) + Send + Sync>(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);
};
};

View File

@ -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<State: WakuNodeState> {
ctx: WakuNodeContext,
phantom: PhantomData<State>,
}
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<WakuNodeConfig>) -> Result<WakuNodeHandle> {
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<WakuNodeConfig>) -> Result<WakuNodeHandle<Initialized>> {
Ok(WakuNodeHandle {
ctx: management::waku_new(config)?,
phantom: PhantomData,
})
}
impl WakuNodeHandle<Initialized> {
/// 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<WakuNodeHandle<Running>> {
management::waku_start(&self.ctx).map(|_| WakuNodeHandle {
ctx: self.ctx,
phantom: PhantomData,
})
}
}
impl WakuNodeHandle<Running> {
/// 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<WakuNodeHandle<Initialized>> {
management::waku_stop(&self.ctx).map(|_| WakuNodeHandle {
ctx: self.ctx,
phantom: PhantomData,
})
}
/// Get the multiaddresses the Waku node is listening to

View File

@ -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<F: FromStr>(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!(

View File

@ -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<Running>,
msg: &WakuMessage,
) -> Result<HashSet<MessageId>, 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<u8>,
}
fn set_callback(node: &WakuNodeHandle, tx: Sender<Response>) {
fn set_callback(node: &WakuNodeHandle<Running>, tx: Sender<Response>) {
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<Response>) {
}
async fn test_echo_messages(
node1: &WakuNodeHandle,
node2: &WakuNodeHandle,
node1: &WakuNodeHandle<Running>,
node2: &WakuNodeHandle<Running>,
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");
}
}