use crate::{Error, Result};
use zenoh::Session;
use zenoh::handlers::FifoChannelHandler;
#[derive(Debug, Clone)]
pub struct ServedQuery {
pub selector: String,
pub parameters: String,
pub payload: Option<zenoh::bytes::ZBytes>,
pub encoding: Option<String>,
pub attachment: Option<zenoh::bytes::ZBytes>,
pub reply_error: Option<String>,
}
pub struct MockResponder {
queryable: zenoh::query::Queryable<FifoChannelHandler<zenoh::query::Query>>,
keyexpr: String,
concrete: bool,
reply: Vec<u8>,
encoding: Option<String>,
}
impl std::fmt::Debug for MockResponder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MockResponder").finish_non_exhaustive()
}
}
pub async fn declare_responder(
session: &Session,
keyexpr: &str,
reply: Vec<u8>,
encoding: Option<&str>,
complete: bool,
) -> Result<MockResponder> {
let parsed = zenoh::key_expr::KeyExpr::try_from(keyexpr.to_string())
.map_err(|e| Error::bus("declare queryable", keyexpr, e))?;
let concrete = !parsed.is_wild();
let queryable = crate::bus::teardown::declared(
"declare queryable",
keyexpr,
session.declare_queryable(parsed).complete(complete),
)
.await?;
Ok(MockResponder {
queryable,
keyexpr: keyexpr.to_string(),
concrete,
reply,
encoding: encoding.map(str::to_string),
})
}
impl MockResponder {
pub async fn next(&self) -> Option<zenoh::query::Query> {
self.queryable.recv_async().await.ok()
}
pub fn stream(&self) -> impl futures_core::Stream<Item = zenoh::query::Query> + '_ {
self.queryable.stream()
}
pub async fn answer(&self, query: zenoh::query::Query) -> ServedQuery {
let mut view = ServedQuery {
selector: query.selector().to_string(),
parameters: query.parameters().to_string(),
payload: query.payload().cloned(),
encoding: query.encoding().map(|e| e.to_string()),
attachment: query.attachment().cloned(),
reply_error: None,
};
let key = if self.concrete {
self.keyexpr.clone()
} else {
query.key_expr().to_string()
};
let reply = query.reply(key, self.reply.clone());
let reply = match &self.encoding {
Some(e) => reply.encoding(e.as_str()),
None => reply,
};
view.reply_error = reply.await.err().map(|e| e.to_string());
view
}
pub async fn undeclare(self) -> Result<()> {
self.queryable
.undeclare()
.await
.map_err(|e| Error::bus("undeclare queryable", "", e))
}
}