use crate::errors::{ProtocolError, Result};
use thiserror::Error;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use std::fmt::Display;
use super::traits::TryFromState;
use super::state::State;
use std::sync::Arc;
use tokio::sync::RwLock;
use std::collections::HashMap;
pub fn json_to_type_or_error<T: DeserializeOwned>(
response: serde_json::Value,
) -> Result<ResponseOrError<T>> {
Ok(serde_json::from_value(response)
.map_err(|x| {
ProtocolError::coerce_static_from_str(&format!("{:#?}", x))
})?)
}
pub fn serializable_to_json<T: Serialize>(obj: &T) -> Result<serde_json::Value> {
let str_val = serde_json::to_string(obj)
.map_err(|_| ProtocolError("Unexpected problem serializing T to string"))?;
Ok(serde_json::from_str(&str_val)
.expect("Transforming to JSON failed. This should never happen"))
}
pub fn try_response_from_json<A, B>(response: serde_json::Value) -> Result<ResponseOrError<A>>
where
A: TryFrom<B>,
<A as TryFrom<B>>::Error: Display,
B: DeserializeOwned,
{
let parse_graphql = json_to_type_or_error::<B>(response)?;
let mapped = parse_graphql.map(Box::new(|data| data.try_into()));
match mapped {
ResponseOrError::Response(DataResponse { data }) => match data {
Ok(data) => Ok(ResponseOrError::from_data(data)),
Err(err) => Err(ProtocolError::coerce_static_from_str(&format!("{}", err))),
},
ResponseOrError::Error(e) => Ok(ResponseOrError::Error(e)),
}
}
pub async fn try_response_with_state_from_json<A, B>(
response: serde_json::Value,
state: Arc<RwLock<State>>
) -> Result<ResponseOrError<A>>
where
A: TryFromState<B>,
B: DeserializeOwned,
{
let parse_graphql = json_to_type_or_error::<B>(response)?;
match parse_graphql {
ResponseOrError::Response(DataResponse { data }) => {
let conversion = TryFromState::from(data, state.clone()).await;
match conversion {
Ok(data) => Ok(ResponseOrError::from_data(data)),
Err(err) => Err(ProtocolError::coerce_static_from_str(&format!("{}", err))),
}
},
ResponseOrError::Error(e) => Ok(ResponseOrError::Error(e)),
}
}
pub enum ErrorOrData<T> {
Data(T),
Error(ErrorResponse),
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
pub enum ResponseOrError<T> {
Response(DataResponse<T>),
Error(ErrorResponse),
}
impl<T> ResponseOrError<T> {
pub fn from_data(data: T) -> Self {
Self::Response(DataResponse { data })
}
pub fn consume_match(self) -> ErrorOrData<T> {
match self {
Self::Response(DataResponse { data }) => ErrorOrData::Data(data),
Self::Error(e) => ErrorOrData::Error(e),
}
}
pub fn response(&self) -> Option<&T> {
match self {
Self::Response(DataResponse { data }) => Some(data),
Self::Error(_) => None,
}
}
pub fn consume_response(self) -> Option<T> {
match self {
Self::Response(DataResponse { data }) => Some(data),
Self::Error(_) => None,
}
}
pub fn consume_error(self) -> Option<ErrorResponse> {
match self {
Self::Response(_) => None,
Self::Error(e) => Some(e),
}
}
pub fn response_or_error(self) -> Result<T> {
match self {
Self::Response(DataResponse { data}) => Ok(data),
Self::Error(e) => Err(ProtocolError::coerce_static_from_str(&format!("{:?}", e)))
}
}
pub fn error(&self) -> Option<&ErrorResponse> {
match self {
Self::Response(_) => None,
Self::Error(error) => Some(error),
}
}
pub fn is_error(&self) -> bool {
match self {
Self::Error(_) => true,
Self::Response(_) => false,
}
}
pub fn map<M>(self, f: Box<dyn Fn(T) -> M>) -> ResponseOrError<M> {
match self {
Self::Error(e) => ResponseOrError::Error(e),
Self::Response(r) => ResponseOrError::Response(r.map(f)),
}
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct DataResponse<T> {
pub data: T,
}
impl<T> DataResponse<T> {
fn map<M>(self, f: Box<dyn Fn(T) -> M>) -> DataResponse<M> {
DataResponse { data: f(self.data) }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GraphQLResponse {
#[serde(default)]
pub data: HashMap<String, serde_json::Value>,
#[serde(default)]
pub errors: Vec<Error>
}
impl TryFrom<serde_json::Value> for GraphQLResponse {
type Error = ProtocolError;
fn try_from(response: serde_json::Value) -> Result<Self> {
serde_json::from_value(response).map_err(|e|
ProtocolError::coerce_static_from_str(
&format!("Couldn't parse response: {:#?}", e)
)
)
}
}
#[derive(Clone, Deserialize, Serialize, Debug, Error)]
#[error("")]
pub struct ErrorResponse {
pub errors: Vec<Error>,
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct Error {
pub message: String,
pub path: Vec<String>
}
#[derive(Clone, Debug)]
pub struct RequestPayloadSignature {
pub signed_digest: String,
pub public_key: String,
}
impl RequestPayloadSignature {
pub fn empty() -> Self {
Self {
signed_digest: "".to_string(),
public_key: "".to_string(),
}
}
}