sheave_core/messages/publish.rs
1mod invalid_publishing_type;
2
3use std::io::Result as IOResult;
4use crate::{
5 ByteBuffer,
6 Decoder,
7 Encoder,
8 messages::{
9 Channel,
10 ChunkData,
11 Command,
12 amf::v0::{
13 AmfString,
14 Null
15 },
16 headers::MessageType
17 }
18};
19pub use self::invalid_publishing_type::*;
20
21/// The command to tell publishing information.
22///
23/// Following format is required:
24///
25/// |Field|AMF Type|Value|
26/// | :- | :- | :- |
27/// ||[`Null`]|Nothing but an AMF's type marker is in.|
28/// |Publishing Name|[`String`]|A name for publishing a data to the server.|
29/// |Publishing Type|[`String`]|See [Publishing Type](#publishing-type).|
30///
31/// # Publishing Type
32///
33/// The publish command requires you to specify one of "Publishing Type" in its request.
34/// Publishing Type means:
35///
36/// |Pubishing Type|Description|
37/// | :- | :- |
38/// |`"live"`|Only streaming.<br />Its data will never be stored.|
39/// |`"record"`|Its data will be stored.<br />If publishing name duplicated, it is rewritten as a new file.|
40/// |`"append"`|Same as `"record"` excepts is appended its data if publishing name duplicated.|
41///
42/// [`String`]: crate::messages::amf::v0::AmfString
43/// [`Null`]: crate::messages::amf::v0::Null
44#[derive(Debug, Clone, PartialEq)]
45pub struct Publish {
46 publishing_name: AmfString,
47 publishing_type: AmfString
48}
49
50impl Publish {
51 /// Constructs a Publish command.
52 pub fn new(publishing_name: AmfString, publishing_type: AmfString) -> Self {
53 Self { publishing_name, publishing_type }
54 }
55
56 /// Gets the publishing identifier. (e.g. filename)
57 pub fn get_publishing_name(&self) -> &AmfString {
58 &self.publishing_name
59 }
60
61 /// Gets one of publishing type which is either `"live"`, `"record"` or `"append"`.
62 pub fn get_publishing_type(&self) -> &AmfString {
63 &self.publishing_type
64 }
65}
66
67impl From<Publish> for (AmfString, AmfString) {
68 fn from(publish: Publish) -> Self {
69 (publish.publishing_name, publish.publishing_type)
70 }
71}
72
73impl ChunkData for Publish {
74 const CHANNEL: Channel = Channel::Source;
75 const MESSAGE_TYPE: MessageType = MessageType::Command;
76}
77
78impl Command for Publish {}
79
80impl Decoder<Publish> for ByteBuffer {
81 /// Decodes bytes into a Publish command.
82 ///
83 /// # Errors
84 ///
85 /// * [`InsufficientBufferLength`]
86 ///
87 /// When some field misses.
88 ///
89 /// * [`InconsistentMarker`]
90 ///
91 /// When some value is inconsistent with its marker.
92 ///
93 /// * [`InvalidString`]
94 ///
95 /// When some value is invalid for UTF-8 string.
96 ///
97 /// * [`InvalidPublishingType`]
98 ///
99 /// When the publishing type is neither `"live"`, `"record"` nor `"append"`.
100 ///
101 /// # Examples
102 ///
103 /// ```rust
104 /// use sheave_core::{
105 /// ByteBuffer,
106 /// Decoder,
107 /// Encoder,
108 /// messages::{
109 /// Publish,
110 /// amf::v0::{
111 /// AmfString,
112 /// Null
113 /// }
114 /// }
115 /// };
116 ///
117 /// let mut buffer = ByteBuffer::default();
118 /// buffer.encode(&Null);
119 /// buffer.encode(&AmfString::default());
120 /// buffer.encode(&AmfString::from("live"));
121 /// assert!(Decoder::<Publish>::decode(&mut buffer).is_ok());
122 ///
123 /// let mut buffer = ByteBuffer::default();
124 /// buffer.encode(&Null);
125 /// buffer.encode(&AmfString::default());
126 /// buffer.encode(&AmfString::from("record"));
127 /// assert!(Decoder::<Publish>::decode(&mut buffer).is_ok());
128 ///
129 /// let mut buffer = ByteBuffer::default();
130 /// buffer.encode(&Null);
131 /// buffer.encode(&AmfString::default());
132 /// buffer.encode(&AmfString::from("append"));
133 /// assert!(Decoder::<Publish>::decode(&mut buffer).is_ok());
134 ///
135 /// let mut buffer = ByteBuffer::default();
136 /// buffer.encode(&Null);
137 /// buffer.encode(&AmfString::default());
138 /// buffer.encode(&AmfString::from("something else"));
139 /// assert!(Decoder::<Publish>::decode(&mut buffer).is_err())
140 /// ```
141 ///
142 /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
143 /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
144 /// [`InvalidString`]: crate::messages::amf::InvalidString
145 /// [`InvalidPublishingType`]: InvalidPublishingType
146 fn decode(&mut self) -> IOResult<Publish> {
147 Decoder::<Null>::decode(self)?;
148 let publishing_name: AmfString = self.decode()?;
149 let publishing_type: AmfString = self.decode()?;
150
151 if publishing_type != "live" && publishing_type != "record" && publishing_type != "append" {
152 return Err(invalid_publishing_type(publishing_type))
153 }
154
155 Ok(Publish { publishing_name, publishing_type })
156 }
157}
158
159impl Encoder<Publish> for ByteBuffer {
160 /// Encodes a Publish command into bytes.
161 fn encode(&mut self, publish: &Publish) {
162 self.encode(&Null);
163 self.encode(publish.get_publishing_name());
164 self.encode(publish.get_publishing_type());
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn decode_publish() {
174 let mut buffer = ByteBuffer::default();
175 buffer.encode(&Null);
176 buffer.encode(&AmfString::default());
177 buffer.encode(&AmfString::from("live"));
178 let result: IOResult<Publish> = buffer.decode();
179 assert!(result.is_ok());
180 let actual = result.unwrap();
181 let expected = Publish::new(AmfString::default(), AmfString::from("live"));
182 assert_eq!(expected, actual)
183 }
184
185 #[test]
186 fn encode_publish() {
187 let mut buffer = ByteBuffer::default();
188 let expected_publishing_name = "";
189 let expected_publishing_type = "live";
190 let expected = Publish::new(AmfString::from(expected_publishing_name), AmfString::from(expected_publishing_type));
191 buffer.encode(&expected);
192 Decoder::<Null>::decode(&mut buffer).unwrap();
193 let actual_publishing_name: AmfString = buffer.decode().unwrap();
194 assert_eq!(expected_publishing_name, actual_publishing_name);
195 let actual_publishing_type: AmfString = buffer.decode().unwrap();
196 assert_eq!(expected_publishing_type, actual_publishing_type)
197 }
198}