1use serde::{Deserialize, Serialize};
2use std::sync::Arc;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct IpcMessage {
7 pub id: String,
9
10 pub cmd: String,
12
13 pub payload: serde_json::Value,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct IpcResponse {
20 pub id: String,
22
23 pub success: bool,
25
26 pub data: serde_json::Value,
28}
29
30pub type IpcResponseSender = Arc<dyn Fn(IpcResponse) + Send + Sync + 'static>;
35
36pub trait IpcHandler: Send + Sync {
38 fn handle(&self, message: IpcMessage) -> IpcResponse;
40
41 fn handle_async(&self, message: IpcMessage, respond: IpcResponseSender) {
49 respond(self.handle(message));
50 }
51}
52
53pub struct FnIpcHandler<F>
55where
56 F: Fn(IpcMessage) -> IpcResponse + Send + Sync,
57{
58 handler: F,
59}
60
61impl<F> FnIpcHandler<F>
62where
63 F: Fn(IpcMessage) -> IpcResponse + Send + Sync,
64{
65 pub fn new(handler: F) -> Self {
66 Self { handler }
67 }
68}
69
70impl<F> IpcHandler for FnIpcHandler<F>
71where
72 F: Fn(IpcMessage) -> IpcResponse + Send + Sync,
73{
74 fn handle(&self, message: IpcMessage) -> IpcResponse {
75 (self.handler)(message)
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::{FnIpcHandler, IpcHandler, IpcMessage, IpcResponse, IpcResponseSender};
82 use serde_json::json;
83 use std::sync::{Arc, Mutex};
84
85 #[test]
86 fn default_async_dispatch_preserves_sync_handler_contract() {
87 let handler = FnIpcHandler::new(|message: IpcMessage| IpcResponse {
88 id: message.id,
89 success: true,
90 data: json!({ "method": message.cmd }),
91 });
92 let received = Arc::new(Mutex::new(None));
93 let sink_target = received.clone();
94 let sink: IpcResponseSender = Arc::new(move |response| {
95 *sink_target.lock().unwrap() = Some(response);
96 });
97
98 handler.handle_async(
99 IpcMessage {
100 id: "async-1".to_string(),
101 cmd: "ping".to_string(),
102 payload: json!({}),
103 },
104 sink,
105 );
106
107 let response = received.lock().unwrap().take().unwrap();
108 assert_eq!(response.id, "async-1");
109 assert_eq!(response.data["method"], "ping");
110 }
111}