1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::fmt;
4
5use crate::error::{Error, ErrorCode};
6
7pub const LATEST_PROTOCOL_VERSION: &str = "2024-11-05";
12
13pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &[LATEST_PROTOCOL_VERSION, "2024-10-07"];
19
20pub const JSONRPC_VERSION: &str = "2.0";
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28#[serde(untagged)]
29pub enum RequestId {
30 String(String),
31 Number(i64),
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct Request {
37 pub jsonrpc: String,
38 pub method: String,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub params: Option<Value>,
41 pub id: RequestId,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct Notification {
47 pub jsonrpc: String,
48 pub method: String,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub params: Option<Value>,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct Response {
56 pub jsonrpc: String,
57 pub id: RequestId,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub result: Option<Value>,
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub error: Option<ResponseError>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct ResponseError {
67 pub code: i32,
68 pub message: String,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub data: Option<Value>,
71}
72
73impl Request {
74 pub fn new(method: impl Into<String>, params: Option<Value>, id: RequestId) -> Self {
75 Self {
76 jsonrpc: crate::JSONRPC_VERSION.to_string(),
77 method: method.into(),
78 params,
79 id,
80 }
81 }
82}
83
84impl Notification {
85 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
86 Self {
87 jsonrpc: crate::JSONRPC_VERSION.to_string(),
88 method: method.into(),
89 params,
90 }
91 }
92}
93
94impl Response {
95 pub fn success(id: RequestId, result: Option<Value>) -> Self {
96 Self {
97 jsonrpc: crate::JSONRPC_VERSION.to_string(),
98 id,
99 result,
100 error: None,
101 }
102 }
103
104 pub fn error(id: RequestId, error: ResponseError) -> Self {
105 Self {
106 jsonrpc: crate::JSONRPC_VERSION.to_string(),
107 id,
108 result: None,
109 error: Some(error),
110 }
111 }
112}
113
114impl From<Error> for ResponseError {
115 fn from(err: Error) -> Self {
116 match err {
117 Error::Protocol {
118 code,
119 message,
120 data,
121 } => ResponseError {
122 code: code.into(),
123 message,
124 data,
125 },
126 Error::Transport(msg) => ResponseError {
127 code: ErrorCode::InternalError.into(),
128 message: format!("Transport error: {}", msg),
129 data: None,
130 },
131 Error::Serialization(err) => ResponseError {
132 code: ErrorCode::ParseError.into(),
133 message: err.to_string(),
134 data: None,
135 },
136 Error::Io(err) => ResponseError {
137 code: ErrorCode::InternalError.into(),
138 message: err.to_string(),
139 data: None,
140 },
141 Error::Other(msg) => ResponseError {
142 code: ErrorCode::InternalError.into(),
143 message: msg,
144 data: None,
145 },
146 }
147 }
148}
149
150impl fmt::Display for RequestId {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 match self {
153 RequestId::String(s) => write!(f, "{}", s),
154 RequestId::Number(n) => write!(f, "{}", n),
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use serde_json::json;
163
164 #[test]
165 fn test_request_creation() {
166 let id = RequestId::Number(1);
167 let params = Some(json!({"key": "value"}));
168 let request = Request::new("test_method", params.clone(), id.clone());
169
170 assert_eq!(request.jsonrpc, JSONRPC_VERSION);
171 assert_eq!(request.method, "test_method");
172 assert_eq!(request.params, params);
173 assert_eq!(request.id, id);
174 }
175
176 #[test]
177 fn test_notification_creation() {
178 let params = Some(json!({"event": "update"}));
179 let notification = Notification::new("test_event", params.clone());
180
181 assert_eq!(notification.jsonrpc, JSONRPC_VERSION);
182 assert_eq!(notification.method, "test_event");
183 assert_eq!(notification.params, params);
184 }
185
186 #[test]
187 fn test_response_success() {
188 let id = RequestId::String("test-1".to_string());
189 let result = Some(json!({"status": "ok"}));
190 let response = Response::success(id.clone(), result.clone());
191
192 assert_eq!(response.jsonrpc, JSONRPC_VERSION);
193 assert_eq!(response.id, id);
194 assert_eq!(response.result, result);
195 assert!(response.error.is_none());
196 }
197
198 #[test]
199 fn test_response_error() {
200 let id = RequestId::Number(123);
201 let error = ResponseError {
202 code: -32600,
203 message: "Invalid Request".to_string(),
204 data: Some(json!({"details": "missing method"})),
205 };
206 let response = Response::error(id.clone(), error.clone());
207
208 assert_eq!(response.jsonrpc, JSONRPC_VERSION);
209 assert_eq!(response.id, id);
210 assert!(response.result.is_none());
211
212 let response_error = response.error.unwrap();
213 assert_eq!(response_error.code, error.code);
214 assert_eq!(response_error.message, error.message);
215 }
216
217 #[test]
218 fn test_request_id_display() {
219 let num_id = RequestId::Number(42);
220 let str_id = RequestId::String("test-id".to_string());
221
222 assert_eq!(num_id.to_string(), "42");
223 assert_eq!(str_id.to_string(), "test-id");
224 }
225
226 #[test]
227 fn test_protocol_versions() {
228 assert!(SUPPORTED_PROTOCOL_VERSIONS.contains(&LATEST_PROTOCOL_VERSION));
229 assert_eq!(JSONRPC_VERSION, "2.0");
230 }
231}