1use steam_auth::EAuthSessionGuardType;
4use steam_cm_provider::CmError;
5use steam_enums::EResult;
6use thiserror::Error;
7
8#[derive(Error, Debug)]
10pub enum SteamError {
11 #[error("Steam error: {0:?}")]
13 SteamResult(EResult),
14
15 #[error("Connection error: {0}")]
17 ConnectionError(String),
18
19 #[error("Already logged on")]
21 AlreadyLoggedOn,
22
23 #[error("Already connecting")]
25 AlreadyConnecting,
26
27 #[error("Not logged on")]
29 NotLoggedOn,
30
31 #[error("Not connected")]
33 NotConnected,
34
35 #[error("Invalid credentials")]
37 InvalidCredentials,
38
39 #[error("Steam Guard required: {guard_type:?}")]
47 SteamGuardRequired {
48 guard_type: EAuthSessionGuardType,
50 email_domain: Option<String>,
52 },
53
54 #[error("Two-factor authentication required")]
56 TwoFactorRequired,
57
58 #[error("Invalid token: {0}")]
60 InvalidToken(String),
61
62 #[error("Network error: {0}")]
64 NetworkError(std::io::Error),
65
66 #[error("Operation timed out")]
68 Timeout,
69
70 #[error("Response timed out")]
72 ResponseTimeout,
73
74 #[error("Deserialization failed")]
76 DeserializationFailed,
77
78 #[error("Protocol error: {0}")]
80 ProtocolError(String),
81
82 #[error("Bad response: {message}")]
87 BadResponse {
88 message: String,
90 emsg: Option<steam_enums::EMsg>,
92 raw_bytes: Option<Vec<u8>>,
94 },
95
96 #[error("Session error: {0}")]
98 SessionError(#[from] steam_auth::SessionError),
99
100 #[error("Not implemented: {0}")]
102 NotImplemented(String),
103
104 #[error("{0}")]
106 Other(String),
107}
108
109impl SteamError {
110 pub fn eresult(&self) -> Option<EResult> {
112 match self {
113 SteamError::SteamResult(result) => Some(*result),
114 _ => None,
115 }
116 }
117
118 pub fn is_retryable(&self) -> bool {
127 match self {
128 SteamError::SteamResult(result) => matches!(result, EResult::Fail | EResult::ServiceUnavailable | EResult::TryAnotherCM | EResult::NoConnection),
129 SteamError::NetworkError(_) | SteamError::Timeout => true,
130 _ => false,
131 }
132 }
133
134 pub fn bad_response(message: impl Into<String>) -> Self {
137 SteamError::BadResponse { message: message.into(), emsg: None, raw_bytes: None }
138 }
139
140 pub fn bad_response_with_context(message: impl Into<String>, emsg: Option<steam_enums::EMsg>, raw_bytes: Option<Vec<u8>>) -> Self {
142 SteamError::BadResponse { message: message.into(), emsg, raw_bytes }
143 }
144}
145
146impl From<CmError> for SteamError {
147 fn from(e: CmError) -> Self {
148 match e {
149 CmError::Network(s) => SteamError::NetworkError(std::io::Error::other(s)),
150 CmError::Protocol(s) => SteamError::ProtocolError(s),
151 CmError::ApiError(status, msg) => SteamError::ProtocolError(format!("Steam API error (status {}): {}", status, msg)),
152 CmError::InvalidResponse(s) => SteamError::bad_response(s),
153 CmError::Connection(s) => SteamError::ConnectionError(s),
154 CmError::CacheError(s) => SteamError::Other(format!("Cache error: {}", s)),
155 CmError::Timeout => SteamError::Timeout,
156 CmError::NoServers => SteamError::ConnectionError("No CM servers available".into()),
157 CmError::Io(e) => SteamError::NetworkError(e),
158 CmError::Json(e) => SteamError::ProtocolError(format!("JSON error: {}", e)),
159 CmError::Other(s) => SteamError::Other(s),
160 }
161 }
162}