playit_agent_core/agent_control/
errors.rs

1use std::{
2    error::Error,
3    fmt::{Display, Formatter},
4    future::Future,
5    net::SocketAddr,
6    panic::Location,
7    time::Duration,
8};
9
10use futures_util::TryFutureExt;
11use playit_api_client::{
12    api::{ApiError, ApiErrorNoFail, ApiResponseError},
13    http_client::HttpClientError,
14};
15
16#[derive(Debug)]
17pub enum SetupError {
18    IoError(std::io::Error),
19    FailedToConnect,
20    ApiFail(String),
21    ApiError(ApiResponseError),
22    RequestError(HttpClientError),
23    AttemptingToAuthWithOldFlow,
24    FailedToDecodeSignedAgentRegisterHex,
25    NoResponseFromAuthenticate,
26    RegisterInvalidSignature,
27    RegisterUnauthorized,
28    Timeout(TimeoutSource),
29}
30
31impl From<TimeoutSource> for SetupError {
32    fn from(value: TimeoutSource) -> Self {
33        SetupError::Timeout(value)
34    }
35}
36
37#[derive(Debug)]
38pub struct TimeoutSource {
39    pub file_name: &'static str,
40    pub line_no: u32,
41}
42
43impl TimeoutSource {
44    pub fn from_location(location: &'static Location<'static>) -> Self {
45        TimeoutSource {
46            file_name: location.file(),
47            line_no: location.line(),
48        }
49    }
50}
51
52pub trait TimeoutHelper {
53    type Data;
54
55    fn timeout(self, max: Duration) -> impl Future<Output = Result<Self::Data, SetupError>>;
56}
57
58pub trait TryTimeoutHelper {
59    type Success;
60    type Error;
61
62    fn try_timeout(self, max: Duration)
63        -> impl Future<Output = Result<Self::Success, Self::Error>>;
64}
65
66impl<F: Future> TimeoutHelper for F {
67    type Data = F::Output;
68
69    #[track_caller]
70    fn timeout(self, max: Duration) -> impl Future<Output = Result<Self::Data, SetupError>> {
71        tokio::time::timeout(max, self)
72            .map_err(|_| SetupError::Timeout(TimeoutSource::from_location(Location::caller())))
73    }
74}
75
76impl<R, E: From<TimeoutSource>, F: Future<Output = Result<R, E>>> TryTimeoutHelper for F {
77    type Success = R;
78    type Error = E;
79
80    #[track_caller]
81    fn try_timeout(
82        self,
83        max: Duration,
84    ) -> impl Future<Output = Result<Self::Success, Self::Error>> {
85        let fut = tokio::time::timeout(max, self)
86            .map_err(|_| E::from(TimeoutSource::from_location(Location::caller())));
87
88        async {
89            match fut.await {
90                Ok(Ok(res)) => Ok(res),
91                Err(err) | Ok(Err(err)) => Err(err),
92            }
93        }
94    }
95}
96
97impl<F: serde::Serialize> From<ApiError<F, HttpClientError>> for SetupError {
98    fn from(value: ApiError<F, HttpClientError>) -> Self {
99        match value {
100            ApiError::ApiError(api) => SetupError::ApiError(api),
101            ApiError::ClientError(error) => SetupError::RequestError(error),
102            ApiError::Fail(fail) => SetupError::ApiFail(serde_json::to_string(&fail).unwrap()),
103        }
104    }
105}
106
107impl From<ApiErrorNoFail<HttpClientError>> for SetupError {
108    fn from(value: ApiErrorNoFail<HttpClientError>) -> Self {
109        match value {
110            ApiErrorNoFail::ApiError(api) => SetupError::ApiError(api),
111            ApiErrorNoFail::ClientError(error) => SetupError::RequestError(error),
112        }
113    }
114}
115
116impl Display for SetupError {
117    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
118        write!(f, "{:?}", self)
119    }
120}
121
122impl Error for SetupError {}
123
124impl From<std::io::Error> for SetupError {
125    fn from(e: std::io::Error) -> Self {
126        SetupError::IoError(e)
127    }
128}
129
130#[derive(Debug)]
131pub enum ControlError {
132    IoError(std::io::Error),
133    InvalidRemote {
134        expected: SocketAddr,
135        got: SocketAddr,
136    },
137    FailedToReadControlFeed(std::io::Error),
138    Timeout(TimeoutSource),
139}
140
141impl From<std::io::Error> for ControlError {
142    fn from(e: std::io::Error) -> Self {
143        ControlError::IoError(e)
144    }
145}
146
147impl From<TimeoutSource> for ControlError {
148    fn from(value: TimeoutSource) -> Self {
149        ControlError::Timeout(value)
150    }
151}