turul_mcp_json_rpc_server/
request.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5use crate::types::{RequestId, JsonRpcVersion};
6
7/// Parameters for a JSON-RPC request  
8#[derive(Debug, Clone, Deserialize, Serialize)]
9#[serde(untagged)]
10pub enum RequestParams {
11    /// Positional parameters as an array
12    Array(Vec<Value>),
13    /// Named parameters as an object
14    Object(HashMap<String, Value>),
15}
16
17impl RequestParams {
18    /// Get a parameter by index (for array params) or name (for object params)
19    pub fn get(&self, key: &str) -> Option<&Value> {
20        match self {
21            RequestParams::Object(map) => map.get(key),
22            RequestParams::Array(_) => None, // Can't get by name from array
23        }
24    }
25
26    /// Get a parameter by index (for array params only)
27    pub fn get_index(&self, index: usize) -> Option<&Value> {
28        match self {
29            RequestParams::Array(vec) => vec.get(index),
30            RequestParams::Object(_) => None, // Can't get by index from object
31        }
32    }
33
34    /// Convert to HashMap for easier processing (arrays become indexed keys)
35    pub fn to_map(&self) -> HashMap<String, Value> {
36        match self {
37            RequestParams::Object(map) => map.clone(),
38            RequestParams::Array(vec) => {
39                vec.iter()
40                    .enumerate()
41                    .map(|(i, v)| (i.to_string(), v.clone()))
42                    .collect()
43            }
44        }
45    }
46
47    /// Check if parameters are empty
48    pub fn is_empty(&self) -> bool {
49        match self {
50            RequestParams::Object(map) => map.is_empty(),
51            RequestParams::Array(vec) => vec.is_empty(),
52        }
53    }
54
55    /// Convert to a serde_json::Value for serialization
56    pub fn to_value(&self) -> Value {
57        match self {
58            RequestParams::Object(map) => Value::Object(map.iter()
59                .map(|(k, v)| (k.clone(), v.clone()))
60                .collect()),
61            RequestParams::Array(arr) => Value::Array(arr.clone()),
62        }
63    }
64}
65
66impl From<HashMap<String, Value>> for RequestParams {
67    fn from(map: HashMap<String, Value>) -> Self {
68        RequestParams::Object(map)
69    }
70}
71
72impl From<Vec<Value>> for RequestParams {
73    fn from(vec: Vec<Value>) -> Self {
74        RequestParams::Array(vec)
75    }
76}
77
78/// A JSON-RPC request
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonRpcRequest {
81    #[serde(rename = "jsonrpc")]
82    pub version: JsonRpcVersion,
83    pub id: RequestId,
84    pub method: String,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub params: Option<RequestParams>,
87}
88
89impl JsonRpcRequest {
90    pub fn new(id: RequestId, method: String, params: Option<RequestParams>) -> Self {
91        Self {
92            version: JsonRpcVersion::V2_0,
93            id,
94            method,
95            params,
96        }
97    }
98
99    /// Create a new request with no parameters
100    pub fn new_no_params(id: RequestId, method: String) -> Self {
101        Self::new(id, method, None)
102    }
103
104    /// Create a new request with object parameters
105    pub fn new_with_object_params(
106        id: RequestId,
107        method: String,
108        params: HashMap<String, Value>,
109    ) -> Self {
110        Self::new(id, method, Some(RequestParams::Object(params)))
111    }
112
113    /// Create a new request with array parameters
114    pub fn new_with_array_params(id: RequestId, method: String, params: Vec<Value>) -> Self {
115        Self::new(id, method, Some(RequestParams::Array(params)))
116    }
117
118    /// Get a parameter by name (if params are an object)
119    pub fn get_param(&self, name: &str) -> Option<&Value> {
120        self.params.as_ref()?.get(name)
121    }
122
123    /// Get a parameter by index (if params are an array)
124    pub fn get_param_index(&self, index: usize) -> Option<&Value> {
125        self.params.as_ref()?.get_index(index)
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use serde_json::{json, from_str, to_string};
133
134    #[test]
135    fn test_request_serialization() {
136        let request = JsonRpcRequest::new_no_params(
137            RequestId::Number(1),
138            "test_method".to_string(),
139        );
140
141        let json = to_string(&request).unwrap();
142        let parsed: JsonRpcRequest = from_str(&json).unwrap();
143
144        assert_eq!(parsed.id, RequestId::Number(1));
145        assert_eq!(parsed.method, "test_method");
146        assert!(parsed.params.is_none());
147    }
148
149    #[test]
150    fn test_request_with_object_params() {
151        let mut params = HashMap::new();
152        params.insert("name".to_string(), json!("test"));
153        params.insert("value".to_string(), json!(42));
154
155        let request = JsonRpcRequest::new_with_object_params(
156            RequestId::String("req1".to_string()),
157            "set_value".to_string(),
158            params,
159        );
160
161        assert_eq!(request.get_param("name"), Some(&json!("test")));
162        assert_eq!(request.get_param("value"), Some(&json!(42)));
163        assert_eq!(request.get_param("missing"), None);
164    }
165
166    #[test]
167    fn test_request_with_array_params() {
168        let params = vec![json!("test"), json!(42), json!(true)];
169
170        let request = JsonRpcRequest::new_with_array_params(
171            RequestId::Number(2),
172            "process".to_string(),
173            params,
174        );
175
176        assert_eq!(request.get_param_index(0), Some(&json!("test")));
177        assert_eq!(request.get_param_index(1), Some(&json!(42)));
178        assert_eq!(request.get_param_index(2), Some(&json!(true)));
179        assert_eq!(request.get_param_index(3), None);
180    }
181
182    #[test]
183    fn test_params_to_map() {
184        let object_params = RequestParams::Object({
185            let mut map = HashMap::new();
186            map.insert("key".to_string(), json!("value"));
187            map
188        });
189
190        let array_params = RequestParams::Array(vec![json!("first"), json!("second")]);
191
192        let object_map = object_params.to_map();
193        assert_eq!(object_map.get("key"), Some(&json!("value")));
194
195        let array_map = array_params.to_map();
196        assert_eq!(array_map.get("0"), Some(&json!("first")));
197        assert_eq!(array_map.get("1"), Some(&json!("second")));
198    }
199}