xapi-shared 0.0.1

XAPI Shared Library
Documentation
use crate::ws::{
    error::SharedWsError, payload::SharedWsApiPayloadTrait, response::SharedWsResponseTrait,
};
use ezsockets::{Client, ClientExt};
use std::{collections::HashMap, fmt::Debug, hash::Hash};
use tokio::sync::oneshot;

pub trait SharedWsApiTrait<
    WsApiId: Hash + Eq + Clone + Debug,
    Payload: SharedWsApiPayloadTrait<WsApiId>,
    Response: SharedWsResponseTrait<WsApiId> + Debug,
> where
    Self: Sized + ClientExt,
{
    fn get_client(&self) -> &Client<Self>;

    fn get_oneshot_tx_map(
        &mut self,
    ) -> &mut HashMap<WsApiId, oneshot::Sender<Result<Response, SharedWsError>>>;

    fn send_oneshot(
        &mut self,
        payload: Payload,
        tx: oneshot::Sender<Result<Response, SharedWsError>>,
    ) -> Result<(), SharedWsError> {
        let id = payload.get_id();

        let oneshot_tx_map = self.get_oneshot_tx_map();

        if oneshot_tx_map.contains_key(id) {
            tracing::error!(?id, "duplicated id in ws api request");
            return Err(SharedWsError::InvalidIdError(format!("{id:?}")));
        }

        let text = payload.serialize()?;

        oneshot_tx_map.insert(id.clone(), tx);

        tracing::info!(?text, "sending ws api request");
        self.get_client()
            .text(text)
            .inspect_err(|err| {
                tracing::error!(?err, "failed to send ws api request");
            })
            .map_err(|err| SharedWsError::ChannelClosedError(err.to_string()))?;

        Ok(())
    }

    fn recv_oneshot_resp(&mut self, text: &str) -> Option<Result<(), SharedWsError>> {
        match Response::try_parse(text) {
            None => None,
            Some(result) => {
                let (id, msg) = match result {
                    Ok(resp) => {
                        let id = resp.get_id().clone();

                        (id, Ok(resp))
                    }
                    Err((id, err)) => {
                        tracing::error!(?id, ?err, "failed to parse ws api response");
                        (id, Err(err))
                    }
                };

                let tx_map = self.get_oneshot_tx_map();

                Some(match tx_map.remove(&id) {
                    None => {
                        tracing::error!(?id, ?msg, "missing ws api resp channel");
                        Err(SharedWsError::InvalidIdError(format!("{id:?}")))
                    }
                    Some(tx) => tx
                        .send(msg)
                        .inspect_err(|err| tracing::error!(?err, "failed to send to resp channel"))
                        .map_err(|err| SharedWsError::ChannelClosedError(format!("{err:?}"))),
                })
            }
        }
    }
}