feat: browse your own shares as a peer receives them

The window could show any peer's share tree but never this account's, so
"am I actually sharing that?" had no answer short of asking a friend to
browse you. The tree is already there; what was missing was feeding it
from our own index.

B opens it — the same collapsible tree, filter, and navigation the peer
browse offers, built from `Shares::directories()`, which is the listing
GetShareFileList answers with. So what it shows is what the network sees,
not what the config meant to share. r re-scans the disk rather than
re-asking a peer, o steps across to the folders that feed it, and nothing
here queues a download from ourselves.

Attached to a daemon the index lives on the daemon's host, so it comes
back over a new `shares.files` method rather than being scanned locally;
`shares files [--filter]` prints the same listing headless, through the
`emit_listing` that `browse` now shares with it — the two are only
comparable while they are built the same way.

Two allocation fixes came out of the review, both on paths this reaches:
the daemon hands its listing to the DTO instead of deep-copying one it
already owns, and `Shares::directories()` allocates its map key once per
folder rather than once per file, which the peer-facing serve path has
been paying for all along.
This commit is contained in:
Michel de Graaf
2026-09-10 11:44:57 +02:00
parent d6d870b39f
commit 26b551d997
24 changed files with 606 additions and 57 deletions
+14 -2
View File
@@ -13,8 +13,9 @@ use super::proto::{
MemberStats, Members, MessageParams, Messages, Method, OPENRPC,
PROTOCOL_VERSION, PasswordParams, QueryParams, RoomRef, RoomUserStatsDto,
RpcError, SayParams, SearchResultDto, SearchResults, SearchSummary,
Searches, Seconds, SharesStatus, SlotsParams, TransferRef, UploadInfoDto,
Uploads, UserInfoDto, UserRef, UserResult, Watched,
Searches, Seconds, SharedDirectoryDto, SharedListing, SharesStatus,
SlotsParams, TransferRef, UploadInfoDto, Uploads, UserInfoDto, UserRef,
UserResult, Watched,
};
use crate::api::SessionApi;
use crate::output::Exit;
@@ -372,6 +373,14 @@ impl Daemon {
}
Method::SharesStatusOf => ok(self.shares()),
Method::SharesFiles => ok(SharedListing {
directories: self
.session
.shared_listing()
.into_iter()
.map(SharedDirectoryDto::from)
.collect(),
}),
Method::SharesSet => {
let directories: DirectoriesParams = parse(params)?;
self.session
@@ -1018,6 +1027,9 @@ mod tests {
fn shared_counts(&self) -> (u32, u32) {
(0, 0)
}
fn shared_listing(&self) -> Vec<soulseek_rs::SharedDirectory> {
Vec::new()
}
fn shared_directories(&self) -> Vec<String> {
Vec::new()
}