scuffle_rtmp/command_messages/netconnection/
writer.rs

1//! Writing [`NetConnectionCommand`].
2
3use std::io;
4
5use scuffle_amf0::encoder::Amf0Encoder;
6
7use super::{NetConnectionCommand, NetConnectionCommandConnectResult};
8use crate::command_messages::error::CommandError;
9
10impl NetConnectionCommand<'_> {
11    /// Writes a [`NetConnectionCommand`] to the given writer.
12    pub fn write(self, buf: &mut impl io::Write, transaction_id: f64) -> Result<(), CommandError> {
13        let mut encoder = Amf0Encoder::new(buf);
14
15        match self {
16            Self::ConnectResult(NetConnectionCommandConnectResult { properties, information }) => {
17                encoder.encode_string("_result")?;
18                encoder.encode_number(transaction_id)?;
19                encoder.serialize(&properties)?;
20                encoder.serialize(&information)?;
21            }
22            Self::CreateStreamResult { stream_id } => {
23                encoder.encode_string("_result")?;
24                encoder.encode_number(transaction_id)?;
25                encoder.encode_null()?;
26                encoder.encode_number(stream_id)?;
27            }
28            Self::Connect { .. } | Self::Call { .. } | Self::Close | Self::CreateStream => {
29                return Err(CommandError::NoClientImplementation);
30            }
31        }
32
33        Ok(())
34    }
35}
36
37#[cfg(test)]
38#[cfg_attr(all(test, coverage_nightly), coverage(off))]
39mod tests {
40    use bytes::{BufMut, BytesMut};
41    use scuffle_amf0::Amf0Value;
42    use scuffle_amf0::decoder::Amf0Decoder;
43
44    use super::*;
45
46    #[test]
47    fn test_netconnection_connect_response() {
48        let mut buf = BytesMut::new();
49
50        NetConnectionCommand::ConnectResult(NetConnectionCommandConnectResult::default())
51            .write(&mut (&mut buf).writer(), 1.0)
52            .expect("write");
53
54        let mut deserializer = Amf0Decoder::from_buf(buf.freeze());
55        let values = deserializer.decode_all().unwrap();
56
57        assert_eq!(values.len(), 4);
58        assert_eq!(values[0], Amf0Value::String("_result".into())); // command name
59        assert_eq!(values[1], Amf0Value::Number(1.0)); // transaction id
60        assert_eq!(
61            values[2],
62            Amf0Value::Object(
63                [
64                    ("fmsVer".into(), Amf0Value::String("FMS/3,0,1,123".into())),
65                    ("capabilities".into(), Amf0Value::Number(31.0)),
66                ]
67                .into_iter()
68                .collect()
69            )
70        );
71        assert_eq!(
72            values[3],
73            Amf0Value::Object(
74                [
75                    ("level".into(), Amf0Value::String("status".into())),
76                    ("code".into(), Amf0Value::String("NetConnection.Connect.Success".into())),
77                    ("description".into(), Amf0Value::String("Connection Succeeded.".into())),
78                    ("objectEncoding".into(), Amf0Value::Number(0.0)),
79                ]
80                .into_iter()
81                .collect()
82            )
83        );
84    }
85
86    #[test]
87    fn test_netconnection_create_stream_response() {
88        let mut buf = BytesMut::new();
89
90        NetConnectionCommand::CreateStreamResult { stream_id: 1.0 }
91            .write(&mut (&mut buf).writer(), 1.0)
92            .expect("write");
93
94        let mut deserializer = Amf0Decoder::from_buf(buf.freeze());
95        let values = deserializer.decode_all().unwrap();
96
97        assert_eq!(values.len(), 4);
98        assert_eq!(values[0], Amf0Value::String("_result".into())); // command name
99        assert_eq!(values[1], Amf0Value::Number(1.0)); // transaction id
100        assert_eq!(values[2], Amf0Value::Null); // command object
101        assert_eq!(values[3], Amf0Value::Number(1.0)); // stream id
102    }
103}