sheave_core/messages/release_stream.rs
1use std::io::Result as IOResult;
2use super::{
3 Channel,
4 ChunkData,
5 Command,
6 headers::MessageType
7};
8use crate::{
9 Decoder,
10 Encoder,
11 ByteBuffer,
12 messages::amf::v0::{
13 AmfString,
14 Null
15 }
16};
17
18/// The command to tell some path to the server.
19///
20/// Following format is required.
21///
22/// |Field|AMF Type|Value|
23/// | :- | :- | :- |
24/// |Command Name|[`String`]|`"releaseStream"`|
25/// |Transaction ID|[`Number`]|A number which is next of the connect.|
26/// ||[`Null`]|Nothing but an AMF's type marker is in.|
27/// |Path|[`String`]|Some path to audio/video data to make server opened.|
28///
29/// For example, path is defined as some file name in FFmpeg and OBS.
30///
31/// [`Number`]: crate::messages::amf::v0::Number
32/// [`String`]: crate::messages::amf::v0::AmfString
33/// [`Null`]: crate::messages::amf::v0::Null
34#[derive(Debug, Clone, PartialEq)]
35pub struct ReleaseStream(AmfString);
36
37impl ReleaseStream {
38 /// Constructs a ReleaseStream command.
39 pub fn new(topic_path: AmfString) -> Self {
40 Self(topic_path)
41 }
42
43 /// Gets the topic path.
44 pub fn get_topic_path(&self) -> &AmfString {
45 &self.0
46 }
47}
48
49impl From<ReleaseStream> for AmfString {
50 fn from(release_stream: ReleaseStream) -> Self {
51 release_stream.0
52 }
53}
54
55impl ChunkData for ReleaseStream {
56 const CHANNEL: Channel = Channel::System;
57 const MESSAGE_TYPE: MessageType = MessageType::Command;
58}
59
60impl Command for ReleaseStream {}
61
62impl Decoder<ReleaseStream> for ByteBuffer {
63 /// Decodes bytes into a ReleaseStream command.
64 ///
65 /// # Errors
66 ///
67 /// * [`InsufficientBufferLength`]
68 ///
69 /// When some field misses.
70 ///
71 /// * [`InconsistentMarker`]
72 ///
73 /// When some value is inconsistent with its marker.
74 ///
75 /// * [`InvalidString`]
76 ///
77 /// When some value is invalid for UTF-8 string.
78 ///
79 /// # Examples
80 ///
81 /// ```rust
82 /// use sheave_core::{
83 /// ByteBuffer,
84 /// Decoder,
85 /// Encoder,
86 /// messages::{
87 /// ReleaseStream,
88 /// amf::v0::{
89 /// AmfString,
90 /// Null
91 /// }
92 /// }
93 /// };
94 ///
95 /// let mut buffer = ByteBuffer::default();
96 /// buffer.encode(&Null);
97 /// buffer.encode(&AmfString::default());
98 /// assert!(Decoder::<ReleaseStream>::decode(&mut buffer).is_ok());
99 ///
100 /// let mut buffer = ByteBuffer::default();
101 /// assert!(Decoder::<ReleaseStream>::decode(&mut buffer).is_err())
102 /// ```
103 ///
104 /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
105 /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
106 /// [`InvalidString`]: crate::messages::amf::InvalidString
107 fn decode(&mut self) -> IOResult<ReleaseStream> {
108 Decoder::<Null>::decode(self)?;
109 let topic_path: AmfString = self.decode()?;
110 Ok(ReleaseStream(topic_path))
111 }
112}
113
114impl Encoder<ReleaseStream> for ByteBuffer {
115 /// Encodes a ReleaseStream command into bytes.
116 fn encode(&mut self, release_stream: &ReleaseStream) {
117 self.encode(&Null);
118 self.encode(release_stream.get_topic_path());
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn decode_release_stream() {
128 let mut buffer = ByteBuffer::default();
129 buffer.encode(&Null);
130 buffer.encode(&AmfString::default());
131 let result: IOResult<ReleaseStream> = buffer.decode();
132 assert!(result.is_ok());
133 let actual = result.unwrap();
134 let expected = ReleaseStream::new(AmfString::default());
135 assert_eq!(expected, actual)
136 }
137
138 #[test]
139 fn encode_release_stream() {
140 let mut buffer = ByteBuffer::default();
141 let expected_topic_path = "";
142 let expected = ReleaseStream::new(AmfString::from(expected_topic_path));
143 buffer.encode(&expected);
144 Decoder::<Null>::decode(&mut buffer).unwrap();
145 let actual_topic_path: AmfString = buffer.decode().unwrap();
146 assert_eq!(expected_topic_path, actual_topic_path)
147 }
148}