o_sfu_telemetry/graph/
common.rs1use 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}