1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! slackbot is here to make creating your own Slack bot easy. It provides a relatively high-level
//! interface for creating Slack bots.
//!
//! # Examples
//!
//! Creates a bot that will respond to a message like `!bot echo Hello world!` with `Hello world!`
//! for any channels it is in.
//!
//! ```rust,no_run
//! extern crate slackbot;
//!
//! use slackbot::{SlackBot, Sender};
//!
//! fn main() {
//!     let mut echo_bot = SlackBot::new("bot", "BOT_API_TOKEN");
//!
//!     echo_bot.on("echo", Box::new(|sender: &mut Sender, args: &Vec<String>| {
//!         if args.len() > 0 {
//!             sender.respond_in_channel(args.join(" ")).unwrap();
//!         } else {
//!             sender.respond_in_channel("echo echo echo").unwrap();
//!         }
//!     }));
//!
//!     echo_bot.run().unwrap();
//! }
//! ```

extern crate slack;
extern crate serde_json;

use std::collections::HashMap;
use slack::RtmClient;

mod event_handler;
mod sender;

use event_handler::SlackBotEventHandler;
pub use sender::Sender;

/// The bot that handles commands and communication with Slack.
pub struct SlackBot {
    name: String,
    token: String,
    handlers: HashMap<String, Box<CommandHandler>>
}

impl SlackBot {
    /// Create a new bot to serve your team!
    ///
    /// # Examples
    ///
    /// ```
    /// use slackbot::SlackBot;
    ///
    /// let mut my_bot = SlackBot::new("bot", "YOUR_API_TOKEN");
    /// ```
    pub fn new<A,B>(name: A, token: B) -> Self
        where A: Into<String>, B: Into<String> {

        SlackBot {
            name: name.into(),
            token: token.into(),
            handlers: HashMap::new()
        }
    }

    /// Tell your bot what to do when it sees a command.
    ///
    /// The handler can be your own type that implements `CommandHandler`, but most simple cases
    /// can be covered by a simple closure.
    ///
    /// # Examples
    ///
    /// With a simple closure:
    ///
    /// ```
    /// # use slackbot::{SlackBot, Sender};
    /// # let mut my_bot = SlackBot::new("bot", "YOUR_API_TOKEN");
    /// my_bot.on("say-hello", Box::new(|sender: &mut Sender, args: &Vec<String>| {
    ///     sender.respond_in_channel("Hello, world!");
    /// }));
    /// ```
    ///
    /// With an implemented CommandHandler:
    ///
    /// ```
    /// # use slackbot::{SlackBot, Sender, CommandHandler};
    /// # let mut my_bot = SlackBot::new("bot", "YOUR_API_TOKEN");
    /// struct SayHelloCommandHandler;
    ///
    /// impl CommandHandler for SayHelloCommandHandler {
    ///     fn handle(&mut self, sender: &mut Sender, args: &Vec<String>) {
    ///         sender.respond_in_channel("Hello, world!");
    ///     }
    /// }
    ///
    /// my_bot.on("say-hello", Box::new(SayHelloCommandHandler));
    /// ```
    pub fn on<S: Into<String>>(&mut self, command_name: S, handler: Box<CommandHandler>) {
        self.handlers.insert(command_name.into(), handler);
    }

    /// Tell your bot to start pulling its weight!
    ///
    /// # Examples
    ///
    /// ```
    /// # use slackbot::{SlackBot, Sender};
    /// # let mut my_bot = SlackBot::new("bot", "YOUR_API_TOKEN");
    /// match my_bot.run() {
    ///     Ok(()) => println!("Bot shut down successfully. Goodbye world!"),
    ///     Err(err) => println!("Bot crashed. Error message: {}", err)
    /// };
    /// ```
    pub fn run(&mut self) -> Result<(), String> {
        let mut client = RtmClient::new(&self.token[..]);
        let mut handler = SlackBotEventHandler::new(&self.name[..], &mut self.handlers);

        client.login_and_run(&mut handler)
    }
}

/// A trait implemented by types that can handle commands.
///
/// # Examples
///
/// ```
/// # use slackbot::{Sender, CommandHandler};
/// struct SayHelloCommandHandler;
///
/// impl CommandHandler for SayHelloCommandHandler {
///     fn handle(&mut self, sender: &mut Sender, args: &Vec<String>) {
///         sender.respond_in_channel("Hello, world!");
///     }
/// }
/// ```
pub trait CommandHandler {
    /// Handle the command.
    fn handle(&mut self, sender: &mut Sender, args: &Vec<String>);
}

impl<F> CommandHandler for F where F: FnMut(&mut Sender, &Vec<String>) {
    fn handle(&mut self, sender: &mut Sender, args: &Vec<String>) {
        self(sender, args);
    }
}