-
Notifications
You must be signed in to change notification settings - Fork 565
/
main.rs
193 lines (174 loc) · 6.83 KB
/
main.rs
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! Requires the 'methods' feature flag be enabled in your project's Cargo.toml.
//!
//! This can be activated by specifying the feature in the dependency section:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/zeyla/serenity.rs.git"
//! features = ["framework", "methods"]
//! ```
#[macro_use]
extern crate serenity;
extern crate typemap;
use serenity::client::Context;
use serenity::Client;
use serenity::model::{Message, permissions};
use serenity::ext::framework::help_commands;
use std::collections::HashMap;
use std::env;
use std::fmt::Write;
use typemap::Key;
struct CommandCounter;
impl Key for CommandCounter {
type Value = HashMap<String, u64>;
}
fn main() {
// Configure the client with your Discord bot token in the environment.
let token = env::var("DISCORD_TOKEN")
.expect("Expected a token in the environment");
let mut client = Client::login_bot(&token);
{
let mut data = client.data.lock().unwrap();
data.insert::<CommandCounter>(HashMap::default());
}
client.on_ready(|_, ready| {
println!("{} is connected!", ready.user.name);
});
// Commands are equivalent to:
// "~about"
// "~emoji cat"
// "~emoji dog"
// "~multiply"
// "~ping"
// "~some long command"
client.with_framework(|f| f
// Configures the client, allowing for options to mutate how the
// framework functions.
//
// Refer to the documentation for
// `serenity::ext::framework::Configuration` for all available
// configurations.
.configure(|c| c
.allow_whitespace(true)
.on_mention(true)
.rate_limit_message("Try this again in `%time%` seconds.")
.prefix("~"))
// Set a function to be called prior to each command execution. This
// provides the context of the command, the message that was received,
// and the full name of the command that will be called.
//
// You can not use this to determine whether a command should be
// executed. Instead, `set_check` is provided to give you this
// functionality.
.before(|context, message, command_name| {
println!("Got command '{}' by user '{}'",
command_name,
message.author.name);
// Increment the number of times this command has been run once. If
// the command's name does not exist in the counter, add a default
// value of 0.
let mut data = context.data.lock().unwrap();
let counter = data.get_mut::<CommandCounter>().unwrap();
let entry = counter.entry(command_name.clone()).or_insert(0);
*entry += 1;
true // if `before` returns false, command processing doesn't happen.
})
// Similar to `before`, except will be called directly _after_
// command execution.
.after(|_, _, command_name, error| {
match error {
Ok(()) => println!("Processed command '{}'", command_name),
Err(why) => println!("Command '{}' returned error {:?}", command_name, why),
}
})
// Can't be used more than once per 5 seconds:
.simple_bucket("emoji", 5)
// Can't be used more than 2 times per 30 seconds, with a 5 second delay:
.bucket("complicated", 5, 30, 2)
.command("about", |c| c.exec_str("A test bot"))
.command("help", |c| c.exec_help(help_commands::plain))
.command("commands", |c| c
// Make this command use the "complicated" bucket.
.bucket("complicated")
.exec(commands))
.group("Emoji", |g| g
.prefix("emoji")
.command("cat", |c| c
.desc("Sends an emoji with a cat.")
.batch_known_as(vec!["kitty", "neko"]) // Adds multiple aliases
.bucket("emoji") // Make this command use the "emoji" bucket.
.exec_str(":cat:")
// Allow only administrators to call this:
.required_permissions(permissions::ADMINISTRATOR))
.command("dog", |c| c
.desc("Sends an emoji with a dog.")
.bucket("emoji")
.exec_str(":dog:")))
.command("multiply", |c| c
.known_as("*") // Lets us call ~* instead of ~multiply
.exec(multiply))
.command("ping", |c| c
.check(owner_check)
.exec_str("Pong!"))
.command("some long command", |c| c.exec(some_long_command)));
if let Err(why) = client.start() {
println!("Client error: {:?}", why);
}
}
// Commands can be created via the `command!` macro, to avoid manually typing
// type annotations.
//
// This may bring more features available for commands in the future. See the
// "multiply" command below for some of the power that the `command!` macro can
// bring.
command!(commands(context, _msg, _args) {
let mut contents = "Commands used:\n".to_owned();
let data = context.data.lock().unwrap();
let counter = data.get::<CommandCounter>().unwrap();
for (k, v) in counter {
let _ = write!(contents, "- {name}: {amount}\n", name=k, amount=v);
}
if let Err(why) = context.say(&contents) {
println!("Error sending message: {:?}", why);
}
});
// A function which acts as a "check", to determine whether to call a command.
//
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
fn owner_check(_: &mut Context, message: &Message) -> bool {
// Replace 7 with your ID
message.author.id == 7
}
command!(some_long_command(context, _msg, args) {
if let Err(why) = context.say(&format!("Arguments: {:?}", args)) {
println!("Error sending message: {:?}", why);
}
});
// Using the `command!` macro, commands can be created with a certain type of
// "dynamic" type checking. This is a method of requiring that the arguments
// given match the required type, and maps those arguments to the specified
// bindings.
//
// For example, the following will be correctly parsed by the macro:
//
// `~multiply 3.7 4.3`
//
// However, the following will not, as the second argument can not be an f64:
//
// `~multiply 3.7 four`
//
// Since the argument can't be converted, the command returns early.
//
// Additionally, if not enough arguments are given (e.g. `~multiply 3`), then
// the command will return early. If additional arguments are provided, they
// will be ignored.
//
// Argument type overloading is currently not supported.
command!(multiply(context, _msg, args, first: f64, second: f64) {
let res = first * second;
if let Err(why) = context.say(&res.to_string()) {
println!("Err sending product of {} and {}: {:?}", first, second, why);
}
});