From ff0fd083c88486a62353273ecf86946b5203d152 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 1 Sep 2021 13:39:16 -0400 Subject: [PATCH] feat: handle saving config better --- src/app.rs | 33 +++++++++++++++++++++++++++------ src/app/web.rs | 1 + src/main.rs | 23 +++++++++++++++-------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/app.rs b/src/app.rs index f2ac7ff..6f08cb1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,6 +9,7 @@ pub mod web; use anyhow::Result; use cached::{TimedCache, Cached}; +use chrono::Duration; use futures::{StreamExt, SinkExt}; use irc::client::prelude::Client as IrcClient; use rhai::Engine; @@ -40,13 +41,13 @@ use crate::app::{ use std::{ collections::HashMap, ops::{Deref, DerefMut}, + path::Path, sync::{ Arc, - atomic::AtomicBool, + atomic::{AtomicBool, Ordering}, }, time::Instant, }; -use std::sync::atomic::Ordering; pub struct State { pub user_config: UserConfig, @@ -77,15 +78,15 @@ impl State { pub async fn new(runtime: Handle, user_config: UserConfig, mut config: Config) -> Result> { let http_client = reqwest::Client::new(); - println!("Verifying bot token"); + println!("verifying bot token"); verify_token(&mut config.bot_token, &user_config, &http_client, vec![ // IRC Scope::ChatRead, Scope::ChatEdit, ]).await?; - println!("Bot token ready"); + println!("bot token ready"); - println!("Verifying user token"); + println!("verifying user token"); verify_token(&mut config.user_token, &user_config, &http_client, vec![ // Channel points redemptions Scope::ChannelReadRedemptions, @@ -96,7 +97,7 @@ impl State { Scope::ModerationRead, Scope::ModeratorManageAutoMod, ]).await?; - println!("User token ready"); + println!("user token ready"); let config = Arc::new(RwLock::new(config)); @@ -104,13 +105,29 @@ impl State { let twitch_config = Arc::clone(&config); let twitch = Arc::new(Twitch::new(twitch_client, twitch_config)); + println!("getting channel name"); let user_id = UserId::new(user_config.twitch.channel_id.to_string()); let channel_name = twitch.client.helix.get_user_from_id(user_id, &twitch.bot_token().await?) .await? .ok_or_else(|| anyhow::anyhow!("no channel for id {}", user_config.twitch.channel_id))? .login .to_string(); + println!("configured to run for channel: {}", channel_name); + println!("starting periodic config save task"); + let task_config = Arc::clone(&config); + tokio::task::spawn(async move { + loop { + println!("saving config"); + if let Err(e) = crate::save_config(Path::new("data.json"), &*task_config.read().await).await { + eprintln!("could not save config: {:?}", e); + } + + tokio::time::sleep(Duration::minutes(5).to_std().unwrap()).await; + } + }); + + println!("connecting to irc"); let mut irc = self::twitch_irc::connect(&twitch).await?; let mut irc_stream = irc.stream()?; @@ -182,6 +199,7 @@ impl State { )?; let task_state = Arc::clone(&state); tokio::task::spawn(async move { + println!("starting pubsub listener"); let res: Result<()> = try { let (ws, _) = tokio_tungstenite::connect_async("wss://pubsub-edge.twitch.tv").await?; let (mut write, mut read) = ws.split(); @@ -213,6 +231,7 @@ impl State { // start irc task let task_state = Arc::clone(&state); tokio::task::spawn(async move { + println!("listening for irc events"); loop { while let Some(event) = irc_stream.next().await.transpose().unwrap_or_default() { let task_state = Arc::clone(&task_state); @@ -259,6 +278,8 @@ impl State { let task_state = Arc::clone(&state); self::task::stream_status::start_task(task_state).await; + println!("initialised"); + Ok(state) } diff --git a/src/app/web.rs b/src/app/web.rs index 9c2b7f5..bdb587f 100644 --- a/src/app/web.rs +++ b/src/app/web.rs @@ -14,6 +14,7 @@ use std::{ }; pub async fn start_web(state: Arc) { + println!("starting web server"); let cookie_state = Arc::clone(&state); let authed = warp::cookie("access_token") .or(warp::header("x-api-key")) diff --git a/src/main.rs b/src/main.rs index aa3befc..446b611 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,10 +13,7 @@ use crate::app::{ config::Config, user_config::UserConfig, }; -use std::{ - path::Path, - sync::Arc, -}; +use std::path::Path; fn main() -> anyhow::Result<()> { let runtime = Builder::new_multi_thread() @@ -28,10 +25,12 @@ fn main() -> anyhow::Result<()> { } 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(); @@ -41,23 +40,31 @@ async fn inner(runtime: Handle) -> anyhow::Result<()> { Config::default() }; + println!("starting bot"); let state = State::new(runtime, user_config, config).await?; - save_config(c_path, Arc::clone(&state)).await?; + save_config(c_path, &*state.config.read().await).await?; tokio::signal::ctrl_c() - .then(|_| save_config(c_path, Arc::clone(&state))) + .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(()) } -async fn save_config(path: &Path, state: Arc) -> anyhow::Result<()> { +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(&*state.config.read().await)?).await?; + config_file.write_all(&serde_json::to_vec(config)?).await?; Ok(()) }