1use crate::state::AppState;
13
14use super::error::RpcError;
15use super::methods;
16use super::types::*;
17
18#[derive(Clone)]
32pub struct RpcRouter {
33 state: AppState,
34}
35
36impl RpcRouter {
37 pub fn new(state: AppState) -> Self {
39 Self { state }
40 }
41
42 pub async fn handle_request(&self, raw: &str) -> String {
45 if let Ok(batch) = serde_json::from_str::<Vec<JsonRpcRequest>>(raw) {
47 let mut responses = Vec::with_capacity(batch.len());
48 for req in batch {
49 responses.push(self.dispatch(req).await);
50 }
51 return serde_json::to_string(&responses).unwrap_or_else(|_| {
52 r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Failed to serialize response"},"id":null}"#.into()
53 });
54 }
55
56 let request: JsonRpcRequest = match serde_json::from_str(raw) {
58 Ok(req) => req,
59 Err(e) => {
60 return serde_json::to_string(&JsonRpcResponse::error(
61 None,
62 PARSE_ERROR,
63 format!("Parse error: {}", e),
64 ))
65 .unwrap_or_default();
66 }
67 };
68
69 let response = self.dispatch(request).await;
70 serde_json::to_string(&response).unwrap_or_else(|_| {
71 r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Failed to serialize response"},"id":null}"#.into()
72 })
73 }
74
75 pub async fn handle_value(&self, value: serde_json::Value) -> serde_json::Value {
78 let request: JsonRpcRequest = match serde_json::from_value(value) {
79 Ok(req) => req,
80 Err(e) => {
81 return serde_json::to_value(JsonRpcResponse::error(
82 None,
83 PARSE_ERROR,
84 format!("Invalid request: {}", e),
85 ))
86 .unwrap_or_default();
87 }
88 };
89
90 let response = self.dispatch(request).await;
91 serde_json::to_value(response).unwrap_or_default()
92 }
93
94 pub async fn dispatch(&self, req: JsonRpcRequest) -> JsonRpcResponse {
96 if req.jsonrpc != "2.0" {
98 return JsonRpcResponse::error(
99 req.id,
100 INVALID_REQUEST,
101 "Invalid JSON-RPC version, expected \"2.0\"",
102 );
103 }
104
105 let id = req.id.clone();
106 let params = req
107 .params
108 .unwrap_or(serde_json::Value::Object(Default::default()));
109
110 match self.route(&req.method, params).await {
111 Ok(result) => JsonRpcResponse::success(id, result),
112 Err(err) => err.to_response(id),
113 }
114 }
115
116 async fn route(
118 &self,
119 method: &str,
120 params: serde_json::Value,
121 ) -> Result<serde_json::Value, RpcError> {
122 match method {
123 "agents.list" => {
125 let p = parse_params(params)?;
126 let r = methods::agents::list(&self.state, p).await?;
127 Ok(serde_json::to_value(r).unwrap())
128 }
129 "agents.get" => {
130 let p = parse_params(params)?;
131 let r = methods::agents::get(&self.state, p).await?;
132 Ok(serde_json::to_value(r).unwrap())
133 }
134 "agents.create" => {
135 let p = parse_params(params)?;
136 let r = methods::agents::create(&self.state, p).await?;
137 Ok(serde_json::to_value(r).unwrap())
138 }
139 "agents.delete" => {
140 let p = parse_params(params)?;
141 let r = methods::agents::delete(&self.state, p).await?;
142 Ok(serde_json::to_value(r).unwrap())
143 }
144 "agents.updateStatus" => {
145 let p = parse_params(params)?;
146 let r = methods::agents::update_status(&self.state, p).await?;
147 Ok(serde_json::to_value(r).unwrap())
148 }
149
150 "tasks.list" => {
152 let p = parse_params(params)?;
153 let r = methods::tasks::list(&self.state, p).await?;
154 Ok(serde_json::to_value(r).unwrap())
155 }
156 "tasks.get" => {
157 let p = parse_params(params)?;
158 let r = methods::tasks::get(&self.state, p).await?;
159 Ok(serde_json::to_value(r).unwrap())
160 }
161 "tasks.create" => {
162 let p = parse_params(params)?;
163 let r = methods::tasks::create(&self.state, p).await?;
164 Ok(serde_json::to_value(r).unwrap())
165 }
166 "tasks.delete" => {
167 let p = parse_params(params)?;
168 let r = methods::tasks::delete(&self.state, p).await?;
169 Ok(serde_json::to_value(r).unwrap())
170 }
171 "tasks.updateStatus" => {
172 let p = parse_params(params)?;
173 let r = methods::tasks::update_status(&self.state, p).await?;
174 Ok(serde_json::to_value(r).unwrap())
175 }
176 "tasks.findReady" => {
177 let p = parse_params(params)?;
178 let r = methods::tasks::find_ready(&self.state, p).await?;
179 Ok(serde_json::to_value(r).unwrap())
180 }
181 "tasks.listArtifacts" => {
182 let p = parse_params(params)?;
183 let r = methods::tasks::list_artifacts(&self.state, p).await?;
184 Ok(serde_json::to_value(r).unwrap())
185 }
186 "tasks.provideArtifact" => {
187 let p = parse_params(params)?;
188 let r = methods::tasks::provide_artifact(&self.state, p).await?;
189 Ok(serde_json::to_value(r).unwrap())
190 }
191
192 "kanban.listBoards" => {
194 let p = parse_params(params)?;
195 let r = methods::kanban::list_boards(&self.state, p).await?;
196 Ok(serde_json::to_value(r).unwrap())
197 }
198 "kanban.createBoard" => {
199 let p = parse_params(params)?;
200 let r = methods::kanban::create_board(&self.state, p).await?;
201 Ok(serde_json::to_value(r).unwrap())
202 }
203 "kanban.getBoard" => {
204 let p = parse_params(params)?;
205 let r = methods::kanban::get_board(&self.state, p).await?;
206 Ok(serde_json::to_value(r).unwrap())
207 }
208 "kanban.updateBoard" => {
209 let p = parse_params(params)?;
210 let r = methods::kanban::update_board(&self.state, p).await?;
211 Ok(serde_json::to_value(r).unwrap())
212 }
213 "kanban.createCard" => {
214 let p = parse_params(params)?;
215 let r = methods::kanban::create_card(&self.state, p).await?;
216 Ok(serde_json::to_value(r).unwrap())
217 }
218 "kanban.moveCard" => {
219 let p = parse_params(params)?;
220 let r = methods::kanban::move_card(&self.state, p).await?;
221 Ok(serde_json::to_value(r).unwrap())
222 }
223 "kanban.updateCard" => {
224 let p = parse_params(params)?;
225 let r = methods::kanban::update_card(&self.state, p).await?;
226 Ok(serde_json::to_value(r).unwrap())
227 }
228 "kanban.deleteCard" => {
229 let p = parse_params(params)?;
230 let r = methods::kanban::delete_card(&self.state, p).await?;
231 Ok(serde_json::to_value(r).unwrap())
232 }
233 "kanban.createColumn" => {
234 let p = parse_params(params)?;
235 let r = methods::kanban::create_column(&self.state, p).await?;
236 Ok(serde_json::to_value(r).unwrap())
237 }
238 "kanban.deleteColumn" => {
239 let p = parse_params(params)?;
240 let r = methods::kanban::delete_column(&self.state, p).await?;
241 Ok(serde_json::to_value(r).unwrap())
242 }
243 "kanban.searchCards" => {
244 let p = parse_params(params)?;
245 let r = methods::kanban::search_cards(&self.state, p).await?;
246 Ok(serde_json::to_value(r).unwrap())
247 }
248 "kanban.listCardsByColumn" => {
249 let p = parse_params(params)?;
250 let r = methods::kanban::list_cards_by_column(&self.state, p).await?;
251 Ok(serde_json::to_value(r).unwrap())
252 }
253 "kanban.decomposeTasks" => {
254 let p = parse_params(params)?;
255 let r = methods::kanban::decompose_tasks(&self.state, p).await?;
256 Ok(serde_json::to_value(r).unwrap())
257 }
258 "kanban.requestPreviousLaneHandoff" => {
259 let p = parse_params(params)?;
260 let r = methods::kanban::request_previous_lane_handoff(&self.state, p).await?;
261 Ok(serde_json::to_value(r).unwrap())
262 }
263 "kanban.submitLaneHandoff" => {
264 let p = parse_params(params)?;
265 let r = methods::kanban::submit_lane_handoff(&self.state, p).await?;
266 Ok(serde_json::to_value(r).unwrap())
267 }
268
269 "notes.list" => {
271 let p = parse_params(params)?;
272 let r = methods::notes::list(&self.state, p).await?;
273 Ok(serde_json::to_value(r).unwrap())
274 }
275 "notes.get" => {
276 let p = parse_params(params)?;
277 let r = methods::notes::get(&self.state, p).await?;
278 Ok(serde_json::to_value(r).unwrap())
279 }
280 "notes.create" => {
281 let p = parse_params(params)?;
282 let r = methods::notes::create(&self.state, p).await?;
283 Ok(serde_json::to_value(r).unwrap())
284 }
285 "notes.delete" => {
286 let p = parse_params(params)?;
287 let r = methods::notes::delete(&self.state, p).await?;
288 Ok(serde_json::to_value(r).unwrap())
289 }
290
291 "workspaces.list" => {
293 let r = methods::workspaces::list(&self.state).await?;
294 Ok(serde_json::to_value(r).unwrap())
295 }
296 "workspaces.get" => {
297 let p = parse_params(params)?;
298 let r = methods::workspaces::get(&self.state, p).await?;
299 Ok(serde_json::to_value(r).unwrap())
300 }
301 "workspaces.create" => {
302 let p = parse_params(params)?;
303 let r = methods::workspaces::create(&self.state, p).await?;
304 Ok(serde_json::to_value(r).unwrap())
305 }
306 "workspaces.delete" => {
307 let p = parse_params(params)?;
308 let r = methods::workspaces::delete(&self.state, p).await?;
309 Ok(serde_json::to_value(r).unwrap())
310 }
311
312 "skills.list" => {
314 let r = methods::skills::list(&self.state).await?;
315 Ok(serde_json::to_value(r).unwrap())
316 }
317 "skills.get" => {
318 let p = parse_params(params)?;
319 let r = methods::skills::get(&self.state, p).await?;
320 Ok(serde_json::to_value(r).unwrap())
321 }
322 "skills.reload" => {
323 let r = methods::skills::reload(&self.state).await?;
324 Ok(serde_json::to_value(r).unwrap())
325 }
326
327 _ => Err(RpcError::MethodNotFound(format!(
329 "Method not found: {}",
330 method
331 ))),
332 }
333 }
334
335 pub fn method_list(&self) -> Vec<&'static str> {
338 vec![
339 "agents.list",
340 "agents.get",
341 "agents.create",
342 "agents.delete",
343 "agents.updateStatus",
344 "tasks.list",
345 "tasks.get",
346 "tasks.create",
347 "tasks.delete",
348 "tasks.updateStatus",
349 "tasks.findReady",
350 "tasks.listArtifacts",
351 "tasks.provideArtifact",
352 "kanban.listBoards",
353 "kanban.createBoard",
354 "kanban.getBoard",
355 "kanban.updateBoard",
356 "kanban.createCard",
357 "kanban.moveCard",
358 "kanban.updateCard",
359 "kanban.deleteCard",
360 "kanban.createColumn",
361 "kanban.deleteColumn",
362 "kanban.searchCards",
363 "kanban.listCardsByColumn",
364 "kanban.decomposeTasks",
365 "notes.list",
366 "notes.get",
367 "notes.create",
368 "notes.delete",
369 "workspaces.list",
370 "workspaces.get",
371 "workspaces.create",
372 "workspaces.delete",
373 "skills.list",
374 "skills.get",
375 "skills.reload",
376 ]
377 }
378}
379
380fn parse_params<T: serde::de::DeserializeOwned>(value: serde_json::Value) -> Result<T, RpcError> {
382 serde_json::from_value(value)
383 .map_err(|e| RpcError::InvalidParams(format!("Invalid params: {}", e)))
384}