use crate::cli::PubCommands;
use crate::output::{MetadataSource, ReportEntry, ReportStatus, write_data};
use hyper::StatusCode;
use nix::unistd::isatty;
use std::io::{self, BufRead};
use std::os::fd::AsRawFd;
use std::sync::mpsc;
use std::thread;
use tokio::time::Duration;
pub async fn handle_pub_command(commands: &PubCommands) {
match commands {
PubCommands::Doi {
doi,
source_list,
output_path,
} => {
let dois = if let Some(input) = doi {
vec![input.to_string()]
} else {
if isatty(io::stdin().as_raw_fd()).unwrap_or(false) {
eprintln!("No input was provided.");
std::process::exit(1);
}
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let stdin = io::stdin();
let mut buffer = String::new();
let mut handle = stdin.lock();
while let Ok(bytes) = handle.read_line(&mut buffer) {
if bytes == 0 {
break;
}
}
sender
.send(buffer.trim().to_string())
.expect("Failed to send input");
buffer.clear();
});
let timeout = Duration::from_millis(100);
let data =
match tokio::time::timeout(timeout, async { receiver.recv().unwrap() }).await {
Ok(input) => input,
Err(_) => {
eprintln!("Timed out waiting for input on stdin");
"".to_string()
}
};
let s: Vec<String> = data
.split("\n")
.map(|i| i.to_string())
.filter(|i| !i.is_empty())
.collect();
s
};
let report = fetch_dois(&dois, source_list).await;
if !report.is_empty() {
let _ = write_data(&report, output_path).await;
}
}
}
}
pub async fn fetch_dois(dois: &Vec<String>, source_list: &[MetadataSource]) -> Vec<ReportEntry> {
let mut report: Vec<ReportEntry> = Vec::new();
for doi in dois {
let mut status = ReportStatus::NotFound;
for source in source_list {
let response = reqwest::get(&source.url_for_doi(doi)).await.unwrap();
let response = response.error_for_status();
match response {
Ok(resp) => match resp.text().await {
Ok(text) => {
status = ReportStatus::Ok(source.clone(), text);
break;
}
Err(err) => match err.status() {
Some(StatusCode::NOT_FOUND) => {}
_ => status = ReportStatus::Error,
},
},
Err(err) => match err.status() {
Some(StatusCode::NOT_FOUND) => {}
_ => status = ReportStatus::Error,
},
}
}
report.push(ReportEntry {
doi: doi.clone(),
status,
});
}
report
}