use anyhow::{Context, Result};
use zenoh::config::WhatAmIMatcher;
use zenoh::handlers::FifoChannelHandler;
use zenoh::scouting::Hello;
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub struct HelloView {
pub zid: String,
pub whatami: String,
pub locators: Vec<String>,
}
impl HelloView {
fn of(hello: &Hello) -> Self {
HelloView {
zid: hello.zid().to_string(),
whatami: hello.whatami().to_string(),
locators: hello.locators().iter().map(|l| l.to_string()).collect(),
}
}
}
pub struct ScoutStream {
inner: zenoh::scouting::Scout<FifoChannelHandler<Hello>>,
}
impl std::fmt::Debug for ScoutStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScoutStream").finish_non_exhaustive()
}
}
impl ScoutStream {
pub async fn recv(&self) -> Option<HelloView> {
self.inner
.recv_async()
.await
.ok()
.map(|h| HelloView::of(&h))
}
pub fn stop(self) {
self.inner.stop();
}
}
pub async fn scout(
what: WhatAmIMatcher,
connect: &[String],
listen: &[String],
) -> Result<ScoutStream> {
let config = crate::session::explorer_config(connect, listen, true);
let inner = zenoh::scout(what, config)
.await
.map_err(|e| anyhow::anyhow!("{e}"))
.context("failed to start scouting")?;
Ok(ScoutStream { inner })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_hello_serializes_flat_and_stable() {
let view = HelloView {
zid: "a1b2".into(),
whatami: "router".into(),
locators: vec!["tcp/10.0.0.1:7447".into()],
};
let json = serde_json::to_value(&view).unwrap();
assert_eq!(
json,
serde_json::json!({
"zid": "a1b2",
"whatami": "router",
"locators": ["tcp/10.0.0.1:7447"],
})
);
}
}