use serde_json::Value;
use crate::adapters::primary::transport::http::exchange::Answer;
use crate::adapters::primary::transport::http::refusal::Refusal;
use crate::application::server::context::ExchangeError;
use crate::domain::ir::{IrErrorCode, JsonObject};
use crate::domain::jsonrpc::reply::{self, ReplyError};
use crate::domain::jsonrpc::{Envelope, Frame, WireId, decode};
pub(in crate::adapters::primary::transport) type Id<'a> = WireId<'a>;
pub(in crate::adapters::primary::transport) fn result_document(
id: Option<&Id<'_>>,
result: &JsonObject,
) -> Result<Value, Refusal> {
let id = id.ok_or_else(|| {
Refusal::Handler("a result was produced for a request that asked no question".to_owned())
})?;
reply::result_reply(id, result).map_err(|error| match error {
ReplyError::UnreadableResult => {
Refusal::Handler("the dispatcher's result has no JSON form".to_owned())
}
})
}
pub(in crate::adapters::primary::transport) fn refusal_document_from_refusal(
id: Option<&WireId<'_>>,
refusal: &Refusal,
) -> Value {
id.map_or_else(
|| reply::unidentified_error_reply(IrErrorCode::InternalError, &refusal.to_string()),
|id| reply::error_reply(id, IrErrorCode::InternalError, &refusal.to_string()),
)
}
pub(in crate::adapters::primary::transport) fn refusal_document(
id: Option<&WireId<'_>>,
error: &crate::application::server::DispatchError,
) -> Value {
let (code, message) = error.as_wire();
match (id, error.wire_data()) {
(Some(id), Some(data)) => reply::error_reply_with_data(id, code, &message, &data),
(Some(id), None) => reply::error_reply(id, code, &message),
(None, _) => reply::unidentified_error_reply(code, &message),
}
}
pub(in crate::adapters::primary::transport) fn method_of(body: &[u8]) -> Option<String> {
let decoded = decode(body).ok()?;
let Frame::Single(envelope) = decoded else {
return None;
};
envelope.method_str().map(str::to_owned)
}
pub(in crate::adapters::primary::transport) fn params_of(
envelope: &Envelope<'_>,
) -> Result<JsonObject, Refusal> {
envelope.params().map_or_else(
|| Ok(JsonObject::default()),
|raw| {
JsonObject::new(raw.get()).map_err(|_| Refusal::MalformedBody {
reason: "params is not a JSON object".to_owned(),
})
},
)
}
pub(in crate::adapters::primary::transport) const fn id_as_i64(id: &WireId<'_>) -> Option<i64> {
match id {
WireId::Number(value) => Some(*value),
WireId::Text(_) => None,
}
}
pub(in crate::adapters::primary::transport) fn answer_of(body: &[u8]) -> Answer {
let Ok(document) = serde_json::from_slice::<Value>(body) else {
return Err(ExchangeError::new("the answer was not JSON"));
};
if let Some(failure) = document.get("error") {
return Err(ExchangeError::new(failure.to_string()));
}
document.get("result").map_or_else(
|| {
Err(ExchangeError::new(
"the answer carried neither a result nor an error",
))
},
|result| {
JsonObject::from_value(result.clone())
.map_err(|error| ExchangeError::new(error.to_string()))
},
)
}