use crate::api_client::ApiClient;
use crate::credentials::Credentials;
pub async fn login(server_url: &str) -> Result<(), Box<dyn std::error::Error>> {
let client = ApiClient::new(server_url, None);
let device = client.device_start().await?;
let full_url = format!(
"{}/auth/device?token={}",
server_url.trim_end_matches('/'),
device.token
);
println!("Opening browser for authentication...");
println!("If the browser doesn't open, visit: {full_url}");
if let Err(e) = open::that(&full_url) {
eprintln!("Could not open browser: {e}");
}
print!("Waiting for authentication...");
let poll_interval = std::time::Duration::from_secs(2);
let max_attempts = 150;
for _ in 0..max_attempts {
tokio::time::sleep(poll_interval).await;
match client.device_status(&device.token).await {
Ok(status) => {
if status.status == "approved" {
let token = status
.token
.ok_or("Server approved but did not return a session token")?;
let email = status
.email
.ok_or("Server approved but did not return an email")?;
println!(" done!");
println!();
println!("Logged in as {}", email);
let creds = Credentials {
server_url: server_url.to_string(),
token,
email,
};
creds.save()?;
println!("Credentials saved to {}", Credentials::path().display());
return Ok(());
}
}
Err(e) => {
eprintln!("\nError polling status: {e}");
return Err(e);
}
}
}
Err("Authentication timed out after 5 minutes".into())
}