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