main.rs 6.16 KB
Newer Older
1 2 3
#[macro_use]
extern crate lazy_static;

tec's avatar
tec committed
4 5 6 7
#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::*;
8
use std::fs::{File, read_to_string};
tec's avatar
tec committed
9

tec's avatar
tec committed
10 11 12 13 14 15
use serenity::{
    model::{channel, channel::Message, gateway::Ready, guild::Member},
    prelude::*,
    utils::MessageBuilder,
};

tec's avatar
tec committed
16 17 18
mod config;
mod user_management;
mod voting;
tec's avatar
tec committed
19

20 21
use config::CONFIG;

Tom Almeida's avatar
Tom Almeida committed
22 23 24 25
macro_rules! e {
    ($error: literal, $x:expr) => {
        match $x {
            Ok(_) => (),
tec's avatar
tec committed
26
            Err(why) => error!($error, why),
Tom Almeida's avatar
Tom Almeida committed
27
        }
28
    };
Tom Almeida's avatar
Tom Almeida committed
29 30 31 32
}

struct Handler;

tec's avatar
tec committed
33 34 35 36 37 38 39
impl EventHandler for Handler {
    // Set a handler for the `message` event - so that whenever a new message
    // is received - the closure (or function) passed will be called.
    //
    // Event handlers are dispatched through a threadpool, and so multiple
    // events can be dispatched simultaneously.
    fn message(&self, ctx: Context, msg: Message) {
40
        if !(msg.content.starts_with(CONFIG.command_prefix)) {
41 42 43 44
            return;
        }
        let message_content: Vec<_> = msg.content[1..].splitn(2, ' ').collect();
        match message_content[0] {
tec's avatar
tec committed
45 46
            "say" => {
                println!("{:#?}", msg.content);
47
            }
tec's avatar
tec committed
48
            "register" => user_management::Commands::register(ctx, msg.clone(), message_content[1]),
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
            "join" => {
                user_management::Commands::join(ctx, msg.clone(), message_content[1]);
            }
            "move" => {
                voting::Commands::move_something(ctx, msg.clone(), message_content[1]);
            }
            "motion" => {
                voting::Commands::motion(ctx, msg.clone(), message_content[1]);
            }
            "poll" => {
                voting::Commands::poll(ctx, msg.clone(), message_content[1]);
            }
            "cowsay" => {
                voting::Commands::cowsay(ctx, msg.clone(), message_content[1]);
            }
            "help" => {
                let mut message = MessageBuilder::new();
                message.push_line(format!(
                    "Use {}move <action> to make a circular motion",
68
                    &CONFIG.command_prefix
69 70 71
                ));
                message.push_line(format!(
                    "Use {}poll <proposal> to see what people think about something",
72
                    &CONFIG.command_prefix
73 74 75 76 77 78 79 80 81 82 83
                ));
                e!(
                    "Error sending message: {:?}",
                    msg.channel_id.say(&ctx.http, message.build())
                );
            }
            _ => {
                e!(
                    "Error sending message: {:?}",
                    msg.channel_id.say(
                        &ctx.http,
84
                        format!("Unrecognised command. Try {}help", &CONFIG.command_prefix)
85 86
                    )
                );
87
            }
tec's avatar
tec committed
88 89 90
        }
    }

tec's avatar
tec committed
91
    fn reaction_add(&self, ctx: Context, add_reaction: channel::Reaction) {
tec's avatar
tec committed
92 93
        match add_reaction.message(&ctx.http) {
            Ok(message) => {
94
                if message.author.id.0 != CONFIG.bot_id || add_reaction.user_id == CONFIG.bot_id {
tec's avatar
tec committed
95
                    return;
tec's avatar
tec committed
96 97 98 99
                }
                match message_type(&message) {
                    "motion" => {
                        voting::reaction_add(ctx, add_reaction);
tec's avatar
tec committed
100
                    }
tec's avatar
tec committed
101
                    _ => {}
tec's avatar
tec committed
102 103 104 105
                }
            }
            Err(why) => error!("Failed to get react message {:?}", why),
        }
tec's avatar
tec committed
106 107
    }

tec's avatar
tec committed
108
    fn reaction_remove(&self, ctx: Context, removed_reaction: channel::Reaction) {
tec's avatar
tec committed
109 110
        match removed_reaction.message(&ctx.http) {
            Ok(message) => {
111
                if message.author.id.0 != CONFIG.bot_id || removed_reaction.user_id == CONFIG.bot_id {
tec's avatar
tec committed
112
                    return;
tec's avatar
tec committed
113 114 115 116
                }
                match message_type(&message) {
                    "motion" => {
                        voting::reaction_remove(ctx, removed_reaction);
tec's avatar
tec committed
117
                    }
tec's avatar
tec committed
118
                    _ => {}
tec's avatar
tec committed
119 120 121 122
                }
            }
            Err(why) => error!("Failed to get react message {:?}", why),
        }
tec's avatar
tec committed
123 124
    }

tec's avatar
tec committed
125 126 127 128
    fn guild_member_addition(
        &self,
        ctx: Context,
        _guild_id: serenity::model::id::GuildId,
129
        the_new_member: Member,
tec's avatar
tec committed
130
    ) {
tec's avatar
tec committed
131
        user_management::new_member(&ctx, the_new_member);
tec's avatar
tec committed
132 133 134 135 136 137 138 139 140
    }

    // Set a handler to be called on the `ready` event. This is called when a
    // shard is booted, and a READY payload is sent by Discord. This payload
    // contains data like the current user's guild Ids, current user data,
    // private channels, and more.
    //
    // In this case, just print what the current user's username is.
    fn ready(&self, _: Context, ready: Ready) {
tec's avatar
tec committed
141
        info!("{} is connected!", ready.user.name);
tec's avatar
tec committed
142 143 144 145
    }
}

fn main() {
tec's avatar
tec committed
146 147 148 149 150 151 152 153 154
    CombinedLogger::init(vec![
        TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed).unwrap(),
        WriteLogger::new(
            LevelFilter::Info,
            Config::default(),
            File::create("ucc-bot.log").unwrap(),
        ),
    ])
    .unwrap();
155 156


tec's avatar
tec committed
157
    // Configure the client with your Discord bot token in the environment.
158
    let token = read_to_string("discord_token").unwrap();
tec's avatar
tec committed
159 160 161 162 163 164 165 166 167 168 169

    // Create a new instance of the Client, logging in as a bot. This will
    // automatically prepend your bot token with "Bot ", which is a requirement
    // by Discord for bot users.
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    // Finally, start a single shard, and start listening to events.
    //
    // Shards will automatically attempt to reconnect, and will perform
    // exponential backoff until it reconnects.
    if let Err(why) = client.start() {
tec's avatar
tec committed
170
        error!("Client error: {:?}", why);
tec's avatar
tec committed
171 172
    }
}
tec's avatar
tec committed
173 174

fn message_type(message: &Message) -> &'static str {
175
    if message.embeds.len() <= 0 {
tec's avatar
tec committed
176 177 178 179
        return match message.content.splitn(2, ' ').next().unwrap() {
            "Role" => "role",
            _ => "misc",
        };
tec's avatar
tec committed
180
    }
181 182 183 184 185 186 187 188
    let title: String = message.embeds[0].title.clone().unwrap();
    let words_of_title: Vec<_> = title.splitn(2, ' ').collect();
    let first_word_of_title = words_of_title[0];
    return match first_word_of_title {
        "Motion" => "motion",
        "Poll" => "poll",
        _ => "misc",
    };
tec's avatar
tec committed
189
}