use std::{
collections::HashMap,
net::SocketAddr,
sync::{Mutex, PoisonError},
};
use http_body_util::Full;
use hyper::{body::Bytes, server::conn::http1, service::service_fn, Response};
use hyper_util::rt::TokioIo;
use tokio::{net::TcpListener, sync::oneshot};
use crate::bular_json::BularJson;
static BULAR_CLI_CLIENT_ID: &str = "000000000000";
#[derive(clap::Args)]
#[command(about = "Authenticate with Bular Cloud!")]
pub struct Command {}
impl Command {
pub async fn run(&self, server: String) {
if let Some(config) = BularJson::load() {
if config.token.is_some() {
println!("Already authenticated. Please logout first!");
return;
}
}
let (tx, rx) = oneshot::channel();
let addr = SocketAddr::from(([127, 0, 0, 1], 2857));
let listener = TcpListener::bind(addr).await.unwrap();
tokio::spawn(async move {
let tx = Mutex::new(Some(tx));
while tx.lock().unwrap_or_else(PoisonError::into_inner).is_some() {
let (stream, _) = listener.accept().await.unwrap();
let io = TokioIo::new(stream);
if let Err(err) = http1::Builder::new()
.serve_connection(
io,
service_fn(|req| {
let params: HashMap<String, String> = req
.uri()
.query()
.map(|v| {
url::form_urlencoded::parse(v.as_bytes())
.into_owned()
.collect()
})
.unwrap_or_else(HashMap::new);
let mut ok = false;
if let Some(code) = params.get("code") {
if let Some(tx) =
tx.lock().unwrap_or_else(PoisonError::into_inner).take()
{
tx.send(code.to_string()).unwrap();
ok = true;
}
}
async move {
Ok::<_, hyper::Error>(Response::new(Full::new(Bytes::from(
if ok {
"Authenticated successfully! You can close this tab and go back to the application."
} else {
"Error occurred during authentication! Please try again."
},
))))
}
}),
)
.await
{
eprintln!("Error serving connection: {:?}", err);
}
}
});
let url = format!("{server}/auth/cli?client_id={BULAR_CLI_CLIENT_ID}");
open::that(&url).ok();
println!("Opened {url:?} in your browser. Follow the instructions to authenticate!");
let Ok(token) = rx.await else {
todo!();
};
BularJson { token: Some(token) }.save();
println!("Successfully authenticated!");
}
}