rtmp_rs/session/
context.rs1use std::net::SocketAddr;
7use std::sync::Arc;
8
9use crate::protocol::enhanced::EnhancedCapabilities;
10use crate::protocol::message::ConnectParams;
11use crate::protocol::quirks::EncoderType;
12use crate::stats::SessionStats;
13
14#[derive(Debug, Clone)]
19pub struct SessionContext {
20 pub session_id: u64,
22
23 pub peer_addr: SocketAddr,
25
26 pub app: String,
28
29 pub encoder_type: EncoderType,
31
32 pub connect_params: Option<Arc<ConnectParams>>,
34
35 pub enhanced_capabilities: Option<EnhancedCapabilities>,
37
38 pub stats: SessionStats,
40}
41
42impl SessionContext {
43 pub fn new(session_id: u64, peer_addr: SocketAddr) -> Self {
45 Self {
46 session_id,
47 peer_addr,
48 app: String::new(),
49 encoder_type: EncoderType::Unknown,
50 connect_params: None,
51 enhanced_capabilities: None,
52 stats: SessionStats::default(),
53 }
54 }
55
56 pub fn with_connect(&mut self, params: ConnectParams, encoder_type: EncoderType) {
58 self.app = params.app.clone();
59 self.encoder_type = encoder_type;
60 self.connect_params = Some(Arc::new(params));
61 }
62
63 pub fn with_enhanced_capabilities(&mut self, caps: EnhancedCapabilities) {
65 if caps.enabled {
66 self.enhanced_capabilities = Some(caps);
67 }
68 }
69
70 pub fn is_enhanced_rtmp(&self) -> bool {
72 self.enhanced_capabilities
73 .as_ref()
74 .map(|c| c.enabled)
75 .unwrap_or(false)
76 }
77
78 pub fn tc_url(&self) -> Option<&str> {
80 self.connect_params
81 .as_ref()
82 .and_then(|p| p.tc_url.as_deref())
83 }
84
85 pub fn page_url(&self) -> Option<&str> {
87 self.connect_params
88 .as_ref()
89 .and_then(|p| p.page_url.as_deref())
90 }
91
92 pub fn flash_ver(&self) -> Option<&str> {
94 self.connect_params
95 .as_ref()
96 .and_then(|p| p.flash_ver.as_deref())
97 }
98}
99
100#[derive(Debug, Clone)]
102pub struct StreamContext {
103 pub session: SessionContext,
105
106 pub stream_id: u32,
108
109 pub stream_key: String,
111
112 pub is_publishing: bool,
114}
115
116impl StreamContext {
117 pub fn new(
119 session: SessionContext,
120 stream_id: u32,
121 stream_key: String,
122 is_publishing: bool,
123 ) -> Self {
124 Self {
125 session,
126 stream_id,
127 stream_key,
128 is_publishing,
129 }
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use std::net::{IpAddr, Ipv4Addr};
137
138 fn make_test_addr() -> SocketAddr {
139 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 54321)
140 }
141
142 #[test]
143 fn test_session_context_new() {
144 let addr = make_test_addr();
145 let ctx = SessionContext::new(42, addr);
146
147 assert_eq!(ctx.session_id, 42);
148 assert_eq!(ctx.peer_addr, addr);
149 assert_eq!(ctx.app, "");
150 assert_eq!(ctx.encoder_type, EncoderType::Unknown);
151 assert!(ctx.connect_params.is_none());
152 }
153
154 #[test]
155 fn test_session_context_with_connect() {
156 let addr = make_test_addr();
157 let mut ctx = SessionContext::new(1, addr);
158
159 let mut params = ConnectParams::default();
160 params.app = "live".to_string();
161 params.tc_url = Some("rtmp://localhost/live".to_string());
162 params.flash_ver = Some("FMLE/3.0".to_string());
163 params.page_url = Some("http://example.com".to_string());
164
165 ctx.with_connect(params, EncoderType::Obs);
166
167 assert_eq!(ctx.app, "live");
168 assert_eq!(ctx.encoder_type, EncoderType::Obs);
169 assert!(ctx.connect_params.is_some());
170 }
171
172 #[test]
173 fn test_session_context_tc_url() {
174 let addr = make_test_addr();
175 let mut ctx = SessionContext::new(1, addr);
176
177 assert!(ctx.tc_url().is_none());
179
180 let mut params = ConnectParams::default();
182 params.tc_url = Some("rtmp://server/app".to_string());
183 ctx.with_connect(params, EncoderType::Unknown);
184
185 assert_eq!(ctx.tc_url(), Some("rtmp://server/app"));
186 }
187
188 #[test]
189 fn test_session_context_page_url() {
190 let addr = make_test_addr();
191 let mut ctx = SessionContext::new(1, addr);
192
193 assert!(ctx.page_url().is_none());
195
196 let mut params = ConnectParams::default();
198 params.page_url = Some("http://twitch.tv".to_string());
199 ctx.with_connect(params, EncoderType::Unknown);
200
201 assert_eq!(ctx.page_url(), Some("http://twitch.tv"));
202 }
203
204 #[test]
205 fn test_session_context_flash_ver() {
206 let addr = make_test_addr();
207 let mut ctx = SessionContext::new(1, addr);
208
209 assert!(ctx.flash_ver().is_none());
211
212 let mut params = ConnectParams::default();
214 params.flash_ver = Some("OBS-Studio/29.1.3".to_string());
215 ctx.with_connect(params, EncoderType::Obs);
216
217 assert_eq!(ctx.flash_ver(), Some("OBS-Studio/29.1.3"));
218 }
219
220 #[test]
221 fn test_session_context_no_optional_params() {
222 let addr = make_test_addr();
223 let mut ctx = SessionContext::new(1, addr);
224
225 let params = ConnectParams::default();
227 ctx.with_connect(params, EncoderType::Ffmpeg);
228
229 assert!(ctx.tc_url().is_none());
230 assert!(ctx.page_url().is_none());
231 assert!(ctx.flash_ver().is_none());
232 }
233
234 #[test]
235 fn test_stream_context_new() {
236 let addr = make_test_addr();
237 let session_ctx = SessionContext::new(1, addr);
238
239 let stream_ctx =
240 StreamContext::new(session_ctx.clone(), 5, "my_stream_key".to_string(), true);
241
242 assert_eq!(stream_ctx.stream_id, 5);
243 assert_eq!(stream_ctx.stream_key, "my_stream_key");
244 assert!(stream_ctx.is_publishing);
245 assert_eq!(stream_ctx.session.session_id, 1);
246 }
247
248 #[test]
249 fn test_stream_context_playing() {
250 let addr = make_test_addr();
251 let session_ctx = SessionContext::new(2, addr);
252
253 let stream_ctx = StreamContext::new(session_ctx, 10, "viewer_stream".to_string(), false);
254
255 assert_eq!(stream_ctx.stream_id, 10);
256 assert_eq!(stream_ctx.stream_key, "viewer_stream");
257 assert!(!stream_ctx.is_publishing);
258 }
259
260 #[test]
261 fn test_session_context_clone() {
262 let addr = make_test_addr();
263 let mut ctx = SessionContext::new(1, addr);
264
265 let mut params = ConnectParams::default();
266 params.app = "test".to_string();
267 ctx.with_connect(params, EncoderType::Wirecast);
268
269 let cloned = ctx.clone();
270
271 assert_eq!(cloned.session_id, ctx.session_id);
272 assert_eq!(cloned.app, ctx.app);
273 assert_eq!(cloned.encoder_type, ctx.encoder_type);
274 }
275}