ax-exchange-sdk 1.0.2

ArchitectX SDK
Documentation
use anyhow::{anyhow, bail, Result};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(derive_more::Deref, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Request<T> {
    #[serde(rename = "rid", alias = "request_id")]
    pub request_id: i32,
    #[serde(flatten)]
    #[deref]
    pub request: T,
}

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Response<T> {
    #[serde(rename = "rid", alias = "request_id")]
    pub request_id: i32,
    #[serde(
        rename = "res",
        alias = "result",
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub response: Option<T>,
    #[serde(
        rename = "err",
        alias = "error",
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub error: Option<Error>,
}

impl<T> Response<T> {
    pub fn ok(request_id: i32, response: T) -> Self {
        Self {
            request_id,
            response: Some(response),
            error: None,
        }
    }

    pub fn error(request_id: i32, code: i32, message: Option<String>) -> Self {
        Self {
            request_id,
            response: None,
            error: Some(Error { code, message }),
        }
    }

    pub fn bad_request<S: Into<String>>(request_id: i32, message: Option<S>) -> Self {
        Self::error(request_id, 400, message.map(Into::into))
    }

    pub fn internal_server_error<S: Into<String>>(request_id: i32, message: Option<S>) -> Self {
        Self::error(request_id, 500, message.map(Into::into))
    }

    pub fn into_inner(self) -> Result<T> {
        if let Some(e) = self.error {
            Err(anyhow!(e))
        } else if let Some(inner) = self.response {
            Ok(inner)
        } else {
            bail!("malformed response");
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Error {
    pub code: i32,
    #[serde(rename = "msg", default, skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "code: {}, message: {}",
            self.code,
            self.message
                .as_ref()
                .unwrap_or(&"unknown error".to_string())
        )
    }
}

impl std::error::Error for Error {}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Timestamp {
    pub ts: i32,
    pub tn: u32,
}

impl Timestamp {
    pub fn now() -> Self {
        let now = Utc::now();
        now.into()
    }

    pub fn as_datetime(&self) -> Option<DateTime<Utc>> {
        DateTime::from_timestamp(self.ts as i64, self.tn)
    }
}

impl From<DateTime<Utc>> for Timestamp {
    fn from(value: DateTime<Utc>) -> Self {
        Self {
            ts: value.timestamp() as i32,
            tn: value.timestamp_subsec_nanos() as u32,
        }
    }
}