bb437a73cf
Bare `pixelpass` now opens a dialoguer-driven Host/View menu instead of going straight to host mode. Host path copies the ticket to the system clipboard via arboard with silent print-only fallback. View path prompts for the ticket, then after the local listener binds prompts mpv-vs-VLC and spawns it detached (setsid + null stdio) so the player survives pixelpass exiting. Headless invocations (`pixelpass <ticket>`, `pixelpass --repair`) unchanged. Per spec at ~/Documents/pixelpass-interactive-mode-spec.md.
76 lines
2.9 KiB
Rust
76 lines
2.9 KiB
Rust
use anyhow::{Context, Result};
|
|
use iroh::Endpoint;
|
|
use iroh::endpoint::presets;
|
|
use iroh_tickets::endpoint::EndpointTicket;
|
|
use tokio::net::TcpListener;
|
|
|
|
use crate::cli::ViewerOpts;
|
|
use crate::common::{alpn::ALPN, signal};
|
|
|
|
pub async fn run(ticket: EndpointTicket, opts: ViewerOpts) -> Result<()> {
|
|
let cancel = signal::install_ctrl_c();
|
|
|
|
let endpoint = Endpoint::builder(presets::N0)
|
|
.alpns(vec![ALPN.to_vec()])
|
|
.bind()
|
|
.await?;
|
|
|
|
let addr = ticket.endpoint_addr().clone();
|
|
tracing::info!(remote = %addr.id, "connecting to host");
|
|
let conn = endpoint.connect(addr, ALPN).await?;
|
|
let (quic_send, quic_recv) = conn.open_bi().await?;
|
|
|
|
let listener = TcpListener::bind(("127.0.0.1", opts.port)).await?;
|
|
let port = listener.local_addr()?.port();
|
|
let url = format!("http://127.0.0.1:{port}");
|
|
|
|
if opts.interactive {
|
|
let player = crate::interactive::prompt_player()?;
|
|
player
|
|
.spawn(&url)
|
|
.with_context(|| "failed to launch player")?;
|
|
print_viewer_banner_interactive();
|
|
} else {
|
|
print_viewer_banner(&url);
|
|
}
|
|
|
|
let result = tokio::select! {
|
|
accepted = listener.accept() => {
|
|
let (tcp, peer) = accepted?;
|
|
tracing::info!(%peer, "local viewer connected");
|
|
crate::common::tunnel::bridge(quic_send, quic_recv, tcp).await
|
|
}
|
|
_ = cancel.cancelled() => {
|
|
tracing::info!("ctrl-c received before local viewer connected");
|
|
Ok(())
|
|
}
|
|
};
|
|
|
|
endpoint.close().await;
|
|
result
|
|
}
|
|
|
|
fn print_viewer_banner(url: &str) {
|
|
eprintln!();
|
|
eprintln!("┌─ PixelPass · viewer ───────────────────────────────────────");
|
|
eprintln!("│ Connected to host. Open the stream in your player:");
|
|
eprintln!("│");
|
|
eprintln!(
|
|
"│ mpv --profile=low-latency --untimed --audio-buffer=0.2 --demuxer-max-bytes=2M --demuxer-readahead-secs=0.5 {url}"
|
|
);
|
|
eprintln!("│ vlc --network-caching=200 --live-caching=200 {url}");
|
|
eprintln!("│");
|
|
eprintln!("│ Press Ctrl+C to disconnect.");
|
|
eprintln!("└────────────────────────────────────────────────────────────");
|
|
eprintln!();
|
|
}
|
|
|
|
fn print_viewer_banner_interactive() {
|
|
eprintln!();
|
|
eprintln!("┌─ PixelPass · viewer ───────────────────────────────────────");
|
|
eprintln!("│ Player launched. Close it (or press Ctrl+C here) to");
|
|
eprintln!("│ disconnect.");
|
|
eprintln!("└────────────────────────────────────────────────────────────");
|
|
eprintln!();
|
|
}
|