use anyhow::Result; use robespierre::framework::standard::{macros::command, CommandResult, FwContext}; use robespierre::framework::standard::{Command, CommandCodeFn, StandardFramework}; use robespierre::model::MessageExt; use robespierre::Authentication; use robespierre::CacheWrap; use robespierre::Context; use robespierre::EventHandlerWrap; use robespierre::FrameworkWrap; use robespierre::UserData; use robespierre_cache::CacheConfig; use robespierre_events::Connection; use robespierre_http::Http; use robespierre_models::{channel::Message, events::ReadyEvent}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; struct CommandCounterKey; impl robespierre::typemap::Key for CommandCounterKey { type Value = Arc; } struct ReqwestClientKey; impl robespierre::typemap::Key for ReqwestClientKey { type Value = Arc; } mod commands; use commands::*; mod config; use config::*; static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); #[tokio::main] async fn main() -> Result<()> { let _ = kankyo::init(); tracing_subscriber::fmt::init(); let config: Config = envy::from_env()?; let mut data = robespierre::typemap::ShareMap::custom(); data.insert::(config.clone().make()); let auth = Authentication::bot(config.revolt_token); let http = Http::new(&auth).await?; let connection = Connection::connect(&auth).await?; data.insert::(furbooru::make( config.furbooru_token, config.furbooru_bot_owner, )); data.insert::(Arc::new(AtomicUsize::new(0))); data.insert::(Arc::new( reqwest::Client::builder() .user_agent(APP_USER_AGENT) .build() .unwrap(), )); let context = Context::new(http, data).with_cache(CacheConfig::default()); let fw = StandardFramework::default() .configure(|c| c.prefix("!")) .group(|g| { g.name("General") .command(|| Command::new("ping", ping as CommandCodeFn)) .command(|| Command::new("command_counter", command_counter as CommandCodeFn)) .command(|| Command::new("front", current_front as CommandCodeFn)) .command(|| Command::new("fb", furbooru::search as CommandCodeFn)) }); let handler = FrameworkWrap::new(fw, Handler); let handler = CacheWrap::new(EventHandlerWrap::new(handler)); connection.run(context, handler).await?; Ok(()) } #[command] async fn ping(ctx: &FwContext, msg: &Message) -> CommandResult { msg.reply(ctx, "pong").await?; let data = ctx.data_lock_read().await; let counter = data.get::().unwrap(); counter.fetch_add(1, Ordering::SeqCst); Ok(()) } #[command] async fn command_counter(ctx: &FwContext, msg: &Message) -> CommandResult { let data = ctx.data_lock_read().await; let counter = data.get::().unwrap(); let count = counter.fetch_add(1, Ordering::SeqCst); msg.reply( ctx, format!("I received {} commands since I started running", count), ) .await?; Ok(()) } #[command] async fn current_front(ctx: &FwContext, msg: &Message) -> CommandResult { let data = ctx.data_lock_read().await; let client = data.get::().unwrap().clone(); let client = client; let front = client .get("https://home.cetacean.club/front") .send() .await? .error_for_status()? .text() .await?; tracing::debug!("got front: {}", front); msg.reply(ctx, format!("Current front: {}", front)).await?; Ok(()) } #[derive(Clone)] struct Handler; #[robespierre::async_trait] impl robespierre::EventHandler for Handler { async fn on_ready(&self, _: Context, _: ReadyEvent) { tracing::info!("bot is ready"); } }