use std::time::{Duration, Instant};
use anyhow::bail;
use clap::Args;
use owo_colors::OwoColorize;
use crate::{
client::{ArgsClient, GitCredentialClient},
config::UserConfig,
};
#[derive(Args, Debug)]
pub struct LoginArgs;
impl LoginArgs {
pub async fn execute(&self, mut config: UserConfig) -> anyhow::Result<()> {
let api_client = ArgsClient::from_user_config(&config);
let device_code_response = api_client.create_device_code().await?;
println!("Open the following URL in your browser:");
println!(
"{}",
device_code_response.verification_url.cyan().underline()
);
println!(
"Enter the code: {}",
device_code_response.user_code.yellow().bold()
);
let interval = Duration::from_secs(device_code_response.interval);
let expires_in = Duration::from_secs(device_code_response.expires_in);
let started_at = Instant::now();
loop {
tokio::time::sleep(interval).await;
if started_at.elapsed() >= expires_in {
bail!("{}", "Device code expired. Please try again.".red());
}
match api_client
.poll_token(&device_code_response.device_code)
.await
{
Ok(response) => {
config.user_name = response.user_name.clone();
config.user_email = response.user_email;
config.save()?;
GitCredentialClient::store(
api_client.get_web_url(),
&response.user_name,
&response.access_token,
)?;
println!(
"{} {}!",
"Successfully logged in as".green().bold(),
response.user_name.cyan().bold()
);
return Ok(());
}
Err(_) => {
continue;
}
}
}
}
}