2019-10-31 12:21:24 +01:00
use serde ::de ::DeserializeOwned ;
2019-10-29 22:24:41 +01:00
use serenity ::model ::channel ::Message ;
2020-06-09 20:34:31 +02:00
use serenity ::model ::gateway ::{ Activity , Ready } ;
2019-10-30 22:04:32 +01:00
use serenity ::model ::id ::ChannelId ;
2019-10-29 22:24:41 +01:00
use serenity ::prelude ::* ;
2019-10-31 12:21:24 +01:00
use std ::fmt ;
2019-10-30 23:00:51 +01:00
mod apt ;
2020-06-09 20:34:31 +02:00
mod aur ;
2019-10-31 12:21:24 +01:00
mod dnf ;
2020-06-09 20:34:31 +02:00
mod man ;
2019-10-31 10:39:28 +01:00
mod nix ;
2019-10-31 12:21:24 +01:00
mod pacman ;
2019-11-02 09:41:34 +01:00
mod xbps ;
2019-10-30 22:04:32 +01:00
extern crate reqwest ;
2019-10-29 22:24:41 +01:00
pub struct Handler ;
2019-10-30 23:00:51 +01:00
pub type CommandHandler = dyn Fn ( Context , Message , Vec < & str > ) ;
2019-10-29 22:24:41 +01:00
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 ( )
2019-10-31 11:45:16 +01:00
. find ( | & c | msg . content . starts_with ( & c . trigger ) )
2019-10-29 22:24:41 +01:00
{
2019-10-30 23:00:51 +01:00
let content = msg . content . clone ( ) ;
let mut args = content . split_whitespace ( ) . collect ::< Vec < _ > > ( ) ;
// the prefix + trigger
args . remove ( 0 ) ;
2019-10-31 11:45:16 +01:00
if args . is_empty ( ) {
2019-10-30 23:00:51 +01:00
send (
msg . channel_id ,
" Error: expected at least 1 additional argument " ,
& ctx ,
) ;
return ;
}
( * command . handler ) ( ctx , msg , args ) ;
2019-10-29 22:24:41 +01:00
} ;
}
}
2019-11-02 10:40:18 +01:00
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 ) ) ) ;
}
2019-10-29 22:24:41 +01:00
}
2019-10-31 22:35:07 +01:00
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 ,
2019-11-02 10:40:18 +01:00
& format! ( " Usage: `<command> <search term>` \n Supported commands: ` {} ` \n Source code & information: https://git.kageru.moe/kageru/pacbot " ,
2019-10-31 22:35:07 +01:00
command_triggers ) , & ctx )
}
2019-10-29 22:24:41 +01:00
lazy_static! {
static ref COMMANDS : Vec < Command > = {
let mut command_list = Vec ::new ( ) ;
command_list . push ( Command ::new ( " pacman " , pacman ::query_pacman ) ) ;
2019-10-30 23:00:51 +01:00
command_list . push ( Command ::new ( " apt " , apt ::query_apt ) ) ;
2020-04-23 23:50:00 +02:00
// disabled because they seem to no longer have stable json urls
// command_list.push(Command::new("nix", nix::query_nix));
2019-10-31 12:21:24 +01:00
command_list . push ( Command ::new ( " dnf " , dnf ::query_dnf ) ) ;
2019-10-31 22:55:29 +01:00
command_list . push ( Command ::new ( " aur " , aur ::query_aur ) ) ;
2019-11-02 09:41:34 +01:00
command_list . push ( Command ::new ( " xbps " , xbps ::query_xbps ) ) ;
2019-11-11 13:45:33 +01:00
command_list . push ( Command ::new ( " man " , man ::query_man ) ) ;
2019-10-31 22:35:07 +01:00
command_list . push ( Command ::new ( " pacbot help " , help ) ) ;
command_list . push ( Command ::new ( " pb help " , help ) ) ;
2019-10-29 22:24:41 +01:00
command_list
} ;
}
impl Command {
2019-10-30 23:00:51 +01:00
pub fn new ( trigger : & str , handler : fn ( Context , Message , Vec < & str > ) ) -> Self {
2019-10-29 22:24:41 +01:00
let mut trigger_with_prefix = trigger . to_string ( ) ;
trigger_with_prefix . insert ( 0 , PREFIX ) ;
Self {
trigger : trigger_with_prefix ,
handler : Box ::new ( handler ) ,
}
}
}
2019-10-30 22:04:32 +01:00
pub fn send ( target : ChannelId , message : & str , ctx : & Context ) {
if let Err ( cause ) = target . say ( & ctx . http , message ) {
println! ( " Could not send message: {} " , cause ) ;
}
}
2019-10-31 11:45:16 +01:00
pub fn respond_with_results < T : fmt ::Display > ( target : ChannelId , results : & [ T ] , ctx : & Context ) {
2019-10-30 22:04:32 +01:00
send (
target ,
& format! (
" ```{}``` " ,
results
2019-10-31 11:45:16 +01:00
. iter ( )
2019-10-30 22:04:32 +01:00
. take ( 5 )
. map ( | p | format! ( " {} \n " , p ) )
. collect ::< String > ( )
) ,
ctx ,
) ;
}
2019-10-31 10:39:28 +01:00
pub fn search < T : DeserializeOwned > ( url : & str , fallback : impl Fn ( reqwest ::Error ) -> T ) -> T {
2020-06-09 20:34:31 +02:00
search_inner ( url ) . unwrap_or_else ( | e | {
println! ( " {:?} " , e ) ;
fallback ( e )
} )
2019-10-30 22:04:32 +01:00
}
fn search_inner < T : DeserializeOwned > ( url : & str ) -> Result < T , reqwest ::Error > {
let resp = reqwest ::get ( url ) ? . json ::< T > ( ) ? ;
Ok ( resp )
}