//! 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") }