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