initial commit
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Intellij Idea
|
||||
.idea
|
||||
mixer_discord_bot.iml
|
||||
|
||||
# Rust
|
||||
Cargo.lock
|
||||
target/
|
||||
|
||||
# Database
|
||||
data.db
|
||||
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "mixer_discord_bot"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "*", features = ["full"] }
|
||||
serenity = { version = "*", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] }
|
||||
sqlx = { version = "*", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||
sea-orm = { version = "*", features = ["sqlx-sqlite", "runtime-tokio-rustls", "macros"] }
|
||||
ctrlc = "*"
|
||||
13
src/bot/commands/mod.rs
Normal file
13
src/bot/commands/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
pub mod ping;
|
||||
|
||||
use serenity::builder::CreateApplicationCommand;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
|
||||
use serenity::async_trait;
|
||||
|
||||
#[async_trait]
|
||||
pub trait MixerCommand: Sync + Send {
|
||||
fn name(&self) -> String;
|
||||
fn create(&self, command: &mut CreateApplicationCommand);
|
||||
async fn execute(&self, ctx: &Context, interaction: ApplicationCommandInteraction) -> serenity::Result<()>;
|
||||
}
|
||||
38
src/bot/commands/ping.rs
Normal file
38
src/bot/commands/ping.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use serenity::builder::CreateApplicationCommand;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::application::interaction::{
|
||||
application_command::ApplicationCommandInteraction,
|
||||
InteractionResponseType
|
||||
};
|
||||
use serenity::async_trait;
|
||||
use crate::bot::commands::MixerCommand;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ping;
|
||||
|
||||
#[async_trait]
|
||||
impl MixerCommand for Ping {
|
||||
fn name(&self) -> String {
|
||||
"ping".to_string()
|
||||
}
|
||||
|
||||
fn create(&self, command: &mut CreateApplicationCommand) {
|
||||
command.name(self.name()).description("Hello world!");
|
||||
}
|
||||
|
||||
async fn execute(&self, ctx: &Context, interaction: ApplicationCommandInteraction) -> serenity::Result<()> {
|
||||
let content = "Pong!";
|
||||
interaction.create_interaction_response(&ctx.http, |response| {
|
||||
response.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||
.interaction_response_data(|message| {
|
||||
message.content(content)
|
||||
})
|
||||
}).await?;
|
||||
|
||||
println!("{:#?}", interaction.get_interaction_response(&ctx.http).await?);
|
||||
|
||||
println!("Interacted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
41
src/bot/handler.rs
Normal file
41
src/bot/handler.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use serenity::client::{Context, EventHandler};
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::async_trait;
|
||||
use serenity::model::application::command::Command;
|
||||
use serenity::model::application::interaction::Interaction;
|
||||
use crate::bot::MixerBotContainer;
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn ready(&self, ctx: Context, data_about_bot: Ready) {
|
||||
println!("{} is connected!", data_about_bot.user.name);
|
||||
|
||||
let data = ctx.data.read().await;
|
||||
let bot_commands = &data.get::<MixerBotContainer>().unwrap().read().await.commands;
|
||||
Command::set_global_application_commands(&ctx.http, |commands| {
|
||||
for cmd in bot_commands.values() {
|
||||
commands.create_application_command(|command| {
|
||||
cmd.create(command);
|
||||
command
|
||||
});
|
||||
println!("Registered command \"{}\"", cmd.name())
|
||||
}
|
||||
commands
|
||||
}).await.unwrap();
|
||||
}
|
||||
|
||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
let data = ctx.data.read().await;
|
||||
let bot_commands = &data.get::<MixerBotContainer>().unwrap().read().await.commands;
|
||||
|
||||
match interaction {
|
||||
Interaction::ApplicationCommand(command) =>
|
||||
if let Some(mixer_command) = bot_commands.get(&command.data.name) {
|
||||
mixer_command.execute(&ctx, command).await.unwrap()
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/bot/mod.rs
Normal file
76
src/bot/mod.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
pub mod commands;
|
||||
mod handler;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use serenity::{CacheAndHttp, Client};
|
||||
use serenity::client::bridge::gateway::ShardManager;
|
||||
use serenity::prelude::{GatewayIntents, TypeMap, TypeMapKey};
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use crate::bot::commands::MixerCommand;
|
||||
use crate::bot::handler::Handler;
|
||||
|
||||
pub struct MixerBot {
|
||||
token: String,
|
||||
commands: HashMap<String, Box<dyn MixerCommand>>,
|
||||
}
|
||||
|
||||
struct ShardManagerContainer;
|
||||
struct MixerBotContainer;
|
||||
|
||||
|
||||
impl TypeMapKey for ShardManagerContainer {
|
||||
type Value = Arc<Mutex<ShardManager>>;
|
||||
}
|
||||
|
||||
impl TypeMapKey for MixerBotContainer {
|
||||
type Value = Arc<RwLock<MixerBot>>;
|
||||
}
|
||||
|
||||
|
||||
impl MixerBot {
|
||||
pub fn new(token: String) -> Self {
|
||||
Self {
|
||||
token,
|
||||
commands: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(self) -> serenity::Result<()> {
|
||||
let mut client = Client::builder(&self.token, GatewayIntents::empty()).event_handler(Handler).await?;
|
||||
|
||||
let bot;
|
||||
{
|
||||
let mut data = client.data.write().await;
|
||||
data.insert::<ShardManagerContainer>(client.shard_manager.clone());
|
||||
data.insert::<MixerBotContainer>(Arc::new(RwLock::new(self)));
|
||||
bot = data.get::<MixerBotContainer>().unwrap().clone();
|
||||
}
|
||||
|
||||
let shard_manager = client.shard_manager.clone();
|
||||
let cache_and_http = client.cache_and_http.clone();
|
||||
let data = client.data.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::signal::ctrl_c().await.expect("Could not register ctrl+c handler");
|
||||
|
||||
bot.write().await.shutdown(data, cache_and_http).await;
|
||||
|
||||
shard_manager.lock().await.shutdown_all().await;
|
||||
});
|
||||
|
||||
|
||||
client.start().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_command(&mut self, command: Box<dyn MixerCommand>) -> &mut Self {
|
||||
self.commands.insert(command.name(), command);
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn shutdown(&self, data: Arc<RwLock<TypeMap>>, cache_and_http: Arc<CacheAndHttp>) {
|
||||
println!("{:#?}", cache_and_http.http);
|
||||
println!("Bot has been shutdown.");
|
||||
}
|
||||
}
|
||||
17
src/main.rs
Normal file
17
src/main.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
mod bot;
|
||||
|
||||
use crate::bot::commands::ping::Ping;
|
||||
use crate::bot::MixerBot;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> serenity::Result<()> {
|
||||
let mut bot = MixerBot::new(
|
||||
"NTE2MzMyMzM2NzQ5NzQwMDUz.GiLPzQ.j5gIUGqx6vF6CFhJv8yizksDi-dOBqCvxR32EE".to_string()
|
||||
);
|
||||
|
||||
bot.add_command(Box::new(Ping));
|
||||
|
||||
bot.start().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user