scuffle_rtmp/
error.rs

1//! General RTMP error type.
2
3use crate::chunk::error::ChunkReadError;
4use crate::command_messages::error::CommandError;
5use crate::handshake::complex::error::ComplexHandshakeError;
6use crate::session::server::ServerSessionError;
7
8/// RTMP error.
9#[derive(Debug, thiserror::Error)]
10pub enum RtmpError {
11    /// IO error.
12    #[error("io error: {0}")]
13    Io(#[from] std::io::Error),
14    /// Chunk read error.
15    #[error("chunk read error: {0}")]
16    ChunkRead(#[from] ChunkReadError),
17    /// Command error.
18    #[error("command error: {0}")]
19    Command(#[from] CommandError),
20    /// Complex handshake error.
21    #[error("complex handshake error: {0}")]
22    ComplexHandshake(#[from] ComplexHandshakeError),
23    /// Session error.
24    #[error("session error: {0}")]
25    Session(#[from] ServerSessionError),
26}
27
28impl RtmpError {
29    /// Returns true if the error indicates that the client has closed the connection.
30    pub fn is_client_closed(&self) -> bool {
31        match self {
32            Self::Io(err) => matches!(
33                err.kind(),
34                std::io::ErrorKind::ConnectionAborted
35                    | std::io::ErrorKind::ConnectionReset
36                    | std::io::ErrorKind::UnexpectedEof
37            ),
38            Self::Session(ServerSessionError::Timeout(_)) => true,
39            _ => false,
40        }
41    }
42}
43
44#[cfg(test)]
45#[cfg_attr(all(test, coverage_nightly), coverage(off))]
46mod tests {
47    use std::future;
48    use std::io::ErrorKind;
49    use std::time::Duration;
50
51    use crate::error::RtmpError;
52    use crate::session::server::ServerSessionError;
53
54    #[tokio::test]
55    async fn test_is_client_closed() {
56        assert!(RtmpError::Io(std::io::Error::new(ErrorKind::ConnectionAborted, "test")).is_client_closed());
57        assert!(RtmpError::Io(std::io::Error::new(ErrorKind::ConnectionReset, "test")).is_client_closed());
58        assert!(RtmpError::Io(std::io::Error::new(ErrorKind::UnexpectedEof, "test")).is_client_closed());
59
60        let elapsed = tokio::time::timeout(Duration::ZERO, future::pending::<()>())
61            .await
62            .unwrap_err();
63
64        assert!(RtmpError::Session(ServerSessionError::Timeout(elapsed)).is_client_closed());
65
66        assert!(!RtmpError::Io(std::io::Error::other("test")).is_client_closed());
67    }
68}