Skip to main content

o_sfu_core/engine/room/
definition.rs

1//! Room identity and immutable runtime policy.
2//!
3//! A room has two identities:
4//!
5//! ```text
6//! Odoo-facing identity        Runtime-local placement
7//! issuer, uuid, key           instance, router, media worker
8//! ```
9//!
10//! The first identity is visible at the HTTP and websocket edge. The second
11//! identity is process-local and drives transport ownership, diagnostics and
12//! room topology. Mutable committed routing directories live in `RoomState`
13//! rather than in this immutable definition.
14
15use uuid::Uuid;
16
17use super::{RoomConfig, RoomRuntimeContext, RoomRuntimePolicy};
18use crate::{
19    RoomWorkerPolicy, RuntimeFeatureFlags,
20    engine::{AvailableFeatures, RoomInstanceId},
21};
22
23/// Central gate for exposing recording as a production room capability.
24///
25/// This must become true only when accepted recording controls can produce the
26/// promised persistent artifact or handoff.
27const fn persistent_recording_backend_available() -> bool {
28    false
29}
30
31#[derive(Debug, Clone)]
32struct RoomIdentity {
33    uuid: String,
34    issuer: String,
35    key: String,
36}
37
38impl RoomIdentity {
39    fn new(issuer: String, key: String) -> Self {
40        Self {
41            uuid: Uuid::new_v4().to_string(),
42            issuer,
43            key,
44        }
45    }
46}
47
48#[derive(Debug, Clone)]
49pub(crate) struct RoomDefinition {
50    /// Live room instance id used by runtime diagnostics and transport keys.
51    ///
52    /// Recreating a room for the same issuer allocates a fresh instance id so
53    /// stale transport work cannot be confused with the new room lifetime.
54    instance_id: RoomInstanceId,
55    room_worker_policy: RoomWorkerPolicy,
56    identity: RoomIdentity,
57    config: RoomConfig,
58    feature_flags: RuntimeFeatureFlags,
59}
60
61impl RoomDefinition {
62    #[must_use]
63    pub(crate) fn new(
64        runtime_context: &RoomRuntimeContext,
65        runtime_policy: &RoomRuntimePolicy,
66        issuer: String,
67        key: String,
68        config: RoomConfig,
69    ) -> Self {
70        Self {
71            instance_id: runtime_context.instance(),
72            room_worker_policy: runtime_policy.room_worker_policy,
73            identity: RoomIdentity::new(issuer, key),
74            config,
75            feature_flags: runtime_policy.feature_flags,
76        }
77    }
78
79    #[must_use]
80    pub(crate) fn matches_reservation(&self, key: &str, config: &RoomConfig) -> bool {
81        self.identity.key == key && self.config == *config
82    }
83
84    #[must_use]
85    pub(crate) fn uuid(&self) -> &str {
86        &self.identity.uuid
87    }
88
89    #[must_use]
90    pub(crate) fn issuer(&self) -> &str {
91        &self.identity.issuer
92    }
93
94    #[must_use]
95    pub(crate) fn key(&self) -> &str {
96        &self.identity.key
97    }
98
99    #[must_use]
100    pub(crate) fn available_features(&self) -> AvailableFeatures {
101        let recording_available = self.recording_available();
102        AvailableFeatures {
103            rtc: self.config.web_rtc_enabled,
104            transcription: recording_available && self.feature_flags.transcription,
105            audio_recording: recording_available && self.feature_flags.audio_recording,
106            video_recording: recording_available && self.feature_flags.video_recording,
107        }
108    }
109
110    #[must_use]
111    pub(crate) const fn web_rtc_enabled(&self) -> bool {
112        self.config.web_rtc_enabled
113    }
114
115    #[must_use]
116    pub(crate) const fn recording_available(&self) -> bool {
117        if self.config.recording_address.is_none() {
118            return false;
119        }
120        persistent_recording_backend_available()
121    }
122
123    #[cfg(any(test, feature = "testing-transport"))]
124    #[must_use]
125    pub fn recording_address(&self) -> Option<&str> {
126        self.config.recording_address.as_deref()
127    }
128
129    #[must_use]
130    pub(crate) fn room_worker_policy(&self) -> RoomWorkerPolicy {
131        self.room_worker_policy
132    }
133
134    #[must_use]
135    pub(crate) const fn instance_id(&self) -> RoomInstanceId {
136        self.instance_id
137    }
138}