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
+16 -5
View File
@@ -12,14 +12,14 @@ use crate::daemon::proto::{
Ack, AuthParams, AuthResult, CODE_APPLICATION, ChatMessageDto,
DaemonStatus, DirectoriesParams, DirectoryParams, DownloadDto,
DownloadStartParams, DownloadStarted, Downloads, Event, IntervalSeconds,
Members, MessageParams, Messages, Method, PROTOCOL_VERSION, QueryParams,
Request, Response, RoomRef, RpcError, SayParams, SearchResults, Searches,
Seconds, SharesStatus, SlotsParams, TransferRef, Uploads, UserRef,
UserResult,
MemberStats, Members, MessageParams, Messages, Method, PROTOCOL_VERSION,
QueryParams, Request, Response, RoomRef, RpcError, SayParams,
SearchResults, Searches, Seconds, SharesStatus, SlotsParams, TransferRef,
Uploads, UserRef, UserResult,
};
use mirror::Mirror;
use serde::de::DeserializeOwned;
use soulseek_rs::types::{Download, DownloadMetadata};
use soulseek_rs::types::{Download, DownloadMetadata, RoomUserStats};
use soulseek_rs::{
DownloadStatus, Result, RoomEvent, SearchResult, SessionLoss,
SharedDirectory, SoulseekRs, UploadInfo, UserInfo, UserMessage,
@@ -710,6 +710,17 @@ impl SessionApi for RemoteSession {
.unwrap_or_default()
}
fn room_member_stats(&self, room: &str) -> Vec<RoomUserStats> {
self.request::<_, MemberStats>(
Method::RoomMemberStats,
RoomRef {
room: room.to_string(),
},
)
.map(|stats| stats.members.into_iter().map(Into::into).collect())
.unwrap_or_default()
}
fn take_room_events(&self) -> Vec<RoomEvent> {
self.mirror.take_rooms()
}