use std::any::Any;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::error::Error;
pub struct HandlerContext {
pub app_handle: Arc<dyn Any + Send + Sync>,
pub webview_label: Option<String>,
}
impl HandlerContext {
pub fn new(app_handle: Arc<dyn Any + Send + Sync>, webview_label: Option<String>) -> Self {
Self {
app_handle,
webview_label,
}
}
}
pub enum HandlerResponse {
Sync(Result<Vec<u8>, Error>),
Async(Pin<Box<dyn Future<Output = Result<Vec<u8>, Error>> + Send>>),
}
pub trait ConduitHandler: Send + Sync + 'static {
fn call(&self, payload: Vec<u8>, ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse;
}
#[cfg(test)]
mod tests {
use super::*;
struct EchoHandler;
impl ConduitHandler for EchoHandler {
fn call(&self, payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
HandlerResponse::Sync(Ok(payload))
}
}
struct AsyncEchoHandler;
impl ConduitHandler for AsyncEchoHandler {
fn call(&self, payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
HandlerResponse::Async(Box::pin(async move { Ok(payload) }))
}
}
struct FailHandler;
impl ConduitHandler for FailHandler {
fn call(&self, _payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
HandlerResponse::Sync(Err(Error::Handler("intentional".into())))
}
}
#[test]
fn sync_handler_returns_payload() {
let h = EchoHandler;
let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
match h.call(b"hello".to_vec(), ctx) {
HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"hello"),
_ => panic!("expected Sync(Ok)"),
}
}
#[test]
fn async_handler_returns_future() {
let h = AsyncEchoHandler;
let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
match h.call(b"world".to_vec(), ctx) {
HandlerResponse::Async(_) => {} _ => panic!("expected Async"),
}
}
#[test]
fn sync_handler_error_variant() {
let h = FailHandler;
let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
match h.call(vec![], ctx) {
HandlerResponse::Sync(Err(Error::Handler(msg))) => {
assert_eq!(msg, "intentional");
}
_ => panic!("expected Sync(Err(Handler))"),
}
}
#[test]
fn handler_context_downcast() {
struct CtxHandler;
impl ConduitHandler for CtxHandler {
fn call(&self, _payload: Vec<u8>, ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
if ctx.downcast_ref::<String>().is_some() {
HandlerResponse::Sync(Ok(b"got string".to_vec()))
} else {
HandlerResponse::Sync(Ok(b"no string".to_vec()))
}
}
}
let h = CtxHandler;
let ctx: Arc<dyn Any + Send + Sync> = Arc::new(String::from("hello"));
match h.call(vec![], ctx) {
HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"got string"),
_ => panic!("expected Sync(Ok)"),
}
let ctx2: Arc<dyn Any + Send + Sync> = Arc::new(());
match h.call(vec![], ctx2) {
HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"no string"),
_ => panic!("expected Sync(Ok)"),
}
}
}