use a2a_lf::{JsonRpcId, JsonRpcRequest, JsonRpcResponse};
use reqwest::StatusCode;
use reqwest::header::ACCEPT;
use serde_json::Value;
use super::Transport;
use super::binding::Operation;
use crate::a2a::error::{A2aError, A2aRpcError};
impl Transport {
pub(super) fn jsonrpc_request(
&self,
operation: &Operation,
id: i64,
accept: &'static str,
) -> reqwest::RequestBuilder {
let request = JsonRpcRequest::new(
JsonRpcId::Number(id),
operation.method,
Some(operation.params.clone()),
);
self.http
.post(self.endpoint.clone())
.headers(self.operation_headers(operation))
.header(ACCEPT, accept)
.json(&request)
}
}
pub(super) fn decode_reply(
method: &'static str,
id: i64,
status: StatusCode,
body: &[u8],
) -> Result<Value, A2aError> {
let Ok(reply) = serde_json::from_slice::<JsonRpcResponse>(body) else {
if !status.is_success() {
return Err(A2aError::HttpStatus {
operation: method,
status,
});
}
return Err(A2aError::Decode { method });
};
let result = decode_envelope(method, id, reply)?;
if !status.is_success() {
return Err(A2aError::HttpStatus {
operation: method,
status,
});
}
Ok(result)
}
pub(super) fn decode_envelope(
method: &'static str,
id: i64,
reply: JsonRpcResponse,
) -> Result<Value, A2aError> {
if let Some(error) = reply.error {
if reply.id != JsonRpcId::Number(id) && reply.id != JsonRpcId::Null {
return Err(A2aError::MismatchedReplyId { method });
}
return Err(A2aError::Rpc {
method,
error: A2aRpcError::from_code(error.code),
});
}
if reply.id != JsonRpcId::Number(id) {
return Err(A2aError::MismatchedReplyId { method });
}
Ok(reply.result.unwrap_or(Value::Null))
}