rvoip_client_core/registration.rs
1//! Registration management for SIP client
2//!
3//! This module provides registration information structures and configuration for
4//! SIP registration with registrar servers. All actual SIP registration operations
5//! are delegated to session-core.
6//!
7//! # Architecture
8//!
9//! PROPER LAYER SEPARATION:
10//! client-core -> session-core -> {transaction-core, media-core, sip-transport, sip-core}
11//!
12//! # Key Components
13//!
14//! - **RegistrationConfig** - Configuration for SIP registration
15//! - **RegistrationStatus** - Current state of a registration
16//! - **RegistrationInfo** - Complete registration details and metadata
17//! - **RegistrationStats** - Aggregate statistics about registrations
18//!
19//! # SIP Registration Process
20//!
21//! 1. **Configuration** - Define server, credentials, and parameters
22//! 2. **Registration** - Send REGISTER request to SIP server
23//! 3. **Authentication** - Handle authentication challenge if required
24//! 4. **Maintenance** - Periodically refresh registration before expiry
25//! 5. **Termination** - Unregister when shutting down
26//!
27//! # Usage Examples
28//!
29//! ## Creating Registration Configuration
30//!
31//! ```rust
32//! use rvoip_client_core::registration::RegistrationConfig;
33//!
34//! // Basic registration without authentication
35//! let config = RegistrationConfig::new(
36//! "sip:registrar.example.com".to_string(),
37//! "sip:alice@example.com".to_string(),
38//! "sip:alice@192.168.1.100:5060".to_string(),
39//! );
40//!
41//! // Registration with authentication
42//! let auth_config = RegistrationConfig::new(
43//! "sip:registrar.example.com".to_string(),
44//! "sip:alice@example.com".to_string(),
45//! "sip:alice@192.168.1.100:5060".to_string(),
46//! )
47//! .with_credentials("alice".to_string(), "secret123".to_string())
48//! .with_realm("example.com".to_string())
49//! .with_expires(1800); // 30 minutes
50//!
51//! assert_eq!(auth_config.expires, 1800);
52//! assert_eq!(auth_config.username, Some("alice".to_string()));
53//! ```
54//!
55//! ## Working with Registration Status
56//!
57//! ```rust
58//! use rvoip_client_core::registration::RegistrationStatus;
59//!
60//! let status = RegistrationStatus::Active;
61//! println!("Registration status: {}", status);
62//!
63//! assert_eq!(status, RegistrationStatus::Active);
64//! assert_ne!(status, RegistrationStatus::Failed);
65//! ```
66//!
67//! ## Creating Registration Information
68//!
69//! ```rust
70//! use rvoip_client_core::registration::{RegistrationInfo, RegistrationStatus};
71//! use chrono::Utc;
72//! use uuid::Uuid;
73//!
74//! let reg_info = RegistrationInfo {
75//! id: Uuid::new_v4(),
76//! server_uri: "sip:registrar.example.com".to_string(),
77//! from_uri: "sip:alice@example.com".to_string(),
78//! contact_uri: "sip:alice@192.168.1.100:5060".to_string(),
79//! expires: 3600,
80//! status: RegistrationStatus::Active,
81//! registration_time: Utc::now(),
82//! refresh_time: Some(Utc::now()),
83//! handle: None,
84//! };
85//!
86//! assert_eq!(reg_info.status, RegistrationStatus::Active);
87//! assert_eq!(reg_info.expires, 3600);
88//! ```
89
90use serde::{Deserialize, Serialize};
91use uuid::Uuid;
92use chrono::{DateTime, Utc};
93use rvoip_session_core::api::RegistrationHandle;
94
95/// Registration configuration for SIP server registration
96///
97/// Contains all necessary parameters to register with a SIP registrar server,
98/// including server details, user identity, authentication credentials,
99/// and registration timing parameters.
100///
101/// # Examples
102///
103/// ```rust
104/// use rvoip_client_core::registration::RegistrationConfig;
105///
106/// let config = RegistrationConfig::new(
107/// "sip:registrar.example.com".to_string(),
108/// "sip:alice@example.com".to_string(),
109/// "sip:alice@192.168.1.100:5060".to_string(),
110/// )
111/// .with_credentials("alice".to_string(), "password123".to_string())
112/// .with_expires(1800);
113///
114/// assert_eq!(config.server_uri, "sip:registrar.example.com");
115/// assert_eq!(config.username, Some("alice".to_string()));
116/// assert_eq!(config.expires, 1800);
117/// ```
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct RegistrationConfig {
120 /// SIP registrar server URI (e.g., "sip:registrar.example.com")
121 ///
122 /// The URI of the SIP registrar server where this client will register.
123 /// This should include the scheme (sip: or sips:) and may include port.
124 pub server_uri: String,
125
126 /// From URI representing the user identity (e.g., "sip:alice@example.com")
127 ///
128 /// The SIP address that identifies this user. This appears in the From
129 /// header of REGISTER requests and represents the user's public identity.
130 pub from_uri: String,
131
132 /// Contact URI for this client (e.g., "sip:alice@192.168.1.100:5060")
133 ///
134 /// The SIP URI where this client can be reached for incoming calls.
135 /// Typically includes the client's current IP address and port.
136 pub contact_uri: String,
137
138 /// Registration expiration time in seconds
139 ///
140 /// How long the registration should remain valid. The client will
141 /// automatically refresh the registration before this time expires.
142 /// Common values: 3600 (1 hour), 1800 (30 minutes), 300 (5 minutes).
143 pub expires: u32,
144
145 /// Authentication username (optional)
146 ///
147 /// Username for SIP digest authentication. Required if the registrar
148 /// server requires authentication (most production servers do).
149 pub username: Option<String>,
150
151 /// Authentication password (optional)
152 ///
153 /// Password for SIP digest authentication. Should be kept secure
154 /// and not logged or displayed in plain text.
155 pub password: Option<String>,
156
157 /// Authentication realm (optional)
158 ///
159 /// Authentication realm provided by the server. Often the same as
160 /// the domain portion of the server URI. Usually provided by the
161 /// server in authentication challenges.
162 pub realm: Option<String>,
163}
164
165impl RegistrationConfig {
166 /// Create a new registration configuration with default settings
167 ///
168 /// Creates a basic registration configuration with a default expiration
169 /// of 3600 seconds (1 hour) and no authentication credentials.
170 ///
171 /// # Arguments
172 ///
173 /// * `server_uri` - URI of the SIP registrar server
174 /// * `from_uri` - SIP URI representing the user identity
175 /// * `contact_uri` - SIP URI where this client can be reached
176 ///
177 /// # Examples
178 ///
179 /// ```rust
180 /// use rvoip_client_core::registration::RegistrationConfig;
181 ///
182 /// let config = RegistrationConfig::new(
183 /// "sip:registrar.example.com".to_string(),
184 /// "sip:alice@example.com".to_string(),
185 /// "sip:alice@192.168.1.100:5060".to_string(),
186 /// );
187 ///
188 /// assert_eq!(config.expires, 3600); // Default 1 hour
189 /// assert_eq!(config.username, None); // No auth by default
190 /// ```
191 pub fn new(server_uri: String, from_uri: String, contact_uri: String) -> Self {
192 Self {
193 server_uri,
194 from_uri,
195 contact_uri,
196 expires: 3600, // Default to 1 hour
197 username: None,
198 password: None,
199 realm: None,
200 }
201 }
202
203 /// Set authentication credentials for the registration
204 ///
205 /// Configures username and password for SIP digest authentication.
206 /// Most production SIP servers require authentication.
207 ///
208 /// # Arguments
209 ///
210 /// * `username` - Authentication username
211 /// * `password` - Authentication password
212 ///
213 /// # Examples
214 ///
215 /// ```rust
216 /// use rvoip_client_core::registration::RegistrationConfig;
217 ///
218 /// let config = RegistrationConfig::new(
219 /// "sip:registrar.example.com".to_string(),
220 /// "sip:alice@example.com".to_string(),
221 /// "sip:alice@192.168.1.100:5060".to_string(),
222 /// )
223 /// .with_credentials("alice".to_string(), "secret123".to_string());
224 ///
225 /// assert_eq!(config.username, Some("alice".to_string()));
226 /// assert_eq!(config.password, Some("secret123".to_string()));
227 /// ```
228 pub fn with_credentials(mut self, username: String, password: String) -> Self {
229 self.username = Some(username);
230 self.password = Some(password);
231 self
232 }
233
234 /// Set the authentication realm for the registration
235 ///
236 /// The realm is usually provided by the server during authentication
237 /// challenges, but can be set in advance if known.
238 ///
239 /// # Arguments
240 ///
241 /// * `realm` - Authentication realm (often the server domain)
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use rvoip_client_core::registration::RegistrationConfig;
247 ///
248 /// let config = RegistrationConfig::new(
249 /// "sip:registrar.example.com".to_string(),
250 /// "sip:alice@example.com".to_string(),
251 /// "sip:alice@192.168.1.100:5060".to_string(),
252 /// )
253 /// .with_realm("example.com".to_string());
254 ///
255 /// assert_eq!(config.realm, Some("example.com".to_string()));
256 /// ```
257 pub fn with_realm(mut self, realm: String) -> Self {
258 self.realm = Some(realm);
259 self
260 }
261
262 /// Set the registration expiration time
263 ///
264 /// Controls how long the registration remains valid before requiring
265 /// a refresh. Shorter times provide faster failover detection but
266 /// increase network traffic.
267 ///
268 /// # Arguments
269 ///
270 /// * `expires` - Expiration time in seconds
271 ///
272 /// # Examples
273 ///
274 /// ```rust
275 /// use rvoip_client_core::registration::RegistrationConfig;
276 ///
277 /// let config = RegistrationConfig::new(
278 /// "sip:registrar.example.com".to_string(),
279 /// "sip:alice@example.com".to_string(),
280 /// "sip:alice@192.168.1.100:5060".to_string(),
281 /// )
282 /// .with_expires(1800); // 30 minutes
283 ///
284 /// assert_eq!(config.expires, 1800);
285 /// ```
286 pub fn with_expires(mut self, expires: u32) -> Self {
287 self.expires = expires;
288 self
289 }
290}
291
292/// Current status of a SIP registration
293///
294/// Represents the various states a registration can be in during its lifecycle,
295/// from initial setup through active registration to termination.
296///
297/// # State Transitions
298///
299/// Typical registration flow:
300/// `Pending` → `Active` → `Expired`/`Failed`/`Cancelled`
301///
302/// # Examples
303///
304/// ```rust
305/// use rvoip_client_core::registration::RegistrationStatus;
306///
307/// let status = RegistrationStatus::Active;
308/// println!("Status: {}", status); // Prints "Status: Active"
309///
310/// assert_eq!(status, RegistrationStatus::Active);
311/// assert_ne!(status, RegistrationStatus::Failed);
312/// ```
313#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
314pub enum RegistrationStatus {
315 /// Registration request has been sent but no response received yet
316 ///
317 /// Initial state when a REGISTER request is sent to the server.
318 /// The client is waiting for the server's response.
319 Pending,
320
321 /// Registration is active and valid
322 ///
323 /// The server has accepted the registration and it's currently valid.
324 /// The client can receive incoming calls and the registration will
325 /// be refreshed automatically before expiration.
326 Active,
327
328 /// Registration failed
329 ///
330 /// The server rejected the registration request, typically due to
331 /// authentication failure, invalid credentials, or server error.
332 /// This is a terminal state that requires manual intervention.
333 Failed,
334
335 /// Registration expired
336 ///
337 /// The registration validity period has elapsed and the registration
338 /// is no longer active. This can happen if refresh attempts fail
339 /// or if the client is disconnected for too long.
340 Expired,
341
342 /// Registration was cancelled by the client
343 ///
344 /// The client explicitly unregistered by sending a REGISTER request
345 /// with Expires: 0. This is the normal way to end a registration.
346 Cancelled,
347}
348
349impl std::fmt::Display for RegistrationStatus {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 match self {
352 RegistrationStatus::Pending => write!(f, "Pending"),
353 RegistrationStatus::Active => write!(f, "Active"),
354 RegistrationStatus::Failed => write!(f, "Failed"),
355 RegistrationStatus::Expired => write!(f, "Expired"),
356 RegistrationStatus::Cancelled => write!(f, "Cancelled"),
357 }
358 }
359}
360
361/// Comprehensive information about a SIP registration
362///
363/// Contains all details about a registration including configuration,
364/// current status, timing information, and technical handles.
365///
366/// # Examples
367///
368/// ```rust
369/// use rvoip_client_core::registration::{RegistrationInfo, RegistrationStatus};
370/// use chrono::Utc;
371/// use uuid::Uuid;
372///
373/// let reg_info = RegistrationInfo {
374/// id: Uuid::new_v4(),
375/// server_uri: "sip:registrar.example.com".to_string(),
376/// from_uri: "sip:alice@example.com".to_string(),
377/// contact_uri: "sip:alice@192.168.1.100:5060".to_string(),
378/// expires: 3600,
379/// status: RegistrationStatus::Active,
380/// registration_time: Utc::now(),
381/// refresh_time: Some(Utc::now()),
382/// handle: None,
383/// };
384///
385/// assert_eq!(reg_info.status, RegistrationStatus::Active);
386/// assert_eq!(reg_info.server_uri, "sip:registrar.example.com");
387/// ```
388#[derive(Debug, Clone)]
389pub struct RegistrationInfo {
390 /// Unique registration identifier assigned by the client
391 pub id: Uuid,
392
393 /// SIP registrar server URI where this registration is active
394 pub server_uri: String,
395
396 /// From URI representing the registered user identity
397 pub from_uri: String,
398
399 /// Contact URI where this client can be reached for incoming calls
400 pub contact_uri: String,
401
402 /// Registration expiration time in seconds from last refresh
403 pub expires: u32,
404
405 /// Current status of this registration
406 pub status: RegistrationStatus,
407
408 /// When the registration was initially created
409 pub registration_time: DateTime<Utc>,
410
411 /// When the registration was last successfully refreshed (if applicable)
412 pub refresh_time: Option<DateTime<Utc>>,
413
414 /// Internal handle to the session-core registration (if active)
415 pub handle: Option<RegistrationHandle>,
416}
417
418/// Statistics about SIP registrations in the system
419///
420/// Provides aggregate counts and metrics about registrations, useful for
421/// monitoring, debugging, and user interface displays.
422///
423/// # Examples
424///
425/// ```rust
426/// use rvoip_client_core::registration::RegistrationStats;
427///
428/// let stats = RegistrationStats {
429/// total_registrations: 5,
430/// active_registrations: 3,
431/// failed_registrations: 1,
432/// };
433///
434/// assert_eq!(stats.total_registrations, 5);
435/// assert_eq!(stats.active_registrations, 3);
436/// assert_eq!(stats.failed_registrations, 1);
437///
438/// // Calculate derived metrics
439/// let pending_registrations = stats.total_registrations - stats.active_registrations - stats.failed_registrations;
440/// assert_eq!(pending_registrations, 1);
441/// ```
442#[derive(Debug, Clone)]
443pub struct RegistrationStats {
444 /// Total number of registrations (all statuses)
445 pub total_registrations: usize,
446 /// Number of registrations in Active status
447 pub active_registrations: usize,
448 /// Number of registrations in Failed status
449 pub failed_registrations: usize,
450}