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,57 @@
|
||||
//! Best-effort UPnP port mapping so firewalled peers can reach our
|
||||
//! listener directly. Failure is non-fatal — Soulseek's indirect
|
||||
//! (server-relayed) connection path still works without it.
|
||||
|
||||
use std::net::SocketAddrV4;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Try to map `port` (TCP) on the local gateway to ourselves. Returns the
|
||||
/// external address on success. Runs on a blocking thread.
|
||||
pub(crate) async fn try_map_port(port: u16) {
|
||||
let result = tokio::task::spawn_blocking(move || map_blocking(port)).await;
|
||||
match result {
|
||||
Ok(Ok(external)) => log::info!("UPnP: mapped port {port} (external {external})"),
|
||||
Ok(Err(e)) => log::info!("UPnP unavailable ({e}); relying on indirect connections"),
|
||||
Err(_) => log::debug!("UPnP task panicked"),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_blocking(port: u16) -> Result<SocketAddrV4, String> {
|
||||
use igd_next::{search_gateway, PortMappingProtocol, SearchOptions};
|
||||
|
||||
let gateway = search_gateway(SearchOptions {
|
||||
timeout: Some(Duration::from_secs(5)),
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Find our LAN address facing the gateway.
|
||||
let local_ip = local_ipv4().ok_or_else(|| "no local IPv4".to_string())?;
|
||||
let local = SocketAddrV4::new(local_ip, port);
|
||||
|
||||
gateway
|
||||
.add_port(
|
||||
PortMappingProtocol::TCP,
|
||||
port,
|
||||
std::net::SocketAddr::V4(local),
|
||||
0, // lease 0 = indefinite (until router reboots)
|
||||
"SoulStream",
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
match gateway.get_external_ip() {
|
||||
Ok(std::net::IpAddr::V4(ip)) => Ok(SocketAddrV4::new(ip, port)),
|
||||
_ => Ok(local),
|
||||
}
|
||||
}
|
||||
|
||||
/// Discover our LAN IPv4 by opening a UDP socket toward a public address
|
||||
/// (no packets are actually sent).
|
||||
fn local_ipv4() -> Option<std::net::Ipv4Addr> {
|
||||
let sock = std::net::UdpSocket::bind("0.0.0.0:0").ok()?;
|
||||
sock.connect("8.8.8.8:80").ok()?;
|
||||
match sock.local_addr().ok()?.ip() {
|
||||
std::net::IpAddr::V4(ip) => Some(ip),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user