From f09631b3914dcbd984eb4fd5b14014fdf3d87ca6 Mon Sep 17 00:00:00 2001 From: AmokDev Date: Sat, 15 Mar 2025 14:37:11 +0300 Subject: [PATCH] init --- .env.example | 3 ++ .gitignore | 3 ++ Cargo.toml | 11 ++++ src/commands/id.rs | 20 ++++++++ src/commands/mod.rs | 2 + src/commands/ping.rs | 10 ++++ src/config.rs | 7 +++ src/main.rs | 119 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 175 insertions(+) create mode 100644 .env.example create mode 100644 Cargo.toml create mode 100644 src/commands/id.rs create mode 100644 src/commands/mod.rs create mode 100644 src/commands/ping.rs create mode 100644 src/config.rs create mode 100644 src/main.rs diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..af8caf4 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +BOT_ID=123 +BOT_TOKEN=YOUR-BOT-TOKEN +GUILD_ID=321 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 620f8f6..8c91276 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# custom +.env + # ---> Rust # Generated by Cargo # will have compiled files and executables diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8fa3d0b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "discordbot-rs" +version = "0.1.0" +edition = "2021" + +[dependencies] +serenity = "0.12" +tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } +tracing = "0.1.23" +tracing-subscriber = "0.3" +dotenv = "0.15" diff --git a/src/commands/id.rs b/src/commands/id.rs new file mode 100644 index 0000000..db71f4f --- /dev/null +++ b/src/commands/id.rs @@ -0,0 +1,20 @@ +use serenity::builder::{CreateCommand, CreateCommandOption}; +use serenity::model::application::{CommandOptionType, ResolvedOption, ResolvedValue}; + +pub fn run(options: &[ResolvedOption]) -> String { + if let Some(ResolvedOption { + value: ResolvedValue::User(user, _), .. + }) = options.first() + { + format!("{}'s id is {}", user.tag(), user.id) + } else { + "Please provide a valid user".to_string() + } +} + +pub fn register() -> CreateCommand { + CreateCommand::new("id").description("Get a user id").add_option( + CreateCommandOption::new(CommandOptionType::User, "id", "The user to lookup") + .required(true), + ) +} \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..08c78cf --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,2 @@ +pub mod ping; +pub mod id; \ No newline at end of file diff --git a/src/commands/ping.rs b/src/commands/ping.rs new file mode 100644 index 0000000..3843d42 --- /dev/null +++ b/src/commands/ping.rs @@ -0,0 +1,10 @@ +use serenity::builder::CreateCommand; +use serenity::model::application::ResolvedOption; + +pub fn run(_options: &[ResolvedOption]) -> String { + "Pong!".to_string() +} + +pub fn register() -> CreateCommand { + CreateCommand::new("ping").description("A ping command") +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..1280156 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,7 @@ +use serenity::model::id::UserId; + +pub struct Config { + pub bot_id: UserId, + pub bot_token: String, + pub guild_id: u64, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..dd7eab2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,119 @@ +mod commands; + +use dotenv::dotenv; +use std::env; + +use serenity::async_trait; +use serenity::builder::{CreateInteractionResponse, CreateInteractionResponseMessage}; +use serenity::model::application::Interaction; +use serenity::model::gateway::Ready; +use serenity::model::channel::Message; +use serenity::model::user::OnlineStatus; +use serenity::model::id::GuildId; +use serenity::model::id::UserId; +use serenity::gateway::ActivityData; +use serenity::prelude::*; +use tracing::{warn, error, info}; + +mod config; +use config::Config; + +struct Handler { + config: Config, +} + +#[async_trait] +impl EventHandler for Handler { + + async fn message(&self, ctx: Context, msg: Message) { + if msg.content == ":3" && msg.author.id != self.config.bot_id { + if let Err(why) = msg.channel_id.say(&ctx.http, ":3").await { + error!("Error sending message: {why:?}"); + } + } + } + + async fn interaction_create(&self, ctx: Context, interaction: Interaction) { + if let Interaction::Command(command) = interaction { + + let content = match command.data.name.as_str() { + "ping" => Some(commands::ping::run(&command.data.options())), + "id" => Some(commands::id::run(&command.data.options())), + _ => Some(":no_entry:".to_string()), + }; + + if let Some(content) = content { + let data = CreateInteractionResponseMessage::new().content(content); + let builder = CreateInteractionResponse::Message(data); + if let Err(why) = command.create_response(&ctx.http, builder).await { + warn!("Cannot respond to slash command: {why}"); + } + } + } + } + + async fn ready(&self, ctx: Context, ready: Ready) { + info!("{} is connected!", ready.user.name); + + let guild_id = GuildId::new(self.config.guild_id); + + let _commands = guild_id.set_commands( + &ctx.http, + vec![ + commands::ping::register(), + commands::id::register(), + ] + ).await; + + ctx.set_presence( + Some(ActivityData::playing("/help")), + OnlineStatus::DoNotDisturb, + ); + + } +} + +#[tokio::main] +async fn main() { + tracing_subscriber::fmt::init(); + + dotenv().ok(); + + let bot_id = UserId::new( + env::var("BOT_ID") + .expect("BOT_ID не найден") + .parse() + .expect("Неверный формат BOT_ID") + ); + + let guild_id = env::var("GUILD_ID") + .expect("GUILD_ID не найден") + .parse() + .expect("Неверный формат GUILD_ID"); + + let bot_token = env::var("BOT_TOKEN") + .expect("BOT_TOKEN не найден") + .parse() + .expect("Неверный формат BOT_TOKEN"); + + + let config = Config { + bot_id: bot_id, + bot_token: bot_token, + guild_id: guild_id, + }; + + let intents = GatewayIntents::GUILD_MESSAGES + | GatewayIntents::DIRECT_MESSAGES + | GatewayIntents::MESSAGE_CONTENT; + + let token = &config.bot_token; + let mut client = Client::builder(token, intents) + .event_handler(Handler { config }) + .await + .expect("Error creating client"); + + if let Err(why) = client.start().await { + error!("Client error: {why:?}"); + } +} \ No newline at end of file