Files
SoulStream/crates/soulseek-client/examples/citizen.rs
T
KeelrLeek a667b4b28e Baseline: full tree snapshot after git repository loss
The previous .git directory was found gutted (only info/ remained), so
history is unrecoverable locally. This commit restores version control
with the tree exactly as it stands: the working app, the preview-tracks
launcher on the artist hero, the scrollable-track-previews design bundle
(docs + approved mockups), and the Phase 0 validation artifacts.
2026-07-22 17:57:00 -05:00

87 lines
3.0 KiB
Rust

//! Live citizenship test: share our downloaded albums, join the distributed
//! network, and report every search we answer for real peers.
//!
//! cargo run -p soulseek-client --example citizen
use soulseek_client::{Client, Config, Event};
#[tokio::main]
async fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let suffix = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.subsec_nanos()
% 100_000;
let username = format!("ssplusshare{suffix}");
let music = dirs_music().join("SoulSeek+");
let mut config = Config::default();
config.shared_folders = vec![music.clone()];
config.upload_slots = 4;
config.description = "SoulSeek+ dev share".into();
println!("sharing {}…", music.display());
let (client, mut events) = Client::connect(config).await.expect("connect");
let (dirs, files) = client.share_counts();
println!("indexed {files} files in {dirs} folders");
client
.login(&username, "ssplusdev-throwaway")
.await
.expect("login");
println!("logged in as {username}; joining network, waiting for searches to answer…\n");
let mut answered = 0usize;
let mut uploads = 0usize;
let start = tokio::time::Instant::now();
let deadline = start + std::time::Duration::from_secs(180);
let mut next_tick = start + std::time::Duration::from_secs(20);
loop {
let ev = tokio::select! {
ev = events.recv() => ev,
_ = tokio::time::sleep_until(next_tick) => {
next_tick += std::time::Duration::from_secs(20);
println!(
" … {}s: parent={}, {} searches seen, {answered} answered",
start.elapsed().as_secs(),
client.has_parent(),
client.searches_seen(),
);
if tokio::time::Instant::now() >= deadline { break; }
continue;
}
};
match ev {
Some(Event::RespondedToSearch { username, files }) => {
answered += 1;
if answered <= 25 {
println!(" ✓ answered {username} with {files} file(s)");
}
}
Some(Event::Upload(u)) => {
uploads += 1;
println!(" ⬆ upload to {}: {:?} {}", u.username, u.state, u.filename);
}
Some(Event::Disconnected { reason }) => {
println!("disconnected: {reason}");
break;
}
_ => {}
}
}
println!(
"\nRESULT: {} searches seen, {answered} answered, {uploads} upload events",
client.searches_seen(),
);
client.shutdown();
}
fn dirs_music() -> std::path::PathBuf {
// %USERPROFILE%\Music
let profile = std::env::var("USERPROFILE").unwrap_or_else(|_| ".".into());
std::path::PathBuf::from(profile).join("Music")
}