diff --git a/src/main.rs b/src/main.rs index fa3be79..40ed4d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,8 +26,11 @@ async fn main() { .route("/join", get(test_explore_server)); tracing::info!("serving mumble-stats-api"); - let listener = tokio::net::TcpListener::bind("127.0.0.1:57039").await.unwrap(); - axum::serve(listener, app).await.unwrap() + let listener = tokio::net::TcpListener::bind("127.0.0.1:57039").await + .expect("could not bind on requested addr"); + + axum::serve(listener, app).await + .expect("could not serve axum app"); } #[derive(serde::Deserialize)] @@ -39,10 +42,73 @@ struct ExploreOptions { tokens: Option>, } -async fn test_explore_server(Query(options): Query) -> Result>, String> { - let mut channel = ControlChannel::new(&options.host, options.port).await.unwrap(); +#[derive(Debug, serde::Serialize)] +pub struct User { + /// Unique user session ID of the user whose state this is, may change on + /// reconnect. + pub session: u32, + + /// The session of the user who is updating this user. + pub actor: u32, + + /// User name, UTF-8 encoded. + pub name: String, + + /// Registered user ID if the user is registered. + pub user_id: Option, + + /// User comment if it is less than 128 bytes. + pub comment: Option, + + pub properties: UserProperties, +} + +#[derive(Debug, serde::Serialize)] +pub struct UserProperties { + /// True if the user is muted by admin. + pub mute: bool, + /// True if the user is deafened by admin. + pub deaf: bool, + /// True if the user has been suppressed from talking by a reason other than + /// being muted. + pub suppress: bool, + /// True if the user has muted self. + pub self_mute: bool, + /// True if the user has deafened self. + pub self_deaf: bool, + /// True if the user is a priority speaker. + pub priority_speaker: bool, + /// True if the user is currently recording. + pub recording: bool, +} + +impl From for User { + fn from(value: tcp::proto::UserState) -> Self { + User { + session: value.session(), + actor: value.actor(), + name: value.name().to_string(), + user_id: value.user_id, + comment: value.comment.clone(), + properties: UserProperties { + mute: value.mute(), + deaf: value.deaf(), + suppress: value.suppress(), + self_mute: value.self_mute(), + self_deaf: value.self_deaf(), + priority_speaker: value.priority_speaker(), + recording: value.recording(), + }, + } + } +} + +async fn test_explore_server(Query(options): Query) -> Result>, String> { + let Ok(mut channel) = ControlChannel::new(&options.host, options.port).await else { + return Err("could not connect to server".into()); + }; let version = tcp::proto::Version { - version_v1: None, // Some(67071), + version_v1: None, version_v2: Some(281496485429248), release: Some("1.5.517".into()), os: None, @@ -51,14 +117,20 @@ async fn test_explore_server(Query(options): Query) -> Result) -> Result break Err(format!("error receiving from server: {e}")), // Ok(tcp::proto::Packet::TextMessage(msg)) => tracing::info!("{}", msg.message), // Ok(tcp::proto::Packet::ChannelState(channel)) => tracing::info!("discovered channel: {:?}", channel.name), - Ok(tcp::proto::Packet::UserState(user)) => users.push(user.name.as_deref().unwrap_or("???").to_string()), + Ok(tcp::proto::Packet::UserState(user)) => users.push(user.into()), Ok(tcp::proto::Packet::ServerSync(_sync)) => break Ok(Json(users)), Ok(pkt) => tracing::debug!("ignoring packet {:#?}", pkt), }