moq_lite/ietf/
publish_namespace.rs

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