Skip to main content

o_sfu_telemetry/graph/
common.rs

1use std::collections::HashSet;
2
3use o_sfu_model::UserId;
4use serde_json::Value;
5
6use crate::diagnostics::types::{
7    DiagnosticsRoomDetail, DiagnosticsRouteState, DiagnosticsSource, DiagnosticsSubscription,
8    DiagnosticsTransportHealth, DiagnosticsUserView,
9};
10
11const STREAM_COLOR_PALETTE: &[&str] =
12    &["blue", "orange", "purple", "green", "yellow", "red", "gray"];
13
14pub(super) fn stream_id_label(stream_id: &str) -> &str {
15    if stream_id.is_empty() {
16        "source"
17    } else {
18        stream_id
19    }
20}
21
22pub(super) fn stream_id_color(stream_id: &str) -> &'static str {
23    let hash = stream_id.as_bytes().iter().fold(0_usize, |acc, byte| {
24        acc.wrapping_mul(31).wrapping_add(usize::from(*byte))
25    });
26    STREAM_COLOR_PALETTE
27        .get(hash % STREAM_COLOR_PALETTE.len())
28        .copied()
29        .unwrap_or("gray")
30}
31
32pub(super) fn transport_health_label(health: Option<&DiagnosticsTransportHealth>) -> &'static str {
33    match health {
34        Some(DiagnosticsTransportHealth::Connected) => "connected",
35        Some(DiagnosticsTransportHealth::Disconnected) => "disconnected",
36        None => "unknown",
37    }
38}
39
40pub(super) fn route_state_label(state: &DiagnosticsRouteState) -> &'static str {
41    match state {
42        DiagnosticsRouteState::Active => "active",
43        DiagnosticsRouteState::Inactive => "inactive",
44        DiagnosticsRouteState::Pending => "pending",
45    }
46}
47
48pub(super) fn route_state_color(state: &DiagnosticsRouteState) -> &'static str {
49    match state {
50        DiagnosticsRouteState::Active => "green",
51        DiagnosticsRouteState::Inactive => "gray",
52        DiagnosticsRouteState::Pending => "yellow",
53    }
54}
55
56pub(super) fn download_main_stat(sub: &DiagnosticsSubscription) -> String {
57    let stream_id = stream_id_label(&sub.stream_id);
58    match sub.selection.selected_rid.as_deref() {
59        Some(rid) if !rid.is_empty() => format!("{stream_id} {rid}"),
60        _ => stream_id.to_string(),
61    }
62}
63
64pub(super) fn push_unique_node(
65    nodes: &mut Vec<Value>,
66    seen: &mut HashSet<String>,
67    id: String,
68    node: Value,
69) {
70    if seen.insert(id) {
71        nodes.push(node);
72    }
73}
74
75pub(super) fn push_unique_edge(
76    edges: &mut Vec<Value>,
77    seen: &mut HashSet<String>,
78    id: String,
79    edge: Value,
80) {
81    if seen.insert(id) {
82        edges.push(edge);
83    }
84}
85
86pub(super) fn source_by_id(
87    detail: &DiagnosticsRoomDetail,
88    source_id: u64,
89) -> Option<&DiagnosticsSource> {
90    detail
91        .sources
92        .iter()
93        .find(|source| source.source_id == source_id)
94}
95
96pub(super) fn user_by_id<'a>(
97    detail: &'a DiagnosticsRoomDetail,
98    user_id: &UserId,
99) -> Option<&'a DiagnosticsUserView> {
100    detail.users.iter().find(|user| user.user_id == *user_id)
101}