init - arche setup, empty API, discord bot

This commit is contained in:
2025-04-29 01:48:49 +02:00
commit c56edaf144
10 changed files with 2910 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
use rand::seq::IndexedRandom;
use serenity::all::{
CommandInteraction, CommandOptionType, Context, CreateCommandOption, CreateEmbed,
CreateInteractionResponse, CreateInteractionResponseMessage, MessageBuilder, ResolvedValue,
};
use serenity::builder::CreateCommand;
const KISS_GIF_LINK: &str = "https://media.discordapp.net/attachments/594222795999805643/1078363884190183485/ezgif-1-96508f9a03.gif?ex=681108a1&is=680fb721&hm=719ea63308d9f2989fbdc8110735805c2e9c26a378e749785fa141ddb180203f";
const KISS_TEXTS: &[&str] = &[
"How endearing... :3 :3",
"What does this imply!?",
"What a cutie!",
"That's a little gay...",
"With tongue though?!",
"Will they reciprocate?",
"And they were roommates.",
"How brave!",
"No homo.",
"Better than \"kys\".",
"What comes next?",
];
pub async fn run(ctx: &Context, interaction: &CommandInteraction) -> Result<(), serenity::Error> {
let options = &interaction.data.options();
let target_user = options
.iter()
.find_map(|opt| {
if opt.name == "target" {
match &opt.value {
ResolvedValue::User(user, member) => Some((user, member.as_ref())),
_ => None,
}
} else {
None
}
})
.expect("Target user should be present");
let use_bigger = options
.iter()
.find_map(|opt| {
if opt.name == "bigger" {
match &opt.value {
ResolvedValue::Boolean(v) => Some(*v),
_ => None,
}
} else {
None
}
})
.unwrap_or(false);
let caller_name = interaction
.member
.as_ref()
.map(|m| m.nick.clone().unwrap_or_else(|| m.user.name.clone()))
.unwrap_or_else(|| interaction.user.name.clone());
let target_name = match target_user {
(user, Some(member)) => member.nick.clone().unwrap_or_else(|| user.name.clone()),
(user, None) => user.name.clone(),
};
let rand_text = KISS_TEXTS.choose(&mut rand::rng()).unwrap();
let mention = MessageBuilder::new()
.mention(target_user.0.to_owned())
.build();
let mut embed = CreateEmbed::new()
.title(format!("{} kisses {}", caller_name, target_name))
.description(format!("{rand_text}\n{mention}"))
.color(0xFF89B4);
if use_bigger {
embed = embed.image(KISS_GIF_LINK.to_string())
} else {
embed = embed.thumbnail(KISS_GIF_LINK.to_string())
}
interaction
.create_response(
&ctx.http,
CreateInteractionResponse::Message(
CreateInteractionResponseMessage::new().add_embed(embed),
),
)
.await
}
pub fn register() -> CreateCommand {
CreateCommand::new("kiss")
.description("pocałuj kogoś.")
.add_option(
CreateCommandOption::new(
CommandOptionType::User,
"target",
"użytkownik do pocałowania",
)
.required(true),
)
.add_option(
CreateCommandOption::new(
CommandOptionType::Boolean,
"bigger",
"czy użyć wersji z większym obrazkiem?",
)
.required(false),
)
}

View File

@@ -0,0 +1,2 @@
pub mod kiss;
pub mod ping;

View File

@@ -0,0 +1,19 @@
use serenity::all::{
CommandInteraction, Context, CreateInteractionResponse, CreateInteractionResponseMessage,
};
use serenity::builder::CreateCommand;
pub async fn run(ctx: &Context, command: &CommandInteraction) -> Result<(), serenity::Error> {
command
.create_response(
&ctx.http,
CreateInteractionResponse::Message(
CreateInteractionResponseMessage::new().content("P-p-ping!"),
),
)
.await
}
pub fn register() -> CreateCommand {
CreateCommand::new("ping").description("komenda testowa.")
}

84
src/discordbot/mod.rs Normal file
View File

@@ -0,0 +1,84 @@
use serenity::{
all::{CreateInteractionResponse, CreateInteractionResponseMessage, Interaction, Ready},
async_trait,
prelude::*,
};
use tracing::info;
const TOKEN_ENV: &str = "DISCORD_GRA_MAIN_TOKEN";
const GUILD_ID1: &str = "DISCORD_MAIN_SERVER_ID";
const GUILD_ID2: &str = "DISCORD_RD_SERVER_ID";
struct Handler;
mod commands;
#[async_trait]
impl EventHandler for Handler {
async fn ready(&self, ctx: Context, ready: Ready) {
info!("{} is connected!", ready.user.name);
let cmds = vec![commands::ping::register(), commands::kiss::register()];
let main_guild_id = serenity::model::id::GuildId::from(
std::env::var(GUILD_ID1).unwrap().parse::<u64>().unwrap(),
);
let dev_guild_id = serenity::model::id::GuildId::from(
std::env::var(GUILD_ID2).unwrap().parse::<u64>().unwrap(),
);
match main_guild_id.set_commands(&ctx.http, cmds.clone()).await {
Ok(_) => info!("Successfully registered commands on main guild.",),
Err(why) => info!("Failed to register commands on main guild: {why:?}"),
};
match dev_guild_id.set_commands(&ctx.http, cmds.clone()).await {
Ok(_) => info!("Successfully registered commands on dev guild."),
Err(why) => info!("Failed to register commands on dev guild: {why:?}"),
};
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
if let Interaction::Command(command) = interaction {
let result = match command.data.name.as_str() {
"ping" => commands::ping::run(&ctx, &command).await,
"kiss" => commands::kiss::run(&ctx, &command).await,
_ => {
command
.create_response(
&ctx.http,
CreateInteractionResponse::Message(
CreateInteractionResponseMessage::new().content("Not implemented"),
),
)
.await
}
};
if let Err(why) = result {
println!("Error executing command: {:?}", why);
}
}
}
}
pub async fn init() {
tokio::spawn(async {
init_bot().await;
});
}
async fn init_bot() {
let token = std::env::var(TOKEN_ENV).unwrap();
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client = Client::builder(&token, intents)
.event_handler(Handler)
.await
.expect("errored creating client");
if let Err(why) = client.start().await {
info!("client error: {why:?}");
}
}