43 lines
1.5 KiB
Rust
43 lines
1.5 KiB
Rust
//! Interactive pairing smoke test, sharing the GUI's exact protocol implementation.
|
|
use airplay_discovery::{Discovery, ServiceBrowser};
|
|
use anyhow::Context;
|
|
use spielab::pairing::{ControlSession, CredentialStore};
|
|
use std::{
|
|
io::{self, Write},
|
|
path::PathBuf,
|
|
time::Duration,
|
|
};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
let name = std::env::args()
|
|
.nth(1)
|
|
.context("Usage: cargo run --example pair -- 'Receiver name'")?;
|
|
let state = std::env::var_os("SPIELAB_STATE_DIR")
|
|
.map(PathBuf::from)
|
|
.context("Set SPIELAB_STATE_DIR to the same credential directory as the GUI")?;
|
|
let store = CredentialStore::new(state)?;
|
|
let browser = ServiceBrowser::new()?;
|
|
let device = browser
|
|
.scan(Duration::from_secs(5))
|
|
.await?
|
|
.into_iter()
|
|
.find(|device| device.name == name)
|
|
.context("Receiver not found")?;
|
|
let mut session = ControlSession::open(device).await?;
|
|
if let Some(credentials) = store.load(&session.device)? {
|
|
session.verify(&credentials).await?;
|
|
} else {
|
|
session.request_pin().await?;
|
|
print!("Enter the code shown on Apple TV: ");
|
|
io::stdout().flush()?;
|
|
let mut pin = String::new();
|
|
io::stdin().read_line(&mut pin)?;
|
|
let credentials = session.pair(pin.trim()).await?;
|
|
store.save(&session.device, &credentials)?;
|
|
}
|
|
println!("Authenticated: encrypted OPTIONS round trip succeeded.");
|
|
session.transport.close().await?;
|
|
Ok(())
|
|
}
|