1use std::any::Any;
8use std::future::Future;
9use std::pin::Pin;
10use std::sync::Arc;
11
12use crate::error::Error;
13
14pub struct HandlerContext {
24 pub app_handle: Arc<dyn Any + Send + Sync>,
26 pub webview_label: Option<String>,
28}
29
30impl HandlerContext {
31 pub fn new(app_handle: Arc<dyn Any + Send + Sync>, webview_label: Option<String>) -> Self {
33 Self {
34 app_handle,
35 webview_label,
36 }
37 }
38}
39
40pub enum HandlerResponse {
46 Sync(Result<Vec<u8>, Error>),
48 Async(Pin<Box<dyn Future<Output = Result<Vec<u8>, Error>> + Send>>),
50}
51
52pub trait ConduitHandler: Send + Sync + 'static {
80 fn call(&self, payload: Vec<u8>, ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse;
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 struct EchoHandler;
93
94 impl ConduitHandler for EchoHandler {
95 fn call(&self, payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
96 HandlerResponse::Sync(Ok(payload))
97 }
98 }
99
100 struct AsyncEchoHandler;
101
102 impl ConduitHandler for AsyncEchoHandler {
103 fn call(&self, payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
104 HandlerResponse::Async(Box::pin(async move { Ok(payload) }))
105 }
106 }
107
108 struct FailHandler;
109
110 impl ConduitHandler for FailHandler {
111 fn call(&self, _payload: Vec<u8>, _ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
112 HandlerResponse::Sync(Err(Error::Handler("intentional".into())))
113 }
114 }
115
116 #[test]
117 fn sync_handler_returns_payload() {
118 let h = EchoHandler;
119 let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
120 match h.call(b"hello".to_vec(), ctx) {
121 HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"hello"),
122 _ => panic!("expected Sync(Ok)"),
123 }
124 }
125
126 #[test]
127 fn async_handler_returns_future() {
128 let h = AsyncEchoHandler;
129 let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
130 match h.call(b"world".to_vec(), ctx) {
131 HandlerResponse::Async(_) => {} _ => panic!("expected Async"),
133 }
134 }
135
136 #[test]
137 fn sync_handler_error_variant() {
138 let h = FailHandler;
139 let ctx: Arc<dyn Any + Send + Sync> = Arc::new(());
140 match h.call(vec![], ctx) {
141 HandlerResponse::Sync(Err(Error::Handler(msg))) => {
142 assert_eq!(msg, "intentional");
143 }
144 _ => panic!("expected Sync(Err(Handler))"),
145 }
146 }
147
148 #[test]
149 fn handler_context_downcast() {
150 struct CtxHandler;
151 impl ConduitHandler for CtxHandler {
152 fn call(&self, _payload: Vec<u8>, ctx: Arc<dyn Any + Send + Sync>) -> HandlerResponse {
153 if ctx.downcast_ref::<String>().is_some() {
154 HandlerResponse::Sync(Ok(b"got string".to_vec()))
155 } else {
156 HandlerResponse::Sync(Ok(b"no string".to_vec()))
157 }
158 }
159 }
160
161 let h = CtxHandler;
162 let ctx: Arc<dyn Any + Send + Sync> = Arc::new(String::from("hello"));
163 match h.call(vec![], ctx) {
164 HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"got string"),
165 _ => panic!("expected Sync(Ok)"),
166 }
167
168 let ctx2: Arc<dyn Any + Send + Sync> = Arc::new(());
169 match h.call(vec![], ctx2) {
170 HandlerResponse::Sync(Ok(bytes)) => assert_eq!(bytes, b"no string"),
171 _ => panic!("expected Sync(Ok)"),
172 }
173 }
174}