iscsi_client_rs/client/
common.rs1use std::time::Duration;
5
6use anyhow::Result;
7use bytes::Bytes;
8use thiserror::Error;
9use tokio::time::timeout;
10use tokio_util::sync::CancellationToken;
11
12use crate::models::common::HEADER_LEN;
13
14#[derive(Debug, Error)]
15pub enum ClientIoError {
16 #[error("{label} cancelled")]
17 Cancelled { label: &'static str },
18 #[error("{label} timeout")]
19 Timeout { label: &'static str },
20}
21
22pub(super) fn is_timeout_error(error: &anyhow::Error) -> bool {
23 error
24 .downcast_ref::<ClientIoError>()
25 .is_some_and(|client_error| matches!(client_error, ClientIoError::Timeout { .. }))
26}
27
28pub(super) async fn io_with_timeout<F, T>(
29 label: &'static str,
30 fut: F,
31 io_timeout: Duration,
32 cancel: &CancellationToken,
33) -> Result<T>
34where
35 F: Future<Output = std::io::Result<T>>,
36{
37 tokio::select! {
38 _ = cancel.cancelled() => Err(ClientIoError::Cancelled { label }.into()),
39 res = timeout(io_timeout, fut) => {
40 match res {
41 Ok(Ok(v)) => Ok(v),
42 Ok(Err(e)) => Err(e.into()),
43 Err(_) => Err(ClientIoError::Timeout { label }.into()),
44 }
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
56pub struct RawPdu {
57 pub header: [u8; HEADER_LEN],
62 pub payload: Bytes,
68}