Skip to main content

json_rpc/
types.rs

1//! JSON-RPC 2.0 message types.
2//!
3//! This module defines JSON-RPC 2.0 message types as specified in:
4//! https://www.jsonrpc.org/specification
5
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9use tracing::debug;
10
11use crate::error::Error as InternalError;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Request {
15    pub jsonrpc: String,
16    pub id: RequestId,
17    pub method: String,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub params: Option<serde_json::Value>,
20}
21
22impl Request {
23    pub fn new(
24        id: RequestId,
25        method: impl Into<String>,
26        params: Option<serde_json::Value>,
27    ) -> Self {
28        Self {
29            jsonrpc: "2.0".to_string(),
30            id,
31            method: method.into(),
32            params,
33        }
34    }
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct Response {
39    pub jsonrpc: String,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub result: Option<serde_json::Value>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub error: Option<Error>,
44    pub id: RequestId,
45}
46
47impl Response {
48    pub fn success(id: RequestId, result: serde_json::Value) -> Self {
49        Self {
50            jsonrpc: "2.0".to_string(),
51            id,
52            result: Some(result),
53            error: None,
54        }
55    }
56
57    pub fn error(id: RequestId, error: Error) -> Self {
58        Self {
59            jsonrpc: "2.0".to_string(),
60            id,
61            result: None,
62            error: Some(error),
63        }
64    }
65
66    pub fn validate(&self) -> Result<(), String> {
67        match (&self.result, &self.error) {
68            (Some(_), Some(_)) => Err("Response cannot have both result and error".to_string()),
69            (None, None) => Err("Response must have either result or error".to_string()),
70            _ => Ok(()),
71        }
72    }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Notification {
77    pub jsonrpc: String,
78    pub method: String,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub params: Option<serde_json::Value>,
81}
82
83impl Notification {
84    pub fn new(method: impl Into<String>, params: Option<serde_json::Value>) -> Self {
85        Self {
86            jsonrpc: "2.0".to_string(),
87            method: method.into(),
88            params,
89        }
90    }
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct Error {
95    pub code: i32,
96    pub message: String,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub data: Option<serde_json::Value>,
99}
100
101impl Error {
102    pub fn new(code: i32, message: impl Into<String>, data: Option<serde_json::Value>) -> Self {
103        Self {
104            code,
105            message: message.into(),
106            data,
107        }
108    }
109
110    pub fn parse_error(message: impl Into<String>) -> Self {
111        Self::new(-32700, message, None)
112    }
113
114    pub fn invalid_request(message: impl Into<String>) -> Self {
115        Self::new(-32600, message, None)
116    }
117
118    pub fn method_not_found(message: impl Into<String>) -> Self {
119        Self::new(-32601, message, None)
120    }
121
122    pub fn invalid_params(message: impl Into<String>) -> Self {
123        Self::new(-32602, message, None)
124    }
125
126    pub fn internal_error(message: impl Into<String>) -> Self {
127        Self::new(-32603, message, None)
128    }
129}
130
131impl fmt::Display for Error {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(f, "JSON-RPC error {}: {}", self.code, self.message)
134    }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
138#[serde(untagged)]
139pub enum RequestId {
140    Null,
141    Number(u64),
142    String(String),
143}
144
145impl fmt::Display for RequestId {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        match self {
148            RequestId::Null => write!(f, "null"),
149            RequestId::Number(n) => write!(f, "{}", n),
150            RequestId::String(s) => write!(f, "{}", s),
151        }
152    }
153}
154
155#[derive(Debug, Clone)]
156pub enum Message {
157    Request(Request),
158    Response(Response),
159    Notification(Notification),
160    Batch(Vec<Message>),
161}
162
163impl Message {
164    /// Extract a RequestId from a JSON value, if present.
165    fn extract_request_id(value: &serde_json::Value) -> Option<RequestId> {
166        value.get("id").and_then(|id_value| match id_value {
167            serde_json::Value::Null => Some(RequestId::Null),
168            serde_json::Value::Number(n) => n.as_u64().map(RequestId::Number),
169            serde_json::Value::String(s) => {
170                let id_str = s.to_string();
171                Some(RequestId::String(id_str))
172            }
173            _ => None,
174        })
175    }
176
177    pub fn from_json(value: serde_json::Value) -> Result<Self, InternalError> {
178        debug!("Parsing JSON value: {:?}", value);
179        let value_ref = &value;
180
181        if let Some(arr) = value_ref.as_array() {
182            debug!("Detected batch request with {} items", arr.len());
183            if arr.is_empty() {
184                debug!("Empty array detected - returning Invalid Request error");
185                return Err(InternalError::invalid_request("Invalid Request"));
186            }
187
188            let mut messages = Vec::new();
189            for (index, item) in arr.iter().enumerate() {
190                debug!("Processing batch item {}: {:?}", index, item);
191                match Self::from_json_internal(item.clone()) {
192                    Ok(msg) => {
193                        debug!("Batch item {} parsed successfully", index);
194                        messages.push(msg);
195                    }
196                    Err(e) => {
197                        debug!("Batch item {} failed to parse: {:?}", index, e);
198                        let id = Self::extract_request_id(item);
199                        if let Some(id) = id {
200                            let error_response =
201                                Response::error(id, Error::invalid_request("Invalid Request"));
202                            messages.push(Message::Response(error_response));
203                        } else if item.get("method").is_some() {
204                            debug!(
205                                "Batch item {} is a notification (has method but no id), skipping",
206                                index
207                            );
208                        } else {
209                            debug!(
210                                "Batch item {} is invalid (no id or method), creating error response",
211                                index
212                            );
213                            let error_response = Response::error(
214                                RequestId::Null,
215                                Error::invalid_request("Invalid Request"),
216                            );
217                            messages.push(Message::Response(error_response));
218                        }
219                    }
220                }
221            }
222            debug!("Batch parsing complete, {} messages", messages.len());
223            return Ok(Message::Batch(messages));
224        }
225
226        if value_ref.get("id").is_some() {
227            debug!("Message has 'id' field, checking for error/method");
228            if value_ref.get("error").is_some() {
229                debug!("Message has 'error' field, parsing as Response");
230                serde_json::from_value(value)
231                    .map(Message::Response)
232                    .map_err(|e| {
233                        debug!("Failed to parse as Response: {}", e);
234                        InternalError::invalid_request("Invalid Request")
235                    })
236            } else if value_ref.get("method").is_some() {
237                debug!("Message has 'method' field, parsing as Request");
238                let req: Request = serde_json::from_value(value).map_err(|e| {
239                    debug!("Failed to deserialize as Request: {}", e);
240                    InternalError::invalid_request("Invalid Request")
241                })?;
242
243                if req.jsonrpc != "2.0" {
244                    debug!("Invalid jsonrpc value: '{}', expected '2.0'", req.jsonrpc);
245                    return Err(InternalError::invalid_request("Invalid Request"));
246                }
247
248                debug!("Request parsed successfully: {}", req.method);
249                Ok(Message::Request(req))
250            } else {
251                debug!("Message has 'id' but no 'method' or 'error' - Invalid Request");
252                Err(InternalError::invalid_request("Invalid Request"))
253            }
254        } else {
255            debug!("Message has no 'id' field, parsing as Notification");
256            let notif: Notification = serde_json::from_value(value).map_err(|e| {
257                debug!("Failed to deserialize as Notification: {}", e);
258                InternalError::invalid_request("Invalid Request")
259            })?;
260
261            if notif.jsonrpc != "2.0" {
262                debug!("Invalid jsonrpc value: '{}', expected '2.0'", notif.jsonrpc);
263                return Err(InternalError::invalid_request("Invalid Request"));
264            }
265
266            debug!("Notification parsed successfully: {}", notif.method);
267            Ok(Message::Notification(notif))
268        }
269    }
270
271    pub fn to_json(&self) -> Result<serde_json::Value, serde_json::Error> {
272        match self {
273            Message::Request(req) => serde_json::to_value(req),
274            Message::Response(res) => serde_json::to_value(res),
275            Message::Notification(notif) => serde_json::to_value(notif),
276            Message::Batch(messages) => {
277                let json_array: Result<Vec<serde_json::Value>, serde_json::Error> =
278                    messages.iter().map(|m| m.to_json()).collect();
279                Ok(serde_json::Value::Array(json_array?))
280            }
281        }
282    }
283
284    pub fn id(&self) -> Option<&RequestId> {
285        match self {
286            Message::Request(req) => Some(&req.id),
287            Message::Response(res) => Some(&res.id),
288            Message::Notification(_) => None,
289            Message::Batch(_) => None,
290        }
291    }
292
293    pub fn is_request(&self) -> bool {
294        matches!(self, Message::Request(_))
295    }
296
297    pub fn is_response(&self) -> bool {
298        matches!(self, Message::Response(_))
299    }
300
301    pub fn is_notification(&self) -> bool {
302        matches!(self, Message::Notification(_))
303    }
304
305    pub fn is_batch(&self) -> bool {
306        matches!(self, Message::Batch(_))
307    }
308
309    fn from_json_internal(value: serde_json::Value) -> Result<Self, InternalError> {
310        if value.get("id").is_some() {
311            if value.get("error").is_some() {
312                serde_json::from_value(value)
313                    .map(Message::Response)
314                    .map_err(|_| InternalError::invalid_request("Invalid Request"))
315            } else if value.get("method").is_some() {
316                serde_json::from_value::<Request>(value)
317                    .map(|req| {
318                        if req.jsonrpc != "2.0" {
319                            return Err(InternalError::invalid_request("Invalid Request"));
320                        }
321                        Ok(Message::Request(req))
322                    })
323                    .map_err(|_| InternalError::invalid_request("Invalid Request"))?
324            } else {
325                Err(InternalError::invalid_request("Invalid Request"))
326            }
327        } else {
328            serde_json::from_value::<Notification>(value)
329                .map(|notif| {
330                    if notif.jsonrpc != "2.0" {
331                        return Err(InternalError::invalid_request("Invalid Request"));
332                    }
333                    Ok(Message::Notification(notif))
334                })
335                .map_err(|_| InternalError::invalid_request("Invalid Request"))?
336        }
337    }
338}