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
mod commands;
mod event_handler;
use crate::discord_bot::event_handler::Handler;
use crate::env::{global_config, DiscordConfig};
use actix::{Actor, ActorContext, ActorFuture, AsyncContext, Context, Supervised};
use futures::future::LocalBoxFuture;
use futures::Future;
use serenity::{Client, Result as SerenityResult};
use std::pin::Pin;
use std::task::Context as StdContext;
use std::task::Poll;
pub struct DiscordBot;
impl DiscordBot {
async fn create() -> SerenityResult<Client> {
let discord_conf: &DiscordConfig = &global_config().discord_config;
let app_id = discord_conf
.client_id
.as_str()
.parse::<u64>()
.expect("Could not parse Discord Application ID.");
return Client::builder(&discord_conf.bot_token)
.event_handler(Handler)
.application_id(app_id)
.await;
}
async fn create_and_listen() -> SerenityResult<()> {
Self::create().await?.start_autosharded().await
}
fn wrapped_create_and_listen() -> ListeningFuture {
ListeningFuture {
inner: Box::pin(Self::create_and_listen()),
}
}
}
struct ListeningFuture {
inner: LocalBoxFuture<'static, SerenityResult<()>>,
}
impl ActorFuture for ListeningFuture {
type Output = ();
type Actor = DiscordBot;
fn poll(
mut self: Pin<&mut Self>,
_: &mut Self::Actor,
ctx: &mut <DiscordBot as Actor>::Context,
task: &mut StdContext<'_>,
) -> Poll<Self::Output> {
let pinned_inner = Pin::new(&mut self.inner);
match Future::poll(pinned_inner, task) {
Poll::Pending => Poll::Pending,
Poll::Ready(res) => {
error!("Serenity Discord client crashed and returned: {:?}", res);
ctx.stop();
Poll::Ready(())
}
}
}
}
impl Actor for DiscordBot {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
info!("Starting Discord bot");
let discord_conf: &DiscordConfig = &global_config().discord_config;
info!("Invite bot using \
https://discord.com/api/oauth2/authorize?client_id={}&permissions=2147549184&response_type=code&scope=bot%20applications.commands",
discord_conf.client_id.as_str());
ctx.wait(Self::wrapped_create_and_listen());
}
}
impl Supervised for DiscordBot {
fn restarting(&mut self, ctx: &mut Self::Context) {
error!("Discord bot crashed. Restarting now");
ctx.wait(Self::wrapped_create_and_listen());
}
}