use affinidi_did_common::Document;
use network::WSCommands;
use rand::{RngExt, distr::Alphanumeric};
use serde::{Deserialize, Serialize};
use tokio::{select, sync::oneshot};
use tracing::{Instrument, Level, debug, span, warn};
use crate::{DIDCacheClient, errors::DIDCacheError};
#[cfg(feature = "network")]
pub(crate) mod handshake;
pub mod network;
#[cfg(feature = "network")]
pub(crate) mod utils;
mod request_queue;
#[derive(Debug, Deserialize, Serialize)]
pub struct WSRequest {
pub did: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct WSResponse {
pub did: String,
pub hash: [u64; 2],
pub document: Document,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct WSResponseError {
pub did: String,
pub hash: [u64; 2],
pub error: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub enum WSResponseType {
Response(Box<WSResponse>),
Error(WSResponseError),
}
impl DIDCacheClient {
pub(crate) async fn network_resolve(
&self,
did: &str,
did_hash: [u64; 2],
) -> Result<Document, DIDCacheError> {
let _span = span!(Level::DEBUG, "network_resolve");
async move {
debug!("resolving did ({}) via network hash ({:#?})", did, did_hash);
let network_task_tx = self.network_task_tx
.clone()
.unwrap();
let (tx, rx) = oneshot::channel::<WSCommands>();
let unique_id: String = rand::rng()
.sample_iter(&Alphanumeric)
.take(8)
.map(char::from)
.collect();
network_task_tx
.send(WSCommands::Send(tx, unique_id.clone(), WSRequest { did: did.into() }))
.await
.map_err(|e| {
DIDCacheError::TransportError(format!(
"Couldn't send request to network_task. Reason: {e}",
))
})?;
let sleep = tokio::time::sleep(self.config.network_timeout);
tokio::pin!(sleep);
select! {
_ = &mut sleep => {
warn!("Timeout reached, no message received did_hash ({:#?})", did_hash);
network_task_tx.send(WSCommands::TimeOut(unique_id, did_hash)).await.map_err(|err| {
DIDCacheError::TransportError(format!("Could not send timeout message to ws_handler: {err:?}"))
})?;
Err(DIDCacheError::NetworkTimeout)
}
value = rx => {
match value {
Ok(WSCommands::ResponseReceived(doc)) => {
debug!("Received response from network task ({:#?})", did_hash);
Ok(*doc)
}
Ok(WSCommands::ErrorReceived(msg)) => {
warn!("Received error response from network task");
Err(DIDCacheError::TransportError(msg))
}
Ok(_) => {
debug!("Received unexpected response from network task");
Err(DIDCacheError::TransportError("Unexpected response from network task".into()))
}
Err(e) => {
debug!("Error receiving response from network task: {:?}", e);
Err(DIDCacheError::TransportError(format!("Error receiving response from network task: {e:?}")))
}
}
}
}
}
.instrument(_span)
.await
}
}