moq_lite/ietf/
announce.rs

1//! IETF moq-transport-07 announce messages
2
3use std::borrow::Cow;
4
5use crate::{coding::*, Path};
6
7use super::util::{decode_namespace, encode_namespace};
8
9/// Announce message (0x06)
10/// Sent by the publisher to announce the availability of a namespace.
11#[derive(Clone, Debug)]
12pub struct Announce<'a> {
13	pub track_namespace: Path<'a>,
14}
15
16impl<'a> Message for Announce<'a> {
17	fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, DecodeError> {
18		let track_namespace = decode_namespace(r)?;
19
20		let num_params = u8::decode(r)?;
21		if num_params > 0 {
22			return Err(DecodeError::InvalidValue);
23		}
24
25		Ok(Self { track_namespace })
26	}
27
28	fn encode<W: bytes::BufMut>(&self, w: &mut W) {
29		encode_namespace(w, &self.track_namespace);
30		0u8.encode(w); // number of parameters
31	}
32}
33
34/// AnnounceOk message (0x07)
35#[derive(Clone, Debug)]
36pub struct AnnounceOk<'a> {
37	pub track_namespace: Path<'a>,
38}
39
40impl<'a> Message for AnnounceOk<'a> {
41	fn encode<W: bytes::BufMut>(&self, w: &mut W) {
42		encode_namespace(w, &self.track_namespace);
43	}
44
45	fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, DecodeError> {
46		let track_namespace = decode_namespace(r)?;
47		Ok(Self { track_namespace })
48	}
49}
50
51/// AnnounceError message (0x08)
52#[derive(Clone, Debug)]
53pub struct AnnounceError<'a> {
54	pub track_namespace: Path<'a>,
55	pub error_code: u64,
56	pub reason_phrase: Cow<'a, str>,
57}
58
59impl<'a> Message for AnnounceError<'a> {
60	fn encode<W: bytes::BufMut>(&self, w: &mut W) {
61		encode_namespace(w, &self.track_namespace);
62		self.error_code.encode(w);
63		self.reason_phrase.encode(w);
64	}
65
66	fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, DecodeError> {
67		let track_namespace = decode_namespace(r)?;
68		let error_code = u64::decode(r)?;
69		let reason_phrase = Cow::<str>::decode(r)?;
70
71		Ok(Self {
72			track_namespace,
73			error_code,
74			reason_phrase,
75		})
76	}
77}
78
79/// Unannounce message (0x09)
80#[derive(Clone, Debug)]
81pub struct Unannounce<'a> {
82	pub track_namespace: Path<'a>,
83}
84
85impl<'a> Message for Unannounce<'a> {
86	fn encode<W: bytes::BufMut>(&self, w: &mut W) {
87		encode_namespace(w, &self.track_namespace);
88	}
89
90	fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, DecodeError> {
91		let track_namespace = decode_namespace(r)?;
92		Ok(Self { track_namespace })
93	}
94}
95
96/// AnnounceCancel message (0x0c)
97#[derive(Clone, Debug)]
98pub struct AnnounceCancel<'a> {
99	pub track_namespace: Path<'a>,
100	pub error_code: u64,
101	pub reason_phrase: Cow<'a, str>,
102}
103
104impl<'a> Message for AnnounceCancel<'a> {
105	fn encode<W: bytes::BufMut>(&self, w: &mut W) {
106		encode_namespace(w, &self.track_namespace);
107		self.error_code.encode(w);
108		self.reason_phrase.encode(w);
109	}
110
111	fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, DecodeError> {
112		let track_namespace = decode_namespace(r)?;
113		let error_code = u64::decode(r)?;
114		let reason_phrase = Cow::<str>::decode(r)?;
115
116		Ok(Self {
117			track_namespace,
118			error_code,
119			reason_phrase,
120		})
121	}
122}
123
124#[cfg(test)]
125mod tests {
126	use super::*;
127	use bytes::BytesMut;
128
129	fn encode_message<M: Message>(msg: &M) -> Vec<u8> {
130		let mut buf = BytesMut::new();
131		msg.encode(&mut buf);
132		buf.to_vec()
133	}
134
135	fn decode_message<M: Message>(bytes: &[u8]) -> Result<M, DecodeError> {
136		let mut buf = bytes::Bytes::from(bytes.to_vec());
137		M::decode(&mut buf)
138	}
139
140	#[test]
141	fn test_announce_round_trip() {
142		let msg = Announce {
143			track_namespace: Path::new("test/broadcast"),
144		};
145
146		let encoded = encode_message(&msg);
147		let decoded: Announce = decode_message(&encoded).unwrap();
148
149		assert_eq!(decoded.track_namespace.as_str(), "test/broadcast");
150	}
151
152	#[test]
153	fn test_announce_ok() {
154		let msg = AnnounceOk {
155			track_namespace: Path::new("foo"),
156		};
157
158		let encoded = encode_message(&msg);
159		let decoded: AnnounceOk = decode_message(&encoded).unwrap();
160
161		assert_eq!(decoded.track_namespace.as_str(), "foo");
162	}
163
164	#[test]
165	fn test_announce_error() {
166		let msg = AnnounceError {
167			track_namespace: Path::new("test"),
168			error_code: 404,
169			reason_phrase: "Unauthorized".into(),
170		};
171
172		let encoded = encode_message(&msg);
173		let decoded: AnnounceError = decode_message(&encoded).unwrap();
174
175		assert_eq!(decoded.track_namespace.as_str(), "test");
176		assert_eq!(decoded.error_code, 404);
177		assert_eq!(decoded.reason_phrase, "Unauthorized");
178	}
179
180	#[test]
181	fn test_unannounce() {
182		let msg = Unannounce {
183			track_namespace: Path::new("old/stream"),
184		};
185
186		let encoded = encode_message(&msg);
187		let decoded: Unannounce = decode_message(&encoded).unwrap();
188
189		assert_eq!(decoded.track_namespace.as_str(), "old/stream");
190	}
191
192	#[test]
193	fn test_announce_cancel() {
194		let msg = AnnounceCancel {
195			track_namespace: Path::new("canceled"),
196			error_code: 1,
197			reason_phrase: "Shutdown".into(),
198		};
199
200		let encoded = encode_message(&msg);
201		let decoded: AnnounceCancel = decode_message(&encoded).unwrap();
202
203		assert_eq!(decoded.track_namespace.as_str(), "canceled");
204		assert_eq!(decoded.error_code, 1);
205		assert_eq!(decoded.reason_phrase, "Shutdown");
206	}
207
208	#[test]
209	fn test_announce_rejects_parameters() {
210		#[rustfmt::skip]
211		let invalid_bytes = vec![
212			0x01, // namespace length
213			0x04, 0x74, 0x65, 0x73, 0x74, // "test"
214			0x01, // INVALID: num_params = 1
215		];
216
217		let result: Result<Announce, _> = decode_message(&invalid_bytes);
218		assert!(result.is_err());
219	}
220}