chore: restore product scaffold to rollback baseline
This commit is contained in:
@@ -355,8 +355,6 @@ pub struct BridgeChannel {
|
||||
pub struct BridgeClient {
|
||||
/// Stable client id.
|
||||
pub id: u64,
|
||||
/// Stable TeamSpeak unique identifier.
|
||||
pub uid: String,
|
||||
/// Channel id the client is currently in.
|
||||
pub channel: u64,
|
||||
/// Nickname.
|
||||
@@ -375,6 +373,61 @@ pub struct BridgeClient {
|
||||
pub talk_power_granted: bool,
|
||||
}
|
||||
|
||||
/// Rich profile and live connection details for one online client.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BridgeClientProfile {
|
||||
/// Stable online client id.
|
||||
pub id: u64,
|
||||
/// Channel the client is currently in.
|
||||
pub channel: u64,
|
||||
/// Nickname.
|
||||
pub name: String,
|
||||
/// TeamSpeak unique id.
|
||||
pub unique_id: String,
|
||||
/// Stable TeamSpeak database id, when visible.
|
||||
pub database_id: Option<u64>,
|
||||
/// ISO country code, when visible.
|
||||
pub country_code: String,
|
||||
/// User description, when visible.
|
||||
pub description: String,
|
||||
/// Client version string.
|
||||
pub version: String,
|
||||
/// Client platform string.
|
||||
pub platform: String,
|
||||
/// Account creation time as Unix seconds.
|
||||
pub created_unix_seconds: Option<i64>,
|
||||
/// Last connection time as Unix seconds.
|
||||
pub last_connected_unix_seconds: Option<i64>,
|
||||
/// Total historical connections.
|
||||
pub connections_total: Option<u64>,
|
||||
/// Current online duration in seconds.
|
||||
pub online_seconds: Option<i64>,
|
||||
/// Current idle time in milliseconds.
|
||||
pub idle_milliseconds: Option<i64>,
|
||||
/// Current ping in milliseconds.
|
||||
pub ping_milliseconds: Option<i64>,
|
||||
/// Client address. Empty when permission-gated.
|
||||
pub client_address: String,
|
||||
/// Resolved server group names.
|
||||
pub server_groups: Vec<String>,
|
||||
/// Resolved channel group name.
|
||||
pub channel_group: String,
|
||||
/// TeamSpeak avatar file path suffix.
|
||||
pub avatar_path: String,
|
||||
/// Downloaded bytes this month.
|
||||
pub bytes_downloaded_month: Option<u64>,
|
||||
/// Uploaded bytes this month.
|
||||
pub bytes_uploaded_month: Option<u64>,
|
||||
/// Downloaded bytes across all time.
|
||||
pub bytes_downloaded_total: Option<u64>,
|
||||
/// Uploaded bytes across all time.
|
||||
pub bytes_uploaded_total: Option<u64>,
|
||||
/// Client-to-server total packet loss ratio.
|
||||
pub packet_loss_client_to_server_total: Option<f32>,
|
||||
/// Server-to-client total packet loss ratio.
|
||||
pub packet_loss_server_to_client_total: Option<f32>,
|
||||
}
|
||||
|
||||
/// Server snapshot as seen by Dart.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BridgeSnapshot {
|
||||
@@ -396,6 +449,38 @@ pub struct BridgeSnapshot {
|
||||
pub own_client_id: u64,
|
||||
}
|
||||
|
||||
impl From<chanora_core::ClientProfile> for BridgeClientProfile {
|
||||
fn from(profile: chanora_core::ClientProfile) -> Self {
|
||||
Self {
|
||||
id: profile.id.0,
|
||||
channel: profile.channel.0,
|
||||
name: profile.name,
|
||||
unique_id: profile.unique_id,
|
||||
database_id: profile.database_id,
|
||||
country_code: profile.country_code,
|
||||
description: profile.description,
|
||||
version: profile.version,
|
||||
platform: profile.platform,
|
||||
created_unix_seconds: profile.created_unix_seconds,
|
||||
last_connected_unix_seconds: profile.last_connected_unix_seconds,
|
||||
connections_total: profile.connections_total,
|
||||
online_seconds: profile.online_seconds,
|
||||
idle_milliseconds: profile.idle_milliseconds,
|
||||
ping_milliseconds: profile.ping_milliseconds,
|
||||
client_address: profile.client_address,
|
||||
server_groups: profile.server_groups,
|
||||
channel_group: profile.channel_group,
|
||||
avatar_path: profile.avatar_path,
|
||||
bytes_downloaded_month: profile.bytes_downloaded_month,
|
||||
bytes_uploaded_month: profile.bytes_uploaded_month,
|
||||
bytes_downloaded_total: profile.bytes_downloaded_total,
|
||||
bytes_uploaded_total: profile.bytes_uploaded_total,
|
||||
packet_loss_client_to_server_total: profile.packet_loss_client_to_server_total,
|
||||
packet_loss_server_to_client_total: profile.packet_loss_server_to_client_total,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<chanora_core::ServerSnapshot> for BridgeSnapshot {
|
||||
fn from(s: chanora_core::ServerSnapshot) -> Self {
|
||||
Self {
|
||||
@@ -420,7 +505,6 @@ impl From<chanora_core::ServerSnapshot> for BridgeSnapshot {
|
||||
.into_iter()
|
||||
.map(|c| BridgeClient {
|
||||
id: c.id.0,
|
||||
uid: c.uid,
|
||||
channel: c.channel.0,
|
||||
name: c.name,
|
||||
input_muted: c.input_muted,
|
||||
@@ -459,6 +543,7 @@ pub async fn connect(
|
||||
},
|
||||
identity: None,
|
||||
ready_timeout: Duration::from_secs(15),
|
||||
resolved_address: None,
|
||||
};
|
||||
let snap = match runtime()
|
||||
.spawn(async move { session().connect(cfg).await })
|
||||
@@ -475,6 +560,17 @@ pub async fn connect(
|
||||
Ok(snap.into())
|
||||
}
|
||||
|
||||
/// Warm server address resolution for the active host field. This is
|
||||
/// intentionally fire-and-forget from the UI perspective: it schedules
|
||||
/// Rust-side prefetch work and never opens a TS3 session.
|
||||
pub async fn prefetch_server(host: String) -> Result<(), BridgeError> {
|
||||
runtime()
|
||||
.spawn(async move { session().prefetch_server(host).await })
|
||||
.await
|
||||
.map_err(|e| task_join_error("prefetch_server", e))??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Re-fetch a fresh snapshot from the active connection.
|
||||
pub async fn snapshot() -> Result<BridgeSnapshot, BridgeError> {
|
||||
let snap = runtime()
|
||||
@@ -484,6 +580,15 @@ pub async fn snapshot() -> Result<BridgeSnapshot, BridgeError> {
|
||||
Ok(snap.into())
|
||||
}
|
||||
|
||||
/// Fetch richer profile and live connection details for one online client.
|
||||
pub async fn client_profile(client_id: u64) -> Result<BridgeClientProfile, BridgeError> {
|
||||
let profile = runtime()
|
||||
.spawn(async move { session().client_profile(client_id).await })
|
||||
.await
|
||||
.map_err(|e| task_join_error("client_profile", e))??;
|
||||
Ok(profile.into())
|
||||
}
|
||||
|
||||
/// Disconnect from the server. No-op if not connected.
|
||||
pub async fn disconnect() -> Result<(), BridgeError> {
|
||||
runtime()
|
||||
@@ -816,9 +921,10 @@ pub async fn set_input_muted(muted: bool) -> Result<(), BridgeError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Toggle self output-mute (speaker). Mutes locally, informs the
|
||||
/// server, and clamps local microphone transmit while speaker mute
|
||||
/// is active so the user cannot continue talking while deafened.
|
||||
/// Toggle self output-mute (speaker). Mutes locally *and* informs
|
||||
/// the server. The server uses this for the channel icon next to
|
||||
/// the client name; the local mute kicks in immediately even
|
||||
/// before the server acknowledges.
|
||||
pub async fn set_output_muted(muted: bool) -> Result<(), BridgeError> {
|
||||
runtime()
|
||||
.spawn(async move { session().set_self_muted(None, Some(muted)).await })
|
||||
@@ -1229,7 +1335,8 @@ impl From<chanora_core::AudioProcessingStats> for BridgeAudioProcessingStats {
|
||||
/// On non-Android targets or before a voice session opens the
|
||||
/// section is omitted. Per SDD-090 every field in that section is
|
||||
/// a device-side technical scalar — no PII admitted.
|
||||
pub async fn export_diagnostics() -> String {
|
||||
#[frb(sync)]
|
||||
pub fn export_diagnostics() -> String {
|
||||
let metadata = vec![
|
||||
(
|
||||
"crate_version".to_string(),
|
||||
@@ -1245,15 +1352,12 @@ pub async fn export_diagnostics() -> String {
|
||||
// diagnostics snapshot from the process-global slot published
|
||||
// by AndroidVoiceUnit::open(). Returns None on non-Android and
|
||||
// before any voice session has opened.
|
||||
#[cfg(target_os = "android")]
|
||||
let android_audio_yaml =
|
||||
chanora_audio::mobile_voice_backend::current_android_audio_diagnostics()
|
||||
.map(|d| d.to_yaml_fragment());
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let android_audio_yaml: Option<String> = None;
|
||||
let audio_health = session().audio_processing_stats().await.ok();
|
||||
let network_info = session().network_diagnostics_summary().await;
|
||||
let protocol_events = session().drain_protocol_events().await;
|
||||
let audio_health = session().audio_processing_stats_if_ready();
|
||||
let network_info = runtime().block_on(async { session().network_diagnostics_summary().await });
|
||||
let protocol_events = runtime().block_on(async { session().protocol_events_snapshot().await });
|
||||
let android_audio_yaml = android_audio_yaml.map(|mut yaml| {
|
||||
if let Some(stats) = audio_health {
|
||||
yaml.push_str(&format!(
|
||||
|
||||
Reference in New Issue
Block a user