uberbot/src/main.rs

183 lines
5.6 KiB
Rust
Raw Normal View History

#![allow(clippy::match_wildcard_for_single_variants)]
use std::fs::File;
use std::io::Read;
use std::sync::Arc;
2022-01-02 14:58:54 -06:00
use std::thread;
2022-07-16 05:21:23 -05:00
use std::env;
use std::fmt::Display;
2022-01-26 05:58:49 -06:00
use futures_util::stream::StreamExt;
use irc::client::prelude::Config;
use irc::client::{Client, ClientStream};
2022-01-26 05:58:49 -06:00
use irc::proto::{ChannelExt, Command, Prefix};
use rspotify::Credentials;
use serde::Deserialize;
2022-04-16 18:37:06 -05:00
use tokio::select;
use tokio::sync::broadcast;
2022-01-27 17:44:50 -06:00
use tokio::sync::mpsc::unbounded_channel;
2021-12-27 06:39:01 -06:00
use tracing_subscriber::EnvFilter;
2022-07-16 05:21:23 -05:00
use crate::bot::Bot;
use crate::bots::misc::Waifu;
2021-12-27 06:39:01 -06:00
2022-07-16 05:21:23 -05:00
use crate::config::UberConfig;
use crate::database::{DbExecutor, ExecutorConnection};
2022-01-26 05:58:49 -06:00
mod bots;
mod database;
2022-07-15 10:58:45 -05:00
mod bot;
mod config;
2022-01-26 05:58:49 -06:00
2021-12-31 17:51:54 -06:00
// this will be displayed when the help command is used
const HELP: &[&str] = &[
concat!("=- \x1d\x02Ü\x02berbot\x0f ", env!("CARGO_PKG_VERSION"), " -="),
" * waifu <category>",
" * owo/mock/leet [user]",
" * ev <math expression>",
" - This bot also provides titles of URLs and details for Spotify URIs/links. It can also resolve sed expressions."
2021-12-31 17:51:54 -06:00
];
2021-12-27 06:39:01 -06:00
#[cfg(unix)]
async fn terminate_signal() {
use tokio::signal::unix::{signal, SignalKind};
let mut sigterm = signal(SignalKind::terminate()).unwrap();
let mut sigint = signal(SignalKind::interrupt()).unwrap();
2021-12-31 17:51:54 -06:00
tracing::debug!("Installed ctrl+c handler");
2021-12-27 06:39:01 -06:00
select! {
_ = sigterm.recv() => return,
_ = sigint.recv() => return
2021-12-27 06:39:01 -06:00
}
}
#[cfg(windows)]
async fn terminate_signal() {
use tokio::signal::windows::ctrl_c;
let mut ctrlc = ctrl_c().unwrap();
2021-12-31 17:51:54 -06:00
tracing::debug!("Installed ctrl+c handler");
2021-12-27 06:39:01 -06:00
let _ = ctrlc.recv().await;
}
2022-07-16 05:21:23 -05:00
pub struct AppState<SF: FnMut(String, String) -> anyhow::Result<()>> {
client: Arc<Client>,
stream: ClientStream,
2022-07-16 05:21:23 -05:00
bot: Bot<SF>
}
#[tokio::main]
2021-12-27 06:39:01 -06:00
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_env("UBERBOT_LOG"))
.init();
2021-12-27 06:39:01 -06:00
2022-01-02 14:58:54 -06:00
let mut file =
File::open(env::var("UBERBOT_CONFIG").unwrap_or_else(|_| "uberbot.toml".to_string()))?;
2021-12-28 06:38:50 -06:00
let mut client_conf = String::new();
file.read_to_string(&mut client_conf)?;
2022-07-16 05:21:23 -05:00
let cfg: UberConfig = toml::from_str(&client_conf)?;
2022-01-02 14:58:54 -06:00
let (db_exec, db_conn) =
2022-07-16 05:21:23 -05:00
DbExecutor::create(cfg.db_path.as_deref().unwrap_or("uberbot.db3"))?;
2022-01-01 16:03:15 -06:00
let exec_thread = thread::spawn(move || {
2022-01-01 15:35:27 -06:00
db_exec.run();
tracing::info!("Database executor has been shut down");
});
2022-01-26 05:58:49 -06:00
let uber_ver = concat!("Überbot ", env!("CARGO_PKG_VERSION"));
let irc_config = Config {
nickname: Some(
2022-07-16 05:21:23 -05:00
cfg
.irc
.nickname
2022-07-16 05:21:23 -05:00
.unwrap_or_else(|| cfg.irc.username.clone()),
),
2022-07-16 05:21:23 -05:00
username: Some(cfg.irc.username.clone()),
realname: Some(cfg.irc.username),
server: Some(cfg.irc.host),
port: Some(cfg.irc.port),
use_tls: Some(cfg.irc.tls),
channels: cfg.irc.channels,
umodes: cfg.irc.mode,
2022-01-26 05:58:49 -06:00
user_info: Some(uber_ver.into()),
version: Some(uber_ver.into()),
..Config::default()
};
let mut client = Client::from_config(irc_config).await?;
let stream = client.stream()?;
2022-01-26 05:58:49 -06:00
client.identify()?;
let client = Arc::new(client);
let (ctx, _) = broadcast::channel(1);
let (etx, mut erx) = unbounded_channel();
2022-07-16 05:21:23 -05:00
let mut bot = Bot::new(cfg.irc.prefix, db_conn, {
let client = client.clone();
move |target, msg| Ok(client.send_privmsg(target, msg)?)
});
bot.add_command("waifu".into(), Waifu);
2021-12-27 14:37:50 -06:00
let state = AppState {
client: client.clone(),
stream,
2022-07-16 05:21:23 -05:00
bot
2021-12-27 14:37:50 -06:00
};
let message_loop_task = tokio::spawn(async move {
if let Err(e) = message_loop(state).await {
let _err = etx.send(e);
2022-01-15 11:18:26 -06:00
}
});
select! {
2021-12-31 17:51:54 -06:00
_ = terminate_signal() => {
tracing::info!("Received shutdown signal, sending QUIT message");
client.send_quit("überbot shutting down")?;
}
e = erx.recv() => {
if let Some(e) = e {
tracing::error!("An error has occurred, shutting down: {}", e);
} else {
tracing::error!("Error channel has been dropped due to an unknown error, shutting down");
}
2021-12-27 06:39:01 -06:00
}
}
tracing::info!("Closing services...");
let _ = ctx.send(());
message_loop_task
.await
.unwrap_or_else(|e| tracing::warn!("Couldn't join the web service: {:?}", e));
2022-07-16 05:21:23 -05:00
tracing::info!("Message loop finished");
exec_thread
.join()
.unwrap_or_else(|e| tracing::warn!("Couldn't join the database: {:?}", e));
2022-07-16 05:21:23 -05:00
tracing::info!("Executor thread finished");
tracing::info!("Shutdown complete!");
Ok(())
}
2021-12-27 06:39:01 -06:00
2022-07-16 05:21:23 -05:00
async fn message_loop<SF: FnMut(String, String) -> anyhow::Result<()>>(mut state: AppState<SF>) -> anyhow::Result<()> {
while let Some(message) = state.stream.next().await.transpose()? {
2022-01-26 05:58:49 -06:00
if let Command::PRIVMSG(ref origin, content) = message.command {
if origin.is_channel_name() {
if let Some(author) = message.prefix.as_ref().and_then(|p| match p {
Prefix::Nickname(name, _, _) => Some(&name[..]),
_ => None,
}) {
2022-07-16 05:21:23 -05:00
if let Err(e) = state.bot.handle_message(origin, author, &content).await {
2022-01-26 05:58:49 -06:00
state
.client
.send_privmsg(origin, &format!("Error: {}", e))?;
}
} else {
tracing::warn!("Couldn't get the author for a message");
}
}
}
}
2021-12-27 06:39:01 -06:00
Ok(())
}