feat(daemon): publish room member statistics over RPC and the CLI

The statistics parsed from the JoinRoom reply were reachable only from the
library. They answer the question `room users` already exists to ask -- who
is in here, and are they worth downloading from -- so they belong on its
output rather than behind a second call.

- proto: room.member_stats, with a RoomUserStatsDto carrying status, share
  counts, free slots and country
- SessionApi::room_member_stats, so local and remote sessions stay
  interchangeable; the status word is decoded through one shared helper
  rather than a third copy of the match
- `room users` now emits status, average_speed, shared_files,
  shared_folders, slots_free and country, each null when the server said
  nothing, documented in SKILL.md
- docs/openrpc.json regenerated from the wire types
This commit is contained in:
Michel de Graaf
2026-08-28 13:27:09 +00:00
parent fa49ebd2eb
commit 60f7100e30
12 changed files with 288 additions and 27 deletions
+8 -1
View File
@@ -13,7 +13,7 @@
//! remote session has no borrowed client to hand a `&str` out of.
use crate::daemon::proto::ChatMessageDto;
use soulseek_rs::types::{Download, DownloadMetadata};
use soulseek_rs::types::{Download, DownloadMetadata, RoomUserStats};
use soulseek_rs::{
Client, DownloadStatus, Result, RoomEvent, SearchResult, SessionLoss,
SharedDirectory, UploadInfo, UserInfo, UserMessage,
@@ -126,6 +126,9 @@ pub trait SessionApi: Send + Sync {
fn leave_room(&self, room: &str) -> Result<()>;
fn say_in_room(&self, room: &str, message: &str) -> Result<()>;
fn room_members(&self, room: &str) -> Vec<String>;
/// What the server said about each member when the room was joined:
/// status, share statistics, free upload slots and country.
fn room_member_stats(&self, room: &str) -> Vec<RoomUserStats>;
fn take_room_events(&self) -> Vec<RoomEvent>;
fn send_private_message(&self, username: &str, message: &str)
@@ -329,6 +332,10 @@ impl SessionApi for Client {
Self::room_members(self, room)
}
fn room_member_stats(&self, room: &str) -> Vec<RoomUserStats> {
Self::room_member_stats(self, room)
}
fn take_room_events(&self) -> Vec<RoomEvent> {
Self::take_room_events(self)
}