forked from Keelrleek/SoulStream
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.
This commit is contained in:
commit
a667b4b28e
161 files changed
+53170
No files matched your search
@@ -0,0 +1,86 @@
|
||||
//! 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")
|
||||
}
|
||||
Reference in new issue
Block a user