Skip to main content

ghast_client/
error.rs

1//! Errors and session outcomes.
2
3use ghast_protocol::{DecodeError, EncodeError, FrameError, State};
4use thiserror::Error;
5
6/// How a session that reached the play state ended without an error.
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum SessionEnd {
10    /// The server kicked the player.
11    Kicked {
12        /// The reason as plain text.
13        reason: String,
14        /// The reason as the server sent it (chat JSON).
15        json: String,
16    },
17    /// The server closed the connection without a reason.
18    ServerClosed,
19    /// The behaviour called [`crate::TickContext::disconnect`].
20    Quit(String),
21    /// The shutdown future given to [`crate::Client::run_until`] completed.
22    Shutdown,
23}
24
25/// A session failed.
26#[derive(Debug, Error)]
27#[non_exhaustive]
28pub enum ClientError {
29    /// Opening the connection (direct or through the proxy) failed.
30    #[error(transparent)]
31    Connect(#[from] ghast_auth::connect::ConnectError),
32    /// The username is not valid for an offline login.
33    #[error("invalid username: {0}")]
34    Username(#[from] ghast_auth::offline::UsernameError),
35    /// Socket error.
36    #[error("connection error: {0}")]
37    Io(#[from] std::io::Error),
38    /// Framing / compression / encryption error (the stream is unusable).
39    #[error("bad frame from the server: {0}")]
40    Frame(#[source] FrameError),
41    /// A packet the client needs could not be decoded.
42    #[error("could not decode {state:?} packet 0x{id:02x}: {source}")]
43    Decode {
44        /// Connection state.
45        state: State,
46        /// Packet id.
47        id: i32,
48        /// What was wrong.
49        #[source]
50        source: DecodeError,
51    },
52    /// Chunk data from the server was malformed. Since 0.1.3 a session no longer ends with
53    /// it: the column is dropped, the error logged and play goes on (like vanilla). Kept for
54    /// compatibility.
55    #[error("bad chunk data: {0}")]
56    World(#[source] ghast_world::WorldError),
57    /// A packet could not be encoded (a value the protocol cannot carry).
58    #[error("could not encode a packet: {0}")]
59    Encode(#[from] EncodeError),
60    /// The server refused the login.
61    #[error("login refused: {0}")]
62    LoginRefused(String),
63    /// The server closed the connection during login.
64    #[error("the server closed the connection during login")]
65    LoginClosed,
66    /// The server is in online mode but the account is an offline one.
67    #[error("the server requires online mode (a Microsoft account)")]
68    OnlineModeRequired,
69    /// The encryption handshake failed.
70    #[error("encryption handshake: {0}")]
71    Crypto(#[from] ghast_auth::crypto::CryptoError),
72    /// The session server refused the join (online mode).
73    #[cfg(feature = "microsoft")]
74    #[error("session server: {0}")]
75    Session(#[from] ghast_auth::microsoft::MicrosoftError),
76    /// No data from the server for too long.
77    #[error("timed out: {0}")]
78    Timeout(&'static str),
79}
80
81impl From<FrameError> for ClientError {
82    fn from(e: FrameError) -> Self {
83        match e {
84            FrameError::Io(io) => ClientError::Io(io),
85            e => ClientError::Frame(e),
86        }
87    }
88}