use std::process::{Command, Stdio};
use dvm_api::{CollectCliLogin, CreatedApiKey, Me, NewCliLogin, StartedCliLogin};
use reqwest::Method;
use crate::client::{Client, api_url_of};
use crate::error::Result;
#[derive(Clone, Debug)]
pub struct LoggedIn {
pub api_url: String,
pub login: String,
pub key_name: String,
pub key: String,
}
pub async fn login(
api_url: Option<&str>,
open_browser: bool,
mut say: impl FnMut(&str),
) -> Result<LoggedIn> {
let url = api_url_of(api_url);
let terminal = Client::with_key(url.clone(), None);
let machine = NewCliLogin {
machine: gethostname::gethostname().to_string_lossy().into_owned(),
};
let started: StartedCliLogin = terminal
.json(Method::POST, "/cli-logins", &[], Some(&machine))
.await?;
say(&format!(
"Approve this login in your browser: {}",
started.approve_url
));
say(&format!("The page shows the code {}.", started.code));
if open_browser {
open_in_browser(&started.approve_url);
}
let collect = CollectCliLogin {
collect_token: started.collect_token,
};
let created = loop {
let answer: Option<CreatedApiKey> = terminal
.json(Method::POST, "/cli-logins/key", &[], Some(&collect))
.await?;
if let Some(created) = answer {
break created;
}
};
let me: Me = Client::new(url.clone(), created.secret.clone())
.json(Method::GET, "/me", &[], None::<&()>)
.await?;
Ok(LoggedIn {
api_url: url,
login: me.login,
key_name: created.key.name,
key: created.secret,
})
}
fn open_in_browser(url: &str) {
let opener = if cfg!(target_os = "macos") {
Command::new("open").arg(url).spawn()
} else if cfg!(windows) {
Command::new("cmd").args(["/c", "start", "", url]).spawn()
} else {
Command::new("xdg-open")
.arg(url)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
};
drop(opener);
}