130 lines
3.9 KiB
Rust
130 lines
3.9 KiB
Rust
use serde::de::DeserializeOwned;
|
|
use serenity::model::channel::Message;
|
|
use serenity::model::gateway::{Activity, Ready};
|
|
use serenity::model::id::ChannelId;
|
|
use serenity::prelude::*;
|
|
use std::fmt;
|
|
mod apt;
|
|
mod aur;
|
|
mod dnf;
|
|
mod man;
|
|
mod nix;
|
|
mod pacman;
|
|
mod xbps;
|
|
extern crate reqwest;
|
|
|
|
pub struct Handler;
|
|
pub type CommandHandler = dyn Fn(Context, Message, Vec<&str>);
|
|
struct Command {
|
|
trigger: String,
|
|
handler: Box<CommandHandler>,
|
|
}
|
|
|
|
unsafe impl Sync for Command {}
|
|
|
|
const PREFIX: char = '!';
|
|
|
|
impl EventHandler for Handler {
|
|
fn message(&self, ctx: Context, msg: Message) {
|
|
if msg.content.starts_with(PREFIX) {
|
|
if let Some(command) = COMMANDS
|
|
.iter()
|
|
.find(|&c| msg.content.starts_with(&c.trigger))
|
|
{
|
|
let content = msg.content.clone();
|
|
let mut args = content.split_whitespace().collect::<Vec<_>>();
|
|
// the prefix + trigger
|
|
args.remove(0);
|
|
if args.is_empty() {
|
|
send(
|
|
msg.channel_id,
|
|
"Error: expected at least 1 additional argument",
|
|
&ctx,
|
|
);
|
|
return;
|
|
}
|
|
(*command.handler)(ctx, msg, args);
|
|
};
|
|
}
|
|
}
|
|
|
|
fn ready(&self, ctx: Context, bot_data: Ready) {
|
|
println!("Bot running and serving {} servers", bot_data.guilds.len());
|
|
ctx.reset_presence();
|
|
ctx.set_activity(Activity::listening(&format!("{}pb help", PREFIX)));
|
|
}
|
|
}
|
|
|
|
fn help(ctx: Context, msg: Message, _args: Vec<&str>) {
|
|
let command_triggers = COMMANDS
|
|
.iter()
|
|
.filter(|&c| !c.trigger.contains("help"))
|
|
.map(|c| c.trigger.clone())
|
|
.collect::<Vec<_>>()
|
|
.join(", ");
|
|
send(msg.channel_id,
|
|
&format!("Usage: `<command> <search term>`\nSupported commands: `{}`\nSource code & information: https://git.kageru.moe/kageru/pacbot",
|
|
command_triggers), &ctx)
|
|
}
|
|
|
|
lazy_static! {
|
|
static ref COMMANDS: Vec<Command> = {
|
|
let mut command_list = Vec::new();
|
|
command_list.push(Command::new("pacman", pacman::query_pacman));
|
|
command_list.push(Command::new("apt", apt::query_apt));
|
|
// disabled because they seem to no longer have stable json urls
|
|
// command_list.push(Command::new("nix", nix::query_nix));
|
|
command_list.push(Command::new("dnf", dnf::query_dnf));
|
|
command_list.push(Command::new("aur", aur::query_aur));
|
|
command_list.push(Command::new("xbps", xbps::query_xbps));
|
|
command_list.push(Command::new("man", man::query_man));
|
|
command_list.push(Command::new("pacbot help", help));
|
|
command_list.push(Command::new("pb help", help));
|
|
command_list
|
|
};
|
|
}
|
|
|
|
impl Command {
|
|
pub fn new(trigger: &str, handler: fn(Context, Message, Vec<&str>)) -> Self {
|
|
let mut trigger_with_prefix = trigger.to_string();
|
|
trigger_with_prefix.insert(0, PREFIX);
|
|
Self {
|
|
trigger: trigger_with_prefix,
|
|
handler: Box::new(handler),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn send(target: ChannelId, message: &str, ctx: &Context) {
|
|
if let Err(cause) = target.say(&ctx.http, message) {
|
|
println!("Could not send message: {}", cause);
|
|
}
|
|
}
|
|
|
|
pub fn respond_with_results<T: fmt::Display>(target: ChannelId, results: &[T], ctx: &Context) {
|
|
send(
|
|
target,
|
|
&format!(
|
|
"```{}```",
|
|
results
|
|
.iter()
|
|
.take(5)
|
|
.map(|p| format!("{}\n", p))
|
|
.collect::<String>()
|
|
),
|
|
ctx,
|
|
);
|
|
}
|
|
|
|
pub fn search<T: DeserializeOwned>(url: &str, fallback: impl Fn(reqwest::Error) -> T) -> T {
|
|
search_inner(url).unwrap_or_else(|e| {
|
|
println!("{:?}", e);
|
|
fallback(e)
|
|
})
|
|
}
|
|
|
|
fn search_inner<T: DeserializeOwned>(url: &str) -> Result<T, reqwest::Error> {
|
|
let resp = reqwest::get(url)?.json::<T>()?;
|
|
Ok(resp)
|
|
}
|