turul_rpc_jsonrpc/
dispatch.rs1use serde_json::Value;
8
9use turul_rpc_core::error::JsonRpcError;
10use turul_rpc_core::notification::JsonRpcNotification;
11use turul_rpc_core::request::JsonRpcRequest;
12use turul_rpc_core::response::JsonRpcSuccessResponse;
13use turul_rpc_core::types::RequestId;
14
15#[derive(Debug, Clone)]
19pub enum JsonRpcMessage {
20 Request(JsonRpcRequest),
21 Notification(JsonRpcNotification),
22}
23
24#[derive(Debug, Clone)]
26pub enum JsonRpcMessageResult {
27 Response(JsonRpcSuccessResponse),
29 Error(JsonRpcError),
31 NoResponse,
33}
34
35impl JsonRpcMessageResult {
36 pub fn to_json_string(&self) -> Option<String> {
38 match self {
39 JsonRpcMessageResult::Response(response) => serde_json::to_string(response).ok(),
40 JsonRpcMessageResult::Error(error) => serde_json::to_string(error).ok(),
41 JsonRpcMessageResult::NoResponse => None,
42 }
43 }
44
45 pub fn is_error(&self) -> bool {
47 matches!(self, JsonRpcMessageResult::Error(_))
48 }
49
50 pub fn needs_response(&self) -> bool {
52 !matches!(self, JsonRpcMessageResult::NoResponse)
53 }
54}
55
56pub fn parse_json_rpc_message(json_str: &str) -> Result<JsonRpcMessage, JsonRpcError> {
67 let value: Value = serde_json::from_str(json_str).map_err(|_| JsonRpcError::parse_error())?;
68 parse_json_rpc_value(value)
69}
70
71fn parse_json_rpc_value(value: Value) -> Result<JsonRpcMessage, JsonRpcError> {
76 if !value.is_object() {
77 return Err(JsonRpcError::invalid_request(None));
78 }
79
80 let obj = value.as_object().unwrap();
81
82 match obj.get("jsonrpc") {
84 Some(version) if version == "2.0" => {}
85 _ => return Err(JsonRpcError::invalid_request(extract_id(obj))),
86 }
87
88 if obj.contains_key("id") {
90 if let Some(Value::Number(n)) = obj.get("id")
94 && n.as_i64().is_none()
95 {
96 return Err(JsonRpcError::invalid_request(None));
97 }
98 serde_json::from_value::<JsonRpcRequest>(value.clone())
99 .map(JsonRpcMessage::Request)
100 .map_err(|_| JsonRpcError::invalid_request(extract_id(obj)))
101 } else {
102 serde_json::from_value::<JsonRpcNotification>(value)
103 .map(JsonRpcMessage::Notification)
104 .map_err(|_| JsonRpcError::invalid_request(None))
105 }
106}
107
108pub(crate) fn extract_id(obj: &serde_json::Map<String, Value>) -> Option<RequestId> {
109 obj.get("id").and_then(|v| match v {
110 Value::String(s) => Some(RequestId::String(s.clone())),
111 Value::Number(n) => n.as_i64().map(RequestId::Number),
112 Value::Null => Some(RequestId::Null),
113 _ => None,
114 })
115}
116
117pub fn parse_json_rpc_messages(json_str: &str) -> Vec<Result<JsonRpcMessage, JsonRpcError>> {
126 use crate::batch::{BatchOrSingle, parse_json_rpc_batch};
127 match parse_json_rpc_batch(json_str) {
128 BatchOrSingle::Single(r) => vec![r],
129 BatchOrSingle::Batch(items) => items,
130 BatchOrSingle::EmptyBatch => vec![Err(JsonRpcError::invalid_request(None))],
131 }
132}
133
134pub(crate) fn parse_value_into_message(value: Value) -> Result<JsonRpcMessage, JsonRpcError> {
137 parse_json_rpc_value(value)
138}
139
140pub fn create_success_response(id: RequestId, result: Value) -> JsonRpcMessageResult {
142 JsonRpcMessageResult::Response(JsonRpcSuccessResponse::success(id, result))
143}
144
145pub fn create_error_response(
147 id: Option<RequestId>,
148 code: i64,
149 message: &str,
150) -> JsonRpcMessageResult {
151 let error_obj = turul_rpc_core::error::JsonRpcErrorObject {
152 code,
153 message: message.to_string(),
154 data: None,
155 };
156 JsonRpcMessageResult::Error(JsonRpcError::new(id, error_obj))
157}
158
159impl JsonRpcMessage {
161 pub fn method(&self) -> &str {
163 match self {
164 JsonRpcMessage::Request(req) => &req.method,
165 JsonRpcMessage::Notification(notif) => ¬if.method,
166 }
167 }
168
169 pub fn is_request(&self) -> bool {
171 matches!(self, JsonRpcMessage::Request(_))
172 }
173
174 pub fn is_notification(&self) -> bool {
176 matches!(self, JsonRpcMessage::Notification(_))
177 }
178
179 pub fn request_id(&self) -> Option<&RequestId> {
181 match self {
182 JsonRpcMessage::Request(req) => Some(&req.id),
183 JsonRpcMessage::Notification(_) => None,
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use serde_json::json;
192
193 #[test]
194 fn test_parse_valid_request() {
195 let json = r#"{"jsonrpc": "2.0", "method": "test", "id": 1}"#;
196 let message = parse_json_rpc_message(json).unwrap();
197
198 assert!(message.is_request());
199 assert_eq!(message.method(), "test");
200 assert_eq!(message.request_id(), Some(&RequestId::Number(1)));
201 }
202
203 #[test]
204 fn test_parse_valid_notification() {
205 let json = r#"{"jsonrpc": "2.0", "method": "notify"}"#;
206 let message = parse_json_rpc_message(json).unwrap();
207
208 assert!(message.is_notification());
209 assert_eq!(message.method(), "notify");
210 assert_eq!(message.request_id(), None);
211 }
212
213 #[test]
214 fn test_parse_invalid_json() {
215 let json = r#"{"jsonrpc": "2.0", "method": "test""#;
216 let result = parse_json_rpc_message(json);
217
218 assert!(result.is_err());
219 let error = result.unwrap_err();
220 assert_eq!(error.error.code, -32700);
221 }
222
223 #[test]
224 fn test_parse_invalid_version() {
225 let json = r#"{"jsonrpc": "1.0", "method": "test", "id": 1}"#;
226 let result = parse_json_rpc_message(json);
227
228 assert!(result.is_err());
229 let error = result.unwrap_err();
230 assert_eq!(error.error.code, -32600);
231 }
232
233 #[test]
234 fn test_message_result_to_json() {
235 let response = create_success_response(RequestId::Number(1), json!({"result": "success"}));
236
237 let json_str = response.to_json_string().unwrap();
238 assert!(json_str.contains("\"result\""));
239 assert!(json_str.contains("\"jsonrpc\":\"2.0\""));
240 }
241
242 #[test]
243 fn test_message_result_properties() {
244 let success = create_success_response(RequestId::Number(1), json!({}));
245 let error = create_error_response(Some(RequestId::Number(1)), -32601, "Not found");
246 let no_response = JsonRpcMessageResult::NoResponse;
247
248 assert!(!success.is_error());
249 assert!(success.needs_response());
250
251 assert!(error.is_error());
252 assert!(error.needs_response());
253
254 assert!(!no_response.is_error());
255 assert!(!no_response.needs_response());
256 }
257}