use crate::state::AppState;
use super::error::RpcError;
use super::methods;
use super::types::*;
#[derive(Clone)]
pub struct RpcRouter {
state: AppState,
}
impl RpcRouter {
pub fn new(state: AppState) -> Self {
Self { state }
}
pub async fn handle_request(&self, raw: &str) -> String {
if let Ok(batch) = serde_json::from_str::<Vec<JsonRpcRequest>>(raw) {
let mut responses = Vec::with_capacity(batch.len());
for req in batch {
responses.push(self.dispatch(req).await);
}
return serde_json::to_string(&responses).unwrap_or_else(|_| {
r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Failed to serialize response"},"id":null}"#.into()
});
}
let request: JsonRpcRequest = match serde_json::from_str(raw) {
Ok(req) => req,
Err(e) => {
return serde_json::to_string(&JsonRpcResponse::error(
None,
PARSE_ERROR,
format!("Parse error: {}", e),
))
.unwrap_or_default();
}
};
let response = self.dispatch(request).await;
serde_json::to_string(&response).unwrap_or_else(|_| {
r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Failed to serialize response"},"id":null}"#.into()
})
}
pub async fn handle_value(&self, value: serde_json::Value) -> serde_json::Value {
let request: JsonRpcRequest = match serde_json::from_value(value) {
Ok(req) => req,
Err(e) => {
return serde_json::to_value(JsonRpcResponse::error(
None,
PARSE_ERROR,
format!("Invalid request: {}", e),
))
.unwrap_or_default();
}
};
let response = self.dispatch(request).await;
serde_json::to_value(response).unwrap_or_default()
}
pub async fn dispatch(&self, req: JsonRpcRequest) -> JsonRpcResponse {
if req.jsonrpc != "2.0" {
return JsonRpcResponse::error(
req.id,
INVALID_REQUEST,
"Invalid JSON-RPC version, expected \"2.0\"",
);
}
let id = req.id.clone();
let params = req
.params
.unwrap_or(serde_json::Value::Object(Default::default()));
match self.route(&req.method, params).await {
Ok(result) => JsonRpcResponse::success(id, result),
Err(err) => err.to_response(id),
}
}
async fn route(
&self,
method: &str,
params: serde_json::Value,
) -> Result<serde_json::Value, RpcError> {
match method {
"agents.list" => {
let p = parse_params(params)?;
let r = methods::agents::list(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"agents.get" => {
let p = parse_params(params)?;
let r = methods::agents::get(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"agents.create" => {
let p = parse_params(params)?;
let r = methods::agents::create(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"agents.delete" => {
let p = parse_params(params)?;
let r = methods::agents::delete(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"agents.updateStatus" => {
let p = parse_params(params)?;
let r = methods::agents::update_status(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.list" => {
let p = parse_params(params)?;
let r = methods::tasks::list(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.get" => {
let p = parse_params(params)?;
let r = methods::tasks::get(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.create" => {
let p = parse_params(params)?;
let r = methods::tasks::create(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.delete" => {
let p = parse_params(params)?;
let r = methods::tasks::delete(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.updateStatus" => {
let p = parse_params(params)?;
let r = methods::tasks::update_status(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.findReady" => {
let p = parse_params(params)?;
let r = methods::tasks::find_ready(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.listArtifacts" => {
let p = parse_params(params)?;
let r = methods::tasks::list_artifacts(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"tasks.provideArtifact" => {
let p = parse_params(params)?;
let r = methods::tasks::provide_artifact(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.listBoards" => {
let p = parse_params(params)?;
let r = methods::kanban::list_boards(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.createBoard" => {
let p = parse_params(params)?;
let r = methods::kanban::create_board(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.getBoard" => {
let p = parse_params(params)?;
let r = methods::kanban::get_board(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.updateBoard" => {
let p = parse_params(params)?;
let r = methods::kanban::update_board(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.createCard" => {
let p = parse_params(params)?;
let r = methods::kanban::create_card(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.moveCard" => {
let p = parse_params(params)?;
let r = methods::kanban::move_card(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.updateCard" => {
let p = parse_params(params)?;
let r = methods::kanban::update_card(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.deleteCard" => {
let p = parse_params(params)?;
let r = methods::kanban::delete_card(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.createColumn" => {
let p = parse_params(params)?;
let r = methods::kanban::create_column(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.deleteColumn" => {
let p = parse_params(params)?;
let r = methods::kanban::delete_column(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.searchCards" => {
let p = parse_params(params)?;
let r = methods::kanban::search_cards(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.listCardsByColumn" => {
let p = parse_params(params)?;
let r = methods::kanban::list_cards_by_column(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.decomposeTasks" => {
let p = parse_params(params)?;
let r = methods::kanban::decompose_tasks(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.requestPreviousLaneHandoff" => {
let p = parse_params(params)?;
let r = methods::kanban::request_previous_lane_handoff(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"kanban.submitLaneHandoff" => {
let p = parse_params(params)?;
let r = methods::kanban::submit_lane_handoff(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"notes.list" => {
let p = parse_params(params)?;
let r = methods::notes::list(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"notes.get" => {
let p = parse_params(params)?;
let r = methods::notes::get(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"notes.create" => {
let p = parse_params(params)?;
let r = methods::notes::create(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"notes.delete" => {
let p = parse_params(params)?;
let r = methods::notes::delete(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"workspaces.list" => {
let r = methods::workspaces::list(&self.state).await?;
Ok(serde_json::to_value(r).unwrap())
}
"workspaces.get" => {
let p = parse_params(params)?;
let r = methods::workspaces::get(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"workspaces.create" => {
let p = parse_params(params)?;
let r = methods::workspaces::create(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"workspaces.delete" => {
let p = parse_params(params)?;
let r = methods::workspaces::delete(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"skills.list" => {
let r = methods::skills::list(&self.state).await?;
Ok(serde_json::to_value(r).unwrap())
}
"skills.get" => {
let p = parse_params(params)?;
let r = methods::skills::get(&self.state, p).await?;
Ok(serde_json::to_value(r).unwrap())
}
"skills.reload" => {
let r = methods::skills::reload(&self.state).await?;
Ok(serde_json::to_value(r).unwrap())
}
_ => Err(RpcError::MethodNotFound(format!(
"Method not found: {}",
method
))),
}
}
pub fn method_list(&self) -> Vec<&'static str> {
vec![
"agents.list",
"agents.get",
"agents.create",
"agents.delete",
"agents.updateStatus",
"tasks.list",
"tasks.get",
"tasks.create",
"tasks.delete",
"tasks.updateStatus",
"tasks.findReady",
"tasks.listArtifacts",
"tasks.provideArtifact",
"kanban.listBoards",
"kanban.createBoard",
"kanban.getBoard",
"kanban.updateBoard",
"kanban.createCard",
"kanban.moveCard",
"kanban.updateCard",
"kanban.deleteCard",
"kanban.createColumn",
"kanban.deleteColumn",
"kanban.searchCards",
"kanban.listCardsByColumn",
"kanban.decomposeTasks",
"notes.list",
"notes.get",
"notes.create",
"notes.delete",
"workspaces.list",
"workspaces.get",
"workspaces.create",
"workspaces.delete",
"skills.list",
"skills.get",
"skills.reload",
]
}
}
fn parse_params<T: serde::de::DeserializeOwned>(value: serde_json::Value) -> Result<T, RpcError> {
serde_json::from_value(value)
.map_err(|e| RpcError::InvalidParams(format!("Invalid params: {}", e)))
}