feat: relay ping handling, identity persistence, linux build script (backport)
Some checks failed
Mirror to GitHub / mirror (push) Failing after 40s
Build Release Binaries / build-amd64 (push) Failing after 3m46s

Backported from feat/android-voip-client:
- Relay: SNI "ping" connections handled gracefully (no timeout errors)
- Relay: identity persisted in ~/.wzp/relay-identity (stable fingerprint)
- Linux fire-and-forget build script (Hetzner VM)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-07 11:45:27 +04:00
parent 9f7962a6cd
commit 6d776097c8
4 changed files with 252 additions and 2979 deletions

View File

@@ -28,6 +28,7 @@ prometheus = "0.13"
axum = { version = "0.7", default-features = false, features = ["tokio", "http1", "ws"] }
tower-http = { version = "0.6", features = ["fs"] }
futures-util = "0.3"
dirs = "6"
[[bin]]
name = "wzp-relay"

View File

@@ -13,7 +13,7 @@ use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Mutex;
use tracing::{error, info};
use tracing::{error, info, warn};
use wzp_proto::MediaTransport;
use wzp_relay::config::RelayConfig;
@@ -207,8 +207,39 @@ async fn main() -> anyhow::Result<()> {
tokio::spawn(wzp_relay::metrics::serve_metrics(port, m, p, rr));
}
// Generate ephemeral relay identity for crypto handshake
let relay_seed = wzp_crypto::Seed::generate();
// Load or generate relay identity — persisted in ~/.wzp/relay-identity
let relay_seed = {
let config_dir = dirs::home_dir()
.unwrap_or_else(|| std::path::PathBuf::from("."))
.join(".wzp");
let identity_path = config_dir.join("relay-identity");
if identity_path.exists() {
if let Ok(hex) = std::fs::read_to_string(&identity_path) {
if let Ok(s) = wzp_crypto::Seed::from_hex(hex.trim()) {
info!("loaded relay identity from {}", identity_path.display());
s
} else {
warn!("corrupt relay identity file, generating new");
let s = wzp_crypto::Seed::generate();
let hex: String = s.0.iter().map(|b| format!("{b:02x}")).collect();
let _ = std::fs::write(&identity_path, &hex);
s
}
} else {
let s = wzp_crypto::Seed::generate();
let hex: String = s.0.iter().map(|b| format!("{b:02x}")).collect();
let _ = std::fs::write(&identity_path, &hex);
s
}
} else {
let s = wzp_crypto::Seed::generate();
let _ = std::fs::create_dir_all(&config_dir);
let hex: String = s.0.iter().map(|b| format!("{b:02x}")).collect();
let _ = std::fs::write(&identity_path, &hex);
info!("generated relay identity at {}", identity_path.display());
s
}
};
let relay_fp = relay_seed.derive_identity().public_identity().fingerprint;
info!(addr = %config.listen_addr, fingerprint = %relay_fp, "WarzonePhone relay starting");
@@ -299,6 +330,13 @@ async fn main() -> anyhow::Result<()> {
let transport = Arc::new(wzp_transport::QuinnTransport::new(connection));
// Ping connections: client just measures QUIC connect RTT.
// No handshake, no streams — client closes immediately after connecting.
if room_name == "ping" {
info!(%addr, "ping connection (RTT probe)");
return;
}
// Probe connections use SNI "_probe" to identify themselves.
// They skip auth + handshake and just do Ping->Pong + presence gossip.
if room_name == "_probe" {