scuffle_rtmp/command_messages/
reader.rs

1//! Reading [`Command`].
2
3use std::convert::Infallible;
4use std::str::FromStr;
5
6use bytes::Bytes;
7use scuffle_amf0::decoder::Amf0Decoder;
8use scuffle_bytes_util::StringCow;
9use scuffle_bytes_util::zero_copy::BytesBuf;
10
11use super::error::CommandError;
12use super::netconnection::NetConnectionCommand;
13use super::netstream::NetStreamCommand;
14use super::{Command, CommandResultLevel, CommandType, UnknownCommand};
15
16impl Command<'_> {
17    /// Reads a [`Command`] from the given payload.
18    pub fn read(payload: Bytes) -> Result<Self, CommandError> {
19        let mut decoder = Amf0Decoder::from_buf(payload);
20
21        let command_name = decoder.decode_string()?;
22        let transaction_id = decoder.decode_number()?;
23
24        let command_type = CommandType::read(command_name, &mut decoder)?;
25
26        Ok(Self {
27            transaction_id,
28            command_type,
29        })
30    }
31}
32
33impl<'a> CommandType<'a> {
34    fn read(command_name: StringCow<'a>, decoder: &mut Amf0Decoder<BytesBuf<Bytes>>) -> Result<Self, CommandError> {
35        if let Some(command) = NetConnectionCommand::read(command_name.as_str(), decoder)? {
36            return Ok(Self::NetConnection(command));
37        }
38
39        if let Some(command) = NetStreamCommand::read(command_name.as_str(), decoder)? {
40            return Ok(Self::NetStream(command));
41        }
42
43        let values = decoder.decode_all()?;
44        Ok(Self::Unknown(UnknownCommand { command_name, values }))
45    }
46}
47
48impl FromStr for CommandResultLevel {
49    type Err = Infallible;
50
51    fn from_str(s: &str) -> Result<Self, Self::Err> {
52        match s {
53            "warning" => Ok(Self::Warning),
54            "status" => Ok(Self::Status),
55            "error" => Ok(Self::Error),
56            _ => Ok(Self::Unknown(s.to_string())),
57        }
58    }
59}
60
61#[cfg(test)]
62#[cfg_attr(all(test, coverage_nightly), coverage(off))]
63mod tests {
64    use super::CommandResultLevel;
65
66    #[test]
67    fn test_command_result_level() {
68        assert_eq!("warning".parse::<CommandResultLevel>().unwrap(), CommandResultLevel::Warning);
69        assert_eq!("status".parse::<CommandResultLevel>().unwrap(), CommandResultLevel::Status);
70        assert_eq!("error".parse::<CommandResultLevel>().unwrap(), CommandResultLevel::Error);
71        assert_eq!(
72            "unknown".parse::<CommandResultLevel>().unwrap(),
73            CommandResultLevel::Unknown("unknown".to_string())
74        );
75    }
76}