use http::StatusCode;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use xapi_shared::{
repr::de_status_code::deserialize_status_code,
rest::error::SharedRestError,
ws::{error::SharedWsError, response::SharedWsResponseTrait},
};
pub type BnRestRespType<T> = Result<T, SharedRestError<BnRespError>>;
pub type BnWsApiRespType<T> = Result<T, SharedWsError>;
#[derive(Debug, Serialize, Deserialize)]
pub struct BnRespError {
pub code: i32,
pub msg: String,
}
impl Display for BnRespError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
serde_json::to_string(self).unwrap_or_else(|_| String::from("{}"))
)
}
}
#[derive(Debug)]
pub struct BnWsApiResponse {
pub id: String,
pub result: serde_json::Value,
}
impl SharedWsResponseTrait<String> for BnWsApiResponse {
fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
where
Self: Sized,
{
match serde_json::from_str::<BnWsApiRawResponse>(text) {
Err(_) => None,
Ok(resp) => {
if !resp.status.is_success() || resp.error.is_some() || resp.result.is_none() {
tracing::error!(
status = ?resp.status,
id = resp.id,
?resp,
"ws api request failed with status code"
);
let err_str = serde_json::to_string(&resp.error)
.inspect_err(|err| {
tracing::error!(?err, "failed to serialize ws api error response")
})
.unwrap_or_else(|_| format!("{:?}", resp.error));
return Some(Err((resp.id, SharedWsError::AppError(err_str))));
}
Some(Ok(Self {
id: resp.id,
result: resp.result.unwrap(),
}))
}
}
}
fn get_id(&self) -> &String {
&self.id
}
}
#[derive(Debug, Deserialize)]
struct BnWsApiRawResponse {
id: String,
#[serde(deserialize_with = "deserialize_status_code")]
status: StatusCode,
result: Option<serde_json::Value>,
error: Option<BnRespError>,
}
#[derive(Debug)]
pub struct BnWsStreamResponse {
pub id: String,
pub result: serde_json::Value,
}
impl SharedWsResponseTrait<String> for BnWsStreamResponse {
fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
where
Self: Sized,
{
match serde_json::from_str::<BnWsStreamRawResponse>(text) {
Err(_) => None,
Ok(resp) => {
if let Some(err) = &resp.error {
tracing::error!(id = resp.id, ?err, "ws stream request failed with error");
return Some(Err((resp.id, SharedWsError::AppError(err.msg.clone()))));
}
Some(Ok(Self {
id: resp.id,
result: resp.result.unwrap_or_default(),
}))
}
}
}
fn get_id(&self) -> &String {
&self.id
}
}
#[derive(Debug, Deserialize)]
struct BnWsStreamRawResponse {
id: String,
result: Option<serde_json::Value>,
error: Option<BnWsStreamError>,
}
#[derive(Debug, Deserialize)]
struct BnWsStreamError {
#[allow(dead_code)]
code: i64,
msg: String,
#[allow(dead_code)]
id: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct BnWsStreamData {
pub stream: String,
pub data: serde_json::Value,
}
impl SharedWsResponseTrait<String> for BnWsStreamData {
fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
where
Self: Sized,
{
match serde_json::from_str(text) {
Err(_) => None,
Ok(data) => Some(Ok(data)),
}
}
fn get_id(&self) -> &String {
&self.stream
}
}