#![feature(try_blocks, drain_filter)] mod app; use futures::FutureExt; use tokio::{ fs::OpenOptions, io::{AsyncReadExt, AsyncWriteExt}, runtime::{Builder, Handle}, }; use crate::app::{ State, config::Config, user_config::UserConfig, }; use std::path::Path; fn main() -> anyhow::Result<()> { let runtime = Builder::new_multi_thread() .enable_all() .build()?; let handle = runtime.handle().clone(); runtime.block_on(inner(handle)) } async fn inner(runtime: Handle) -> anyhow::Result<()> { println!("reading config"); let mut uc_toml = String::new(); tokio::fs::File::open("config.toml").await?.read_to_string(&mut uc_toml).await?; let user_config: UserConfig = toml::from_str(&uc_toml)?; println!("reading data"); let c_path = Path::new("data.json"); let config: Config = if c_path.exists() { let mut c_json = String::new(); tokio::fs::File::open(c_path).await?.read_to_string(&mut c_json).await?; serde_json::from_str(&c_json)? } else { Config::default() }; println!("starting bot"); let state = State::new(runtime, user_config, config).await?; save_config(c_path, &*state.config.read().await).await?; tokio::signal::ctrl_c() .then(|_| async { println!("received ctrl-c"); println!("saving config"); save_config(c_path, &*state.config.read().await).await?; Result::<(), anyhow::Error>::Ok(()) }) .await?; println!("exiting"); Ok(()) } pub async fn save_config(path: &Path, config: &Config) -> anyhow::Result<()> { let mut config_file = OpenOptions::new() .create(true) .write(true) .truncate(true) .open(path) .await?; config_file.write_all(&serde_json::to_vec(config)?).await?; Ok(()) }