1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::fmt;
4
5use crate::error::{Error, ErrorCode};
6
7pub const LATEST_PROTOCOL_VERSION: &str = "2025-03-26";
12
13pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] =
19 &[LATEST_PROTOCOL_VERSION, "2024-11-05", "2024-10-07"];
20
21pub const JSONRPC_VERSION: &str = "2.0";
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
32#[serde(untagged)]
33pub enum RequestId {
34 String(String),
36 Number(i64),
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct Request {
46 pub jsonrpc: String,
48 pub method: String,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub params: Option<Value>,
53 pub id: RequestId,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct Notification {
63 pub jsonrpc: String,
65 pub method: String,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub params: Option<Value>,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Response {
79 pub jsonrpc: String,
81 pub id: RequestId,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub result: Option<Value>,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub error: Option<ResponseError>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct ResponseError {
96 pub code: i32,
98 pub message: String,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub data: Option<Value>,
103}
104
105impl Request {
106 pub fn new(method: impl Into<String>, params: Option<Value>, id: RequestId) -> Self {
118 Self {
119 jsonrpc: crate::JSONRPC_VERSION.to_string(),
120 method: method.into(),
121 params,
122 id,
123 }
124 }
125}
126
127impl Notification {
128 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
139 Self {
140 jsonrpc: crate::JSONRPC_VERSION.to_string(),
141 method: method.into(),
142 params,
143 }
144 }
145}
146
147impl Response {
148 pub fn success(id: RequestId, result: Option<Value>) -> Self {
159 Self {
160 jsonrpc: crate::JSONRPC_VERSION.to_string(),
161 id,
162 result,
163 error: None,
164 }
165 }
166
167 pub fn error(id: RequestId, error: ResponseError) -> Self {
178 Self {
179 jsonrpc: crate::JSONRPC_VERSION.to_string(),
180 id,
181 result: None,
182 error: Some(error),
183 }
184 }
185}
186
187impl From<Error> for ResponseError {
188 fn from(err: Error) -> Self {
189 match err {
190 Error::Protocol {
191 code,
192 message,
193 data,
194 } => ResponseError {
195 code: code.into(),
196 message,
197 data,
198 },
199 Error::Transport(msg) => ResponseError {
200 code: ErrorCode::InternalError.into(),
201 message: format!("Transport error: {}", msg),
202 data: None,
203 },
204 Error::Serialization(err) => ResponseError {
205 code: ErrorCode::ParseError.into(),
206 message: err.to_string(),
207 data: None,
208 },
209 Error::Io(err) => ResponseError {
210 code: ErrorCode::InternalError.into(),
211 message: err.to_string(),
212 data: None,
213 },
214 Error::Other(msg) => ResponseError {
215 code: ErrorCode::InternalError.into(),
216 message: msg,
217 data: None,
218 },
219 }
220 }
221}
222
223impl fmt::Display for RequestId {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 RequestId::String(s) => write!(f, "{}", s),
230 RequestId::Number(n) => write!(f, "{}", n),
231 }
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238 use serde_json::json;
239
240 #[test]
241 fn test_request_creation() {
242 let id = RequestId::Number(1);
243 let params = Some(json!({"key": "value"}));
244 let request = Request::new("test_method", params.clone(), id.clone());
245
246 assert_eq!(request.jsonrpc, JSONRPC_VERSION);
247 assert_eq!(request.method, "test_method");
248 assert_eq!(request.params, params);
249 assert_eq!(request.id, id);
250 }
251
252 #[test]
253 fn test_notification_creation() {
254 let params = Some(json!({"event": "update"}));
255 let notification = Notification::new("test_event", params.clone());
256
257 assert_eq!(notification.jsonrpc, JSONRPC_VERSION);
258 assert_eq!(notification.method, "test_event");
259 assert_eq!(notification.params, params);
260 }
261
262 #[test]
263 fn test_response_success() {
264 let id = RequestId::String("test-1".to_string());
265 let result = Some(json!({"status": "ok"}));
266 let response = Response::success(id.clone(), result.clone());
267
268 assert_eq!(response.jsonrpc, JSONRPC_VERSION);
269 assert_eq!(response.id, id);
270 assert_eq!(response.result, result);
271 assert!(response.error.is_none());
272 }
273
274 #[test]
275 fn test_response_error() {
276 let id = RequestId::Number(123);
277 let error = ResponseError {
278 code: -32600,
279 message: "Invalid Request".to_string(),
280 data: Some(json!({"details": "missing method"})),
281 };
282 let response = Response::error(id.clone(), error.clone());
283
284 assert_eq!(response.jsonrpc, JSONRPC_VERSION);
285 assert_eq!(response.id, id);
286 assert!(response.result.is_none());
287
288 let response_error = response.error.unwrap();
289 assert_eq!(response_error.code, error.code);
290 assert_eq!(response_error.message, error.message);
291 }
292
293 #[test]
294 fn test_request_id_display() {
295 let num_id = RequestId::Number(42);
296 let str_id = RequestId::String("test-id".to_string());
297
298 assert_eq!(num_id.to_string(), "42");
299 assert_eq!(str_id.to_string(), "test-id");
300 }
301
302 #[test]
303 fn test_protocol_versions() {
304 assert!(SUPPORTED_PROTOCOL_VERSIONS.contains(&LATEST_PROTOCOL_VERSION));
305 assert_eq!(JSONRPC_VERSION, "2.0");
306 }
307}