rvoip_core/config.rs
1use std::sync::Arc;
2use std::thread;
3use std::time::Duration;
4
5use crate::store::{
6 ConversationStore, MemoryConversationStore, MemoryMessageStore, MemoryVconStore, MessageStore,
7 VconStore,
8};
9
10/// P6 — per-tenant quota envelope. Each `None` means "unlimited".
11#[derive(Clone, Copy, Debug, Default)]
12pub struct TenantQuotas {
13 pub max_concurrent_sessions: Option<usize>,
14 pub max_concurrent_recordings: Option<usize>,
15 pub max_concurrent_ai_sessions: Option<usize>,
16}
17
18/// Orchestrator configuration.
19///
20/// Phase-2 admission semaphore default per `PERFORMANCE_PLAN.md`:
21/// `max_concurrent_setups = 256 * available_parallelism()`.
22#[derive(Clone)]
23pub struct Config {
24 pub max_concurrent_setups: usize,
25 /// Maximum number of distinct direct-media subscriber Connections
26 /// admitted by this Orchestrator across every UCTP ingress substrate.
27 ///
28 /// A subscriber with several stream routes consumes one slot. The slot is
29 /// released only after its final route is removed, its Connection closes,
30 /// or its Session is dropped. Relay-backed broadcast fanout is accounted
31 /// separately by the relay implementation.
32 pub max_direct_subscribers: usize,
33 pub conversation_store: Arc<dyn ConversationStore>,
34 pub vcon_store: Arc<dyn VconStore>,
35 /// P4 — message log + history pager. Default in-memory.
36 pub message_store: Arc<dyn MessageStore>,
37 /// How long `bridge_connections` waits for both peers' audio streams
38 /// to appear before failing the admission check. Adapters populate
39 /// streams lazily (typically on `connection.ready`), so a caller
40 /// that triggers a bridge from `Event::ConnectionInbound` may race
41 /// the stream registration. Setting this to zero disables the wait
42 /// (strict legacy behavior).
43 ///
44 /// **Default raised to 5 seconds** (plan §7 architectural concern
45 /// #7 / D3): the previous 2 seconds was tight for cold WebTransport
46 /// dials on a high-latency mobile link, where the TLS + HTTP/3 +
47 /// extended-CONNECT handshake routinely exceeds 2s. 5s covers
48 /// realistic mobile network jitter without holding admission for
49 /// pathologically dead peers.
50 pub bridge_stream_deadline: Duration,
51 /// Maximum time an outbound route may remain prepared or activating
52 /// without winning its final commit acknowledgement.
53 ///
54 /// A prepared route is deliberately invisible to Sessions and event
55 /// consumers while an application durably records its Connection ID.
56 /// Core aborts and closes the provisional adapter route when this
57 /// deadline expires. The same deadline fences a hung staged activation.
58 /// A finite default prevents abandoned durable-bind attempts or adapter
59 /// activation futures from retaining route capacity indefinitely.
60 pub outbound_preparation_timeout: Duration,
61 /// P6 — `Event::CapacityReport` emit cadence. None disables the
62 /// scheduler entirely.
63 pub capacity_report_interval: Option<Duration>,
64}
65
66impl Default for Config {
67 fn default() -> Self {
68 let cpus = thread::available_parallelism()
69 .map(|n| n.get())
70 .unwrap_or(1);
71 Self {
72 max_concurrent_setups: 256 * cpus,
73 max_direct_subscribers: 1_000,
74 conversation_store: Arc::new(MemoryConversationStore::new()),
75 vcon_store: Arc::new(MemoryVconStore::new()),
76 message_store: Arc::new(MemoryMessageStore::new()),
77 bridge_stream_deadline: Duration::from_secs(5),
78 outbound_preparation_timeout: Duration::from_secs(30),
79 capacity_report_interval: Some(Duration::from_secs(30)),
80 }
81 }
82}