1use 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#[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); }
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 let _params = Parameters::decode(r, version)?;
36
37 Ok(Self {
38 request_id,
39 track_namespace,
40 })
41 }
42}
43
44#[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#[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#[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#[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, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, ];
220
221 let result: Result<PublishNamespace, _> = decode_message(&invalid_bytes);
222 assert!(result.is_err());
223 }
224}