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
+35
View File
@@ -126,6 +126,41 @@ fn finished(tui: &MainTui, _: &str) -> bool {
tui.state().searches[0].status == SearchStatus::Completed
}
/// The window's answer to "am I actually sharing that?", against a real
/// scan of a real folder rather than a stand-in listing.
#[test]
fn shift_b_shows_the_scanned_index_the_way_a_peer_would_get_it() {
let server = server_or_skip!();
let share = tempfile::tempdir().expect("share dir");
std::fs::create_dir_all(share.path().join("album")).expect("subfolder");
std::fs::write(
share.path().join("album").join("tui_probe_own.bin"),
[3u8; 32],
)
.expect("share file");
let state = tempfile::tempdir().expect("state dir");
let downloads = tempfile::tempdir().expect("download dir");
let me = Arc::new(server.client(
"tui_e2e_own_shares",
vec![share.path().display().to_string()],
));
let mut window = Window::open(me, state.path(), downloads.path());
window.press(KeyCode::Char('B'));
window.press(KeyCode::Char('L'));
let screen = window.frame();
assert!(screen.contains("My shares"), "{screen}");
assert!(
screen.contains("album") && screen.contains("tui_probe_own.bin"),
"the scanned tree, folder by folder:\n{screen}"
);
window.press(KeyCode::Esc);
assert!(!window.tui.state().show_browse, "Esc hides the popup");
}
#[test]
fn shift_s_runs_a_restored_query_again_and_the_answers_land_on_screen() {
let server = server_or_skip!();