frc/src/main.rs

131 lines
3.7 KiB
Rust

mod botdriver;
mod browser;
mod chromedriver;
mod webserve;
use botdriver::BotDriver;
use browser::BrowserSession;
use chromedriver::Driver;
use futures::channel::oneshot;
use serde::{Deserialize, Serialize};
use std::{
io::{self, Write},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use tokio::time;
const STATIC_ADDR: &str = "127.0.0.1:8010";
#[tokio::main]
async fn main() {
if let Err(e) = main_but_with_result().await {
println!("frc exited with error: {}", e);
std::process::exit(1);
}
std::process::exit(0);
}
async fn main_but_with_result() -> Result<(), anyhow::Error> {
let mut cfg: FRCConfig = confy::load_path(CFG_NAME)?;
if cfg.username == None || cfg.token == None {
cfg = create_config()?;
confy::store_path(CFG_NAME, cfg.clone())?;
}
let username = cfg.username.unwrap();
let static_handle = webserve::start_server(STATIC_ADDR.to_string()).await?;
println!("Starting frc with username to listen to: {}", username);
let mut chr = Driver::new()?;
let driver = BrowserSession::new().await?;
let browser = driver.handle();
let mut bot = BotDriver::new(cfg.token.unwrap(), username);
browser.start(STATIC_ADDR).await?;
println!();
println!("#####################");
println!("# launching frc #");
println!("# #");
println!("# frc can be closed #");
println!("# by an interrupt #");
println!("# (Ctl-C) #");
println!("#####################");
println!();
tokio::spawn(async move {
let should_exit = Arc::new(AtomicBool::new(false));
let (chr_sender, mut chr_receiver) = oneshot::channel();
chr.exit_waiter(chr_sender);
signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&should_exit)).unwrap();
signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&should_exit))
.unwrap();
loop {
if should_exit.load(Ordering::Relaxed) || chr_receiver.try_recv().unwrap().is_some() {
break;
}
time::sleep(Duration::from_millis(100)).await;
}
println!();
println!("closing down");
static_handle.abort();
driver.stop().await.expect("failed killing browser");
let output = chr.exit_with_output().expect("failed killing chromedriver");
println!("chromedriver exited with status code {}", output.status);
if output.stderr.len() > 0 {
print!("chromedriver stderr output:");
io::stdout().write(&output.stderr).unwrap();
println!();
}
if output.stdout.len() > 0 {
print!("chromedriver stdout output:");
io::stdout().write(&output.stdout).unwrap();
println!();
}
std::process::exit(0);
});
bot.listen_and_paste(browser).await.unwrap();
Ok(())
}
const CFG_NAME: &str = "frc.toml";
#[derive(Serialize, Deserialize, Clone, Debug)]
struct FRCConfig {
username: Option<String>,
token: Option<String>,
}
impl ::std::default::Default for FRCConfig {
fn default() -> Self {
Self {
username: None,
token: None,
}
}
}
fn create_config() -> Result<FRCConfig, anyhow::Error> {
let username = get_config_from_user("Enter username to listen to:")?;
let token = get_config_from_user("Enter telegram bot token:")?;
Ok(FRCConfig {
username: Some(username),
token: Some(token),
})
}
fn get_config_from_user(prompt: &str) -> Result<String, anyhow::Error> {
print!("{} ", prompt);
io::stdout().flush()?;
let mut value = String::new();
io::stdin().read_line(&mut value)?;
Ok(value.trim().to_string())
}