1use std::sync::atomic::{AtomicU64, Ordering};
2use std::sync::Arc;
3use std::time::Duration;
4
5use dashmap::DashMap;
6use serde::de::DeserializeOwned;
7use serde::Serialize;
8use tokio::io::{AsyncBufRead, AsyncWrite};
9use tokio::sync::{mpsc, oneshot};
10use tracing::{debug, error, warn};
11
12use zerolaunch_plugin_protocol::{codes, JsonRpcError, Message, ProtocolError, Request, Response};
13
14use crate::transport::codec;
15
16#[derive(Debug)]
21pub struct IncomingRequest {
22 pub id: u64,
23 pub method: String,
24 pub params: serde_json::Value,
25}
26
27#[derive(Debug)]
29pub struct JsonRpcClient {
30 next_id: AtomicU64,
31 pending: Arc<DashMap<u64, oneshot::Sender<Result<serde_json::Value, JsonRpcError>>>>,
32 outbound_tx: mpsc::Sender<Message>,
33 _read_handle: tokio::task::JoinHandle<()>,
35 _write_handle: tokio::task::JoinHandle<()>,
37}
38
39impl JsonRpcClient {
40 pub fn new<R, W>(
47 reader: R,
48 writer: W,
49 incoming_request_tx: mpsc::Sender<IncomingRequest>,
50 incoming_notification_tx: mpsc::Sender<(String, serde_json::Value)>,
51 ) -> Arc<Self>
52 where
53 R: AsyncBufRead + Send + Unpin + 'static,
54 W: AsyncWrite + Send + Unpin + 'static,
55 {
56 let pending: Arc<DashMap<u64, oneshot::Sender<Result<serde_json::Value, JsonRpcError>>>> =
57 Arc::new(DashMap::new());
58
59 let (outbound_tx, outbound_rx) = mpsc::channel::<Message>(256);
61
62 let pending_r = pending.clone();
64 let read_handle = tokio::spawn(async move {
65 let mut reader = reader;
66 loop {
67 let frame = match codec::read_frame(&mut reader).await {
68 Ok(f) => f,
69 Err(ProtocolError::TransportClosed) => {
70 debug!("Transport closed (read loop)");
71 break;
72 }
73 Err(e) => {
74 error!("Frame read error: {}", e);
75 break;
76 }
77 };
78
79 debug!(
80 "收到插件原始帧 ({} bytes): {:?}",
81 frame.len(),
82 String::from_utf8_lossy(&frame)
83 );
84
85 let msg: Message = match serde_json::from_slice(&frame) {
86 Ok(m) => m,
87 Err(e) => {
88 warn!(
89 "Failed to parse JSON-RPC message: {}; raw frame ({} bytes): {:?}",
90 e,
91 frame.len(),
92 String::from_utf8_lossy(&frame)
93 );
94 continue;
95 }
96 };
97 debug!(
98 "收到插件消息 ({} bytes): {:?}",
99 frame.len(),
100 zerolaunch_plugin_protocol::codec::summarize_message(&msg)
101 );
102
103 match msg {
104 Message::Response(resp) => {
105 if let Some((_, tx)) = pending_r.remove(&resp.id) {
106 let result = if let Some(err) = resp.error {
107 Err(err)
108 } else {
109 Ok(resp.result.unwrap_or(serde_json::Value::Null))
110 };
111 let _ = tx.send(result);
112 } else {
113 debug!("Response for unknown id: {}", resp.id);
115 }
116 }
117 Message::Request(req) => {
118 let incoming = IncomingRequest {
119 id: req.id,
120 method: req.method,
121 params: req.params,
122 };
123 if incoming_request_tx.send(incoming).await.is_err() {
124 debug!("Incoming request channel closed");
125 }
126 }
127 Message::Notification(notif) => {
128 if incoming_notification_tx
129 .send((notif.method, notif.params))
130 .await
131 .is_err()
132 {
133 debug!("Incoming notification channel closed");
134 }
135 }
136 }
137 }
138
139 let keys: Vec<u64> = pending_r.iter().map(|e| *e.key()).collect();
141 for key in keys {
142 if let Some((_, tx)) = pending_r.remove(&key) {
143 let _ = tx.send(Err(JsonRpcError::new(
144 codes::PLUGIN_CRASHED,
145 "transport closed",
146 )));
147 }
148 }
149 });
150
151 let write_handle = tokio::spawn(async move {
153 let mut writer = writer;
154 let mut rx = outbound_rx;
155 while let Some(msg) = rx.recv().await {
156 debug!(
157 "发送给插件的消息: {:?}",
158 zerolaunch_plugin_protocol::codec::summarize_message(&msg)
159 );
160 let payload = match serde_json::to_vec(&msg) {
161 Ok(p) => p,
162 Err(e) => {
163 error!("Failed to serialize message: {}", e);
164 continue;
165 }
166 };
167 if let Err(e) = codec::write_frame(&mut writer, &payload).await {
168 error!("Failed to write frame: {}", e);
169 break;
170 }
171 }
172 });
173
174 Arc::new(Self {
175 next_id: AtomicU64::new(1),
176 pending,
177 outbound_tx,
178 _read_handle: read_handle,
179 _write_handle: write_handle,
180 })
181 }
182
183 pub fn close_transport(&self) {
186 self._write_handle.abort();
187 }
188
189 pub async fn call<P: Serialize, R: DeserializeOwned>(
191 &self,
192 method: &str,
193 params: P,
194 timeout: Duration,
195 ) -> Result<R, ProtocolError> {
196 let id = self.next_id.fetch_add(1, Ordering::SeqCst);
197 let params_value = serde_json::to_value(params)?;
198
199 let (tx, rx) = oneshot::channel();
200 self.pending.insert(id, tx);
201
202 let request = Request::new(id, method, params_value);
203 tokio::time::timeout(
206 Duration::from_secs(5),
207 self.outbound_tx.send(Message::Request(request)),
208 )
209 .await
210 .map_err(|_| ProtocolError::TransportClosed)?
211 .map_err(|_| ProtocolError::TransportClosed)?;
212
213 match tokio::time::timeout(timeout, rx).await {
214 Ok(Ok(Ok(value))) => {
215 let result: R = serde_json::from_value(value)?;
216 Ok(result)
217 }
218 Ok(Ok(Err(err))) => Err(ProtocolError::Rpc {
219 code: err.code,
220 message: err.message,
221 }),
222 Ok(Err(_)) => {
223 self.pending.remove(&id);
224 Err(ProtocolError::TransportClosed)
225 }
226 Err(_) => {
227 self.pending.remove(&id);
228 Err(ProtocolError::Timeout)
229 }
230 }
231 }
232
233 pub async fn notify<P: Serialize>(&self, method: &str, params: P) -> Result<(), ProtocolError> {
235 let params_value = serde_json::to_value(params)?;
236 let notif = zerolaunch_plugin_protocol::Notification::new(method, params_value);
237 tokio::time::timeout(
238 Duration::from_secs(5),
239 self.outbound_tx.send(Message::Notification(notif)),
240 )
241 .await
242 .map_err(|_| ProtocolError::TransportClosed)?
243 .map_err(|_| ProtocolError::TransportClosed)?;
244 Ok(())
245 }
246
247 pub async fn respond_ok(
249 &self,
250 id: u64,
251 result: serde_json::Value,
252 ) -> Result<(), ProtocolError> {
253 let response = Response::ok(id, result);
254 tokio::time::timeout(
255 Duration::from_secs(5),
256 self.outbound_tx.send(Message::Response(response)),
257 )
258 .await
259 .map_err(|_| ProtocolError::TransportClosed)?
260 .map_err(|_| ProtocolError::TransportClosed)?;
261 Ok(())
262 }
263
264 pub async fn respond_err(&self, id: u64, error: JsonRpcError) -> Result<(), ProtocolError> {
266 let response = Response::err(id, error);
267 tokio::time::timeout(
268 Duration::from_secs(5),
269 self.outbound_tx.send(Message::Response(response)),
270 )
271 .await
272 .map_err(|_| ProtocolError::TransportClosed)?
273 .map_err(|_| ProtocolError::TransportClosed)?;
274 Ok(())
275 }
276}