Update template with changes
This commit is contained in:
parent
ef52e95e03
commit
05c9bed1f8
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -1463,15 +1463,23 @@ name = "rustbot"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"poise",
|
||||
"rand",
|
||||
"reqwest",
|
||||
"rustbot_cmds",
|
||||
"rustbot_events",
|
||||
"rustbot_lib",
|
||||
"rustbot_tokens",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustbot_cmds"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"poise",
|
||||
"rand",
|
||||
"reqwest",
|
||||
"rustbot_lib",
|
||||
"serde",
|
||||
"sysinfo",
|
||||
"time",
|
||||
"tokio",
|
||||
"uptime_lib",
|
||||
]
|
||||
|
||||
@ -1492,7 +1500,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustbot_lib"
|
||||
version = "0.1.19"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo_toml",
|
||||
"poise",
|
||||
|
23
Cargo.toml
23
Cargo.toml
@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"cmds",
|
||||
"events",
|
||||
"jobs",
|
||||
"library",
|
||||
@ -16,21 +17,21 @@ cargo_toml = "0.21.0"
|
||||
poise = "0.6.1"
|
||||
regex = "1.11.0"
|
||||
serde = "1.0.210"
|
||||
tokio = { version = "1.40.0", features = ["macros", "signal", "rt-multi-thread"] }
|
||||
reqwest = { version = "0.12.8", features = ["native-tls-vendored"] }
|
||||
|
||||
[dependencies]
|
||||
rustbot_events = { path = "events" }
|
||||
rustbot_lib = { path = "library" }
|
||||
rustbot_tokens = { path = "tsclient" }
|
||||
poise = { workspace = true }
|
||||
rand = "0.8.5"
|
||||
reqwest = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
sysinfo = "0.33.0"
|
||||
time = "0.3.36"
|
||||
tokio = { workspace = true }
|
||||
uptime_lib = "0.3.1"
|
||||
tokio = { version = "1.40.0", features = ["macros", "signal", "rt-multi-thread"] }
|
||||
reqwest = { version = "0.12.8", features = ["native-tls-vendored"] }
|
||||
rustbot_lib = { path = "library" }
|
||||
|
||||
[dependencies]
|
||||
poise = { workspace = true }
|
||||
rustbot_cmds = { path = "cmds" }
|
||||
rustbot_events = { path = "events" }
|
||||
rustbot_lib = { workspace = true }
|
||||
rustbot_tokens = { path = "tsclient" }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[patch.crates-io]
|
||||
poise = { git = "https://github.com/serenity-rs/poise", branch = "serenity-next" }
|
||||
|
13
cmds/Cargo.toml
Normal file
13
cmds/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rustbot_cmds"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
poise = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
rustbot_lib = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
sysinfo = { workspace = true }
|
||||
uptime_lib = { workspace = true }
|
26
cmds/src/dispatch.rs
Normal file
26
cmds/src/dispatch.rs
Normal file
@ -0,0 +1,26 @@
|
||||
mod dev;
|
||||
mod eightball;
|
||||
mod ping;
|
||||
mod uptime;
|
||||
|
||||
pub use {
|
||||
dev::dev,
|
||||
eightball::eightball,
|
||||
ping::ping,
|
||||
uptime::uptime
|
||||
};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collect {
|
||||
() => {
|
||||
vec![
|
||||
// Developer command(s)
|
||||
$crate::dev(),
|
||||
// Utility commands
|
||||
$crate::ping(),
|
||||
$crate::uptime(),
|
||||
// Unsorted mess
|
||||
$crate::eightball(),
|
||||
]
|
||||
};
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
use rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult
|
||||
};
|
||||
use poise::{
|
||||
CreateReply,
|
||||
serenity_prelude::{
|
||||
ChannelId,
|
||||
ShardId,
|
||||
ShardRunnerInfo
|
||||
use {
|
||||
poise::{
|
||||
CreateReply,
|
||||
serenity_prelude::{
|
||||
ChannelId,
|
||||
ShardId,
|
||||
ShardRunnerInfo
|
||||
}
|
||||
},
|
||||
rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,9 +46,7 @@ async fn format_shard_info(
|
||||
interaction_context = "Guild|BotDm|PrivateChannel",
|
||||
subcommands("deploy", "servers", "shards", "echo")
|
||||
)]
|
||||
pub async fn dev(_: RustbotContext<'_>) -> RustbotResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
pub async fn dev(_: RustbotContext<'_>) -> RustbotResult<()> { Ok(()) }
|
||||
|
||||
/// Deploy commands to this guild or globally
|
||||
#[poise::command(prefix_command)]
|
||||
@ -90,7 +90,8 @@ async fn echo(
|
||||
ctx: RustbotContext<'_>,
|
||||
#[description = "Message to be echoed as a bot"] message: String,
|
||||
#[description = "Channel to send this to"]
|
||||
#[channel_types("Text", "PublicThread", "PrivateThread")] channel: Option<ChannelId>
|
||||
#[channel_types("Text", "PublicThread", "PrivateThread")]
|
||||
channel: Option<ChannelId>
|
||||
) -> RustbotResult<()> {
|
||||
ctx.defer_ephemeral().await?;
|
||||
|
||||
@ -101,18 +102,10 @@ async fn echo(
|
||||
|
||||
match ChannelId::new(channel.get()).say(ctx.http(), message).await {
|
||||
Ok(_) => {
|
||||
ctx.send(
|
||||
CreateReply::new()
|
||||
.content("Sent!")
|
||||
.ephemeral(true)
|
||||
).await?;
|
||||
ctx.send(CreateReply::new().content("Sent!").ephemeral(true)).await?;
|
||||
},
|
||||
Err(y) => {
|
||||
ctx.send(
|
||||
CreateReply::new()
|
||||
.content(format!("Failed... `{y}`"))
|
||||
.ephemeral(true)
|
||||
).await?;
|
||||
ctx.send(CreateReply::new().content(format!("Failed... `{y}`")).ephemeral(true)).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
276
cmds/src/dispatch/eightball.rs
Executable file
276
cmds/src/dispatch/eightball.rs
Executable file
@ -0,0 +1,276 @@
|
||||
use {
|
||||
poise::{
|
||||
builtins::paginate,
|
||||
serenity_prelude::UserId
|
||||
},
|
||||
rand::random,
|
||||
rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult,
|
||||
config::BINARY_PROPERTIES
|
||||
}
|
||||
};
|
||||
|
||||
#[derive(poise::ChoiceParameter, Clone)]
|
||||
enum ResponseMode {
|
||||
Normal,
|
||||
Chicken,
|
||||
#[name = "Chaotic & Unhinged"]
|
||||
Chaotic
|
||||
}
|
||||
|
||||
/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
install_context = "Guild|User",
|
||||
interaction_context = "Guild|BotDm|PrivateChannel",
|
||||
rename = "8ball"
|
||||
)]
|
||||
pub async fn eightball(
|
||||
ctx: RustbotContext<'_>,
|
||||
#[description = "Your yes/no question"] question: String,
|
||||
#[description = "Response modes"] mode: Option<ResponseMode>
|
||||
) -> RustbotResult<()> {
|
||||
if question.to_ascii_lowercase().contains("niko, show list") {
|
||||
show_list(ctx, mode.clone().unwrap_or(ResponseMode::Normal)).await?;
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let rand_resp = match mode {
|
||||
Some(ResponseMode::Chicken) => get_random_chicken_response(),
|
||||
Some(ResponseMode::Chaotic) => get_random_chaotic_response(),
|
||||
_ => get_random_response()
|
||||
};
|
||||
|
||||
ctx.reply(format!("> {question}\n{rand_resp}")).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn show_list(
|
||||
ctx: RustbotContext<'_>,
|
||||
list_type: ResponseMode
|
||||
) -> RustbotResult<()> {
|
||||
if ctx.author().id != UserId::new(BINARY_PROPERTIES.developers[0]) {
|
||||
ctx
|
||||
.reply("The list knows you're looking, but it's playing a game of hide and seek. For now, it wins.")
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let chunks: Vec<String> = match list_type {
|
||||
ResponseMode::Normal => RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect(),
|
||||
ResponseMode::Chicken => CHICKEN_RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect(),
|
||||
ResponseMode::Chaotic => CHAOTIC_RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect()
|
||||
};
|
||||
|
||||
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
|
||||
paginate(ctx, &pages).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const RESPONSES: [&str; 45] = [
|
||||
"Reply hazy. Look it up on Google.", // no
|
||||
"Meh — Figure it out yourself.", // no
|
||||
"I don't know, what do you think?", // no
|
||||
"Yes.", // yes
|
||||
"No.", // no
|
||||
"It is decidedly so", // yes
|
||||
"Signs point to... maybe... depends on... hold on, let me get my glasses, this is getting pretty tiny... depends on whether you'd be up to \
|
||||
getting to know your Magic 8-Ball a little better.", // no
|
||||
"Signs point to... ~~yes~~ no.", // no
|
||||
"Why do you want to know the answer? It's obviously a yes.", // yes
|
||||
"Outlook not so good.", // no
|
||||
"Outlook hazy.", // no
|
||||
"What are you, stupid?", // no
|
||||
"How the hell do you not know that?", // no
|
||||
"Really? Making a decision based on what the plastic 8-Ball says? Jesus...", // no
|
||||
"Try asking later...", // no
|
||||
"I don't know, whip out the ouija board and try again?", // no
|
||||
"The answer is yes.", // yes
|
||||
"Yes, actually no. Wait, nevermind.", // no
|
||||
"Maybeee...", // yes
|
||||
"Definitely!", // yes
|
||||
"It is decidedly so.", // yes
|
||||
"My reply is no.", // no
|
||||
"My sources confirms that the answer is no.\nSource: :sparkles: *i made it up* :sparkles:", // no
|
||||
"As I see it, yes.", // yes
|
||||
"Don't count on it.", // no
|
||||
"Whoa! Why do I have to answer this?", // no
|
||||
"Highly unlikely.", // no
|
||||
"Sure, but with extreme cautions.", // yes
|
||||
"What kind of stupid question is that?? No! I'm not answering that!", // no
|
||||
"Try asking this to a chicken. Probably knows it better than I do!", // no
|
||||
"Not in a million years!", // no
|
||||
"As a matter of fact, yes.", // yes
|
||||
"It's a no, better go ask someone else.", // no
|
||||
"In the end, it's not a bad choice.", // yes
|
||||
"Nope, not today.", // no
|
||||
"Cross your fingers, the answer is yes!", // yes
|
||||
"Nope. *shakes head*", // no
|
||||
"The fortune cookie said yes.", // yes
|
||||
"Sorry, the fortune cookie over there said no.", // no
|
||||
"Sorry, not happening.", // no
|
||||
"I'll have to consult my sources... *flips coin*... no.", // no
|
||||
"I'll have to consult the magic 8-ball... *shakes*... no.", // no
|
||||
"I'm not sure to be honest, let's ask your friend. Oh wait...", // no
|
||||
"This question flew over my head, I'll pass.", // no
|
||||
"Oops, the Magic 8-Ball shattered itself when you asked that! I'll take that as a no." // no
|
||||
];
|
||||
|
||||
const CHICKEN_RESPONSES: [&str; 54] = [
|
||||
"Cluck cluck... Reply hazy, try pecking Google.", // no
|
||||
"Meh... Figure it out yourself, or scratch around a bit.", // no
|
||||
"I don't know... what do you think? *pecks at ground*", // no
|
||||
"BAWK! YES!", // yes
|
||||
"Cluck... no.", // no
|
||||
"It is decidedly so! *flaps wings*", // yes
|
||||
"Signs point to... maybe... hold on, let me fluff my feathers... depends on whether you'd get to know your Magic Chicken a bit better.", // no
|
||||
"Signs point to... ~~yes~~ cluck no.", // no
|
||||
"Why do you want to know? It's a big cluckin' yes!", // yes
|
||||
"Outlook not so clucking good.", // no
|
||||
"Outlook cluckin' hazy.", // no
|
||||
"What are you, a lost chick? Cluck!", // no
|
||||
"How the cluck do you not know that?", // no
|
||||
"Really? Asking a chicken to decide your fate? *clucks judgmentally*", // no
|
||||
"Peck back later, I'm nesting...", // no
|
||||
"I don't know, try flapping your wings and ask again?", // no
|
||||
"The answer is a big ol' yes! *flaps happily*", // yes
|
||||
"Yes... wait, actually... no. Cluck, I'm confused.", // no
|
||||
"Maaaaybe... *chicken waddle*?", // yes
|
||||
"Definitely! *struts confidently*", // yes
|
||||
"It is decidedly so. *struts with pride*", // yes
|
||||
"My reply is a solid *cluck* no.", // no
|
||||
"My sources confirm it's a cluckin' no.\nSource: 🐔 *I made it up* 🐔", // no
|
||||
"As I see it, yes! *pecks approvingly*", // yes
|
||||
"Don't count on it. *cluck cluck*", // no
|
||||
"Whoa, why do I have to answer this? *fluffs feathers*", // no
|
||||
"Highly unlikely. *chicken stare*", // no
|
||||
"Sure, but with extreme cluckin' caution.", // yes
|
||||
"What kind of stupid question is that?? No! *angry clucks*", // no
|
||||
"Try asking this to a fellow chicken. They probably know better than I do!", // no
|
||||
"Cluck yes! *does a happy chicken dance*", // yes
|
||||
"No way, not even for a big bag of feed.", // no
|
||||
"Yes! *lays egg of approval*", // yes
|
||||
"It's a no, better go scratch somewhere else.", // no
|
||||
"Cluck-tastic! That's a definite yes.", // yes
|
||||
"Cluck yeah! *struts proudly*", // yes
|
||||
"Nope, not today. *shakes head*", // no
|
||||
"Feathers crossed, the answer is yes!", // yes
|
||||
"Chicken says nope. *tilts head*", // no
|
||||
"Absolutely! *clucks happily*", // yes
|
||||
"Not a chance. *fluffs feathers*", // no
|
||||
"Eggcellent choice! Yes!", // yes
|
||||
"Not in a million clucks!", // no
|
||||
"As a matter of cluck, yes! *clucks approvingly*", // yes
|
||||
"It's a nopity nope, better go ask another chicken.", // no
|
||||
"In the end, it's not a bad cluck", // yes
|
||||
"Nope, not today. *clucks sadly*", // no
|
||||
"Cross your feathers, the answer is yes!", // yes
|
||||
"The fortune cookie said yes. *clucks in agreement*", // yes
|
||||
"Sorry, the fortune cookie over there said no. *clucks in disagreement*", // no
|
||||
"I'll have to consult my sources... *flips corn*... no.", // no
|
||||
"I'll have to consult the magic 8-cluck... *shakes*... no.", // no
|
||||
"I'm not sure to be honest, let's ask your chicken friend. Oh wait...", // no
|
||||
"This question floated over my head, I'll pass. *clucks dismissively*" // no
|
||||
];
|
||||
|
||||
const CHAOTIC_RESPONSES: [&str; 90] = [
|
||||
"Oops! The Magic 8-Ball shattered upon hearing your question. Coincidence?", // no
|
||||
"Reply hazy. Ask Google’s evil twin, Froogle.", // no
|
||||
"Meh — Consult the ancient texts of Netflix subtitles.", // no
|
||||
"I don't know, but your cat probably does.", // no
|
||||
"Yes, but only if you wear a clown wig.", // yes
|
||||
"No. Unless the moon winks at you first.", // no
|
||||
"It is decidedly a resounding honk-honk!", // yes
|
||||
"Signs point to... maybe... or not... or wait... oh look, a squirrel!", // no
|
||||
"Signs point to... ~~yes~~ pancakes. Definitely pancakes.", // no
|
||||
"Why do you want to know? It’s obviously a yes — trust the donut prophecy.", // yes
|
||||
"Outlook not so good. Blame Mercury retrograde or your Wi-Fi.", // no
|
||||
"Outlook hazy. Consult the nearest fortune-telling hamster.", // no
|
||||
"What are you, a toaster in disguise?", // no
|
||||
"How the heck do you not know this? Ask a sock puppet!", // no
|
||||
"Really? Making life choices based on a magic ball? Bold move, friend.", // no
|
||||
"Try asking later... when I’m less busy binge-watching.", // no
|
||||
"I don't know, summon a raven and whisper your question into the void.", // no
|
||||
"The answer is yes, as foretold by the mystical spaghetti.", // yes
|
||||
"Yes, actually no. Wait, yes? Let’s go with potato.", // no
|
||||
"Maybeee... if the stars align and your pizza has extra cheese.", // yes
|
||||
"Definitely! Unless gravity stops working.", // yes
|
||||
"It is decidedly so. So what? Buy a llama and see what happens.", // yes
|
||||
"My reply is no, and also banana pudding.", // no
|
||||
"My sources confirm that the answer is no.\nSource: A suspicious pigeon.", // no
|
||||
"As I see it, yes. As the chicken sees it, no. Trust who you like.", // yes
|
||||
"Don't count on it. Count on marshmallows instead.", // no
|
||||
"Whoa! Why do I have to answer this? Ask a rubber duck.", // no
|
||||
"Highly unlikely. Unless it’s Tuesday on Mars.", // no
|
||||
"Sure, but with extreme caution and a tinfoil hat.", // yes
|
||||
"What kind of silly question is that?? No! Also, here’s a kazoo.", // no
|
||||
"Try asking this to a chicken. They’re the true oracles.", // no
|
||||
"Not in a million years! Unless the earth is made of cheese.", // no
|
||||
"As a matter of fact, yes. And it’s raining tacos.", // yes
|
||||
"It's a no, but the raccoons might know better.", // no
|
||||
"In the end, it’s not a bad choice. Or is it? Mwahaha.", // yes
|
||||
"Nope, not today. Try tomorrow after coffee.", // no
|
||||
"Cross your fingers! Or better yet, cross the streams.", // yes
|
||||
"Nope. *shakes head like a very judgmental parrot*", // no
|
||||
"The fortune cookie said yes, but it was written in crayon.", // yes
|
||||
"Sorry, the fortune cookie over there said no. Blame it.", // no
|
||||
"Sorry, not happening. But you get a virtual sticker for trying!", // no
|
||||
"I'll have to consult my sources... *flips a pancake*... no.", // no
|
||||
"I'll have to consult the magic 8-ball... *shakes it violently*... still no.", // no
|
||||
"I'm not sure, but your imaginary friend says yes.", // yes
|
||||
"This question flew over my head, so I’ll just say 'llama'.", // no
|
||||
"The answer is yes, but only if you do it while wearing socks on your hands.", // yes
|
||||
"No, and I think you broke the space-time continuum by asking.", // no
|
||||
"Why not? What’s the worst that could happen? Oh wait...", // no
|
||||
"The stars say yes, but the planets are still debating.", // yes
|
||||
"The universe just facepalmed at your question.", // no
|
||||
"Ask again while juggling flaming pineapples for a clearer answer.", // no
|
||||
"Nope, not unless you bribe me with tacos.", // no
|
||||
"I consulted the oracle... she’s out to lunch. Try later.", // no
|
||||
"Yes, but only if you can lick your elbow right now.", // yes
|
||||
"No, because I said so and I’m very wise. Also, I’m a plastic ball.", // no
|
||||
"Yes. No. Wait, I’ve lost track. Did you hear that noise?", // no
|
||||
"Absolutely, as long as you bring me a rubber chicken as tribute.", // yes
|
||||
"I asked a wizard, and they just laughed hysterically.", // no
|
||||
"The spirits say no, but the ghosts are nodding yes.", // no
|
||||
"Yes, if you believe in unicorns and the power of friendship.", // yes
|
||||
"No, and also you might want to move. Something’s behind you.", // no
|
||||
"Ask again, but this time with interpretive dance.", // no
|
||||
"Definitely! Unless the moon turns into cheese. Then no.", // yes
|
||||
"I see... wait, no, I don’t see. My crystal ball is buffering.", // no
|
||||
"Sure! But only after a karaoke duet with a raccoon.", // yes
|
||||
"Yes, but only if you promise not to tell the ducks.", // yes
|
||||
"No way, unless you can recite the alphabet backwards in one breath.", // no
|
||||
"Ask the magic mushroom. It’s way more in touch with reality than I am.", // no
|
||||
"No, because gravity disagrees with your premise.", // no
|
||||
"Yes, but first you must complete the sacred quest for nachos.", // yes
|
||||
"The answer is hidden in the folds of your laundry. Go check.", // no
|
||||
"I would answer, but I’m legally obligated to stay mysterious.", // no
|
||||
"Absolutely! If you can solve this riddle: What walks on four legs in the morning, two legs at noon, and... oh wait, wrong universe.", // yes
|
||||
"The council of frogs says yes, but only if you croak like one.", // yes
|
||||
"No, but only because the Magic 8-Ball union forbids it.", // no
|
||||
"Yes, if the dog wags its tail twice before the clock strikes midnight.", // yes
|
||||
"Try again after doing three cartwheels and making a wish.", // no
|
||||
"The ducks in my dreams say no. They’re rarely wrong.", // no
|
||||
"Not today, Satan. Not today.", // no
|
||||
"Yes, but only on Wednesdays during a full moon.", // yes
|
||||
"No, because bananas don’t grow in winter.", // no
|
||||
"The answer is locked in a time capsule. Check back in 50 years.", // no
|
||||
"I don’t know, but it smells like trouble.", // no
|
||||
"Why not? The penguins approve, and that’s good enough for me.", // yes
|
||||
"Sure, but only if you say 'bubblegum' ten times fast.", // yes
|
||||
"No, unless you can outsmart a sentient toaster.", // no
|
||||
"The answer is yes, but it comes with a plot twist.", // yes
|
||||
"Flip a coin, spin three times, and consult your nearest cactus. Good luck!", // no
|
||||
"Only on the condition that you buy me a donut.", // yes
|
||||
"Yes, but proceed at your own risk. The llamas are watching." // yes
|
||||
];
|
||||
|
||||
fn get_random_response() -> &'static str { RESPONSES[random::<usize>() % RESPONSES.len()] }
|
||||
|
||||
fn get_random_chicken_response() -> &'static str { CHICKEN_RESPONSES[random::<usize>() % CHICKEN_RESPONSES.len()] }
|
||||
|
||||
fn get_random_chaotic_response() -> &'static str { CHAOTIC_RESPONSES[random::<usize>() % CHAOTIC_RESPONSES.len()] }
|
@ -1,7 +1,9 @@
|
||||
use serde::Deserialize;
|
||||
use rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult
|
||||
use {
|
||||
rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult
|
||||
},
|
||||
serde::Deserialize
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -20,16 +22,14 @@ struct Summary {
|
||||
}
|
||||
|
||||
/// Check latency between bot and WebSocket as well as Discord's API latency
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
install_context = "Guild|User",
|
||||
interaction_context = "Guild|BotDm|PrivateChannel"
|
||||
)]
|
||||
#[poise::command(slash_command, install_context = "Guild|User", interaction_context = "Guild|BotDm|PrivateChannel")]
|
||||
pub async fn ping(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||
let statuspage: StatusPage = reqwest::get("https://discordstatus.com/metrics-display/5k2rt9f7pmny/day.json")
|
||||
.await.unwrap()
|
||||
.json()
|
||||
.await.unwrap();
|
||||
.await
|
||||
.unwrap()
|
||||
.json()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut latencies = Vec::new();
|
||||
latencies.push(format!("Discord: `{:.0?}ms`", statuspage.metrics[0].summary.mean));
|
@ -1,28 +1,31 @@
|
||||
use sysinfo::System;
|
||||
use uptime_lib::get;
|
||||
use std::{
|
||||
env::var,
|
||||
fs::File,
|
||||
path::Path,
|
||||
time::{
|
||||
Duration,
|
||||
SystemTime,
|
||||
UNIX_EPOCH
|
||||
use {
|
||||
rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult,
|
||||
config::BINARY_PROPERTIES,
|
||||
utils::{
|
||||
BOT_VERSION,
|
||||
GIT_COMMIT_BRANCH,
|
||||
GIT_COMMIT_HASH,
|
||||
format_duration
|
||||
}
|
||||
},
|
||||
io::{
|
||||
BufRead,
|
||||
BufReader
|
||||
}
|
||||
};
|
||||
use rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult,
|
||||
utils::{
|
||||
BOT_VERSION,
|
||||
GIT_COMMIT_HASH,
|
||||
GIT_COMMIT_BRANCH,
|
||||
format_duration
|
||||
}
|
||||
std::{
|
||||
env::var,
|
||||
fs::File,
|
||||
io::{
|
||||
BufRead,
|
||||
BufReader
|
||||
},
|
||||
path::Path,
|
||||
time::{
|
||||
Duration,
|
||||
SystemTime,
|
||||
UNIX_EPOCH
|
||||
}
|
||||
},
|
||||
sysinfo::System,
|
||||
uptime_lib::get
|
||||
};
|
||||
|
||||
fn get_os_info() -> String {
|
||||
@ -33,13 +36,11 @@ fn get_os_info() -> String {
|
||||
if let Ok(file) = File::open(path) {
|
||||
let reader = BufReader::new(file);
|
||||
let set_value = |s: String| s.split('=').nth(1).unwrap_or_default().trim_matches('"').to_string();
|
||||
reader.lines().map_while(Result::ok).for_each(|line| {
|
||||
match line {
|
||||
l if l.starts_with("NAME=") => name = set_value(l),
|
||||
l if l.starts_with("VERSION=") => version = set_value(l),
|
||||
l if l.starts_with("VERSION_ID=") => version = set_value(l),
|
||||
_ => {}
|
||||
}
|
||||
reader.lines().map_while(Result::ok).for_each(|line| match line {
|
||||
l if l.starts_with("NAME=") => name = set_value(l),
|
||||
l if l.starts_with("VERSION=") => version = set_value(l),
|
||||
l if l.starts_with("VERSION_ID=") => version = set_value(l),
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
@ -95,16 +96,21 @@ pub async fn uptime(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||
}
|
||||
|
||||
// Fetch the node hostname from envvar
|
||||
let docker_node = match var("DOCKER_HOSTNAME") {
|
||||
Ok(h) => h.to_string(),
|
||||
Err(_) => "DOCKER_HOSTNAME is empty!".to_string()
|
||||
let node_hostname = if BINARY_PROPERTIES.env.contains("prod") {
|
||||
match var("DOCKER_HOSTNAME") {
|
||||
Ok(h) => h.to_string(),
|
||||
Err(_) => "DOCKER_HOSTNAME is empty!".to_string()
|
||||
}
|
||||
} else {
|
||||
let hostname = std::process::Command::new("hostname").output().unwrap().stdout;
|
||||
String::from_utf8(hostname).unwrap().trim().to_string()
|
||||
};
|
||||
|
||||
let stat_msg = [
|
||||
format!("**{} v{}** `{GIT_COMMIT_HASH}:{GIT_COMMIT_BRANCH}`", bot.name, *BOT_VERSION),
|
||||
format!(">>> System: `{}`", format_duration(sys_uptime)),
|
||||
format!("Process: `{}`", format_duration(proc_uptime)),
|
||||
format!("Node: `{docker_node}`"),
|
||||
format!("Node: `{node_hostname}`"),
|
||||
format!("CPU: `{}`", cpu[0].brand()),
|
||||
format!("RAM: `{pram}` (`{sram}/{sram_total}`)"),
|
||||
format!("OS: `{}`", get_os_info())
|
2
cmds/src/lib.rs
Normal file
2
cmds/src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
mod dispatch;
|
||||
pub use dispatch::*;
|
@ -4,8 +4,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rustbot_lib = { path = "../library" }
|
||||
poise = { workspace = true }
|
||||
rustbot_lib = { workspace = true }
|
||||
|
||||
[features]
|
||||
production = ["rustbot_lib/production"]
|
||||
|
@ -1,10 +1,12 @@
|
||||
mod ready;
|
||||
mod shards;
|
||||
|
||||
use poise::serenity_prelude::FullEvent;
|
||||
use rustbot_lib::{
|
||||
RustbotFwCtx,
|
||||
RustbotResult
|
||||
use {
|
||||
poise::serenity_prelude::FullEvent,
|
||||
rustbot_lib::{
|
||||
RustbotFwCtx,
|
||||
RustbotResult
|
||||
}
|
||||
};
|
||||
|
||||
pub const RUSTBOT_EVENT: &str = "RustbotEvent";
|
||||
|
@ -3,26 +3,28 @@ use super::{
|
||||
RUSTBOT_EVENT
|
||||
};
|
||||
|
||||
use rustbot_lib::{
|
||||
RustbotFwCtx,
|
||||
RustbotResult,
|
||||
utils::{
|
||||
BOT_VERSION,
|
||||
GIT_COMMIT_HASH,
|
||||
GIT_COMMIT_BRANCH
|
||||
use {
|
||||
poise::serenity_prelude::{
|
||||
ChannelId,
|
||||
CreateEmbed,
|
||||
CreateEmbedAuthor,
|
||||
CreateMessage,
|
||||
Ready
|
||||
},
|
||||
config::BINARY_PROPERTIES
|
||||
};
|
||||
use std::sync::atomic::{
|
||||
AtomicBool,
|
||||
Ordering::Relaxed
|
||||
};
|
||||
use poise::serenity_prelude::{
|
||||
Ready,
|
||||
ChannelId,
|
||||
CreateMessage,
|
||||
CreateEmbed,
|
||||
CreateEmbedAuthor
|
||||
rustbot_lib::{
|
||||
config::BINARY_PROPERTIES,
|
||||
utils::{
|
||||
BOT_VERSION,
|
||||
GIT_COMMIT_BRANCH,
|
||||
GIT_COMMIT_HASH
|
||||
},
|
||||
RustbotFwCtx,
|
||||
RustbotResult
|
||||
},
|
||||
std::sync::atomic::{
|
||||
AtomicBool,
|
||||
Ordering::Relaxed
|
||||
}
|
||||
};
|
||||
|
||||
static READY_ONCE: AtomicBool = AtomicBool::new(false);
|
||||
@ -33,14 +35,26 @@ async fn ready_once(
|
||||
) -> RustbotResult<()> {
|
||||
#[cfg(not(feature = "production"))]
|
||||
{
|
||||
println!("{RUSTBOT_EVENT}[Ready:Notice:S{}]: Detected a non-production environment!", framework.serenity_context.shard_id);
|
||||
println!(
|
||||
"{RUSTBOT_EVENT}[Ready:Notice:S{}]: Detected a non-production environment!",
|
||||
framework.serenity_context.shard_id
|
||||
);
|
||||
let gateway = framework.serenity_context.http.get_bot_gateway().await?;
|
||||
let session = gateway.session_start_limit;
|
||||
println!("{RUSTBOT_EVENT}[Ready:Notice:S{}]: Session limit: {}/{}", framework.serenity_context.shard_id, session.remaining, session.total);
|
||||
println!(
|
||||
"{RUSTBOT_EVENT}[Ready:Notice:S{}]: Session limit: {}/{}",
|
||||
framework.serenity_context.shard_id, session.remaining, session.total
|
||||
);
|
||||
}
|
||||
|
||||
println!("{RUSTBOT_EVENT}[Ready:S{}]: Build version: {} ({}:{})", framework.serenity_context.shard_id, *BOT_VERSION, GIT_COMMIT_HASH, GIT_COMMIT_BRANCH);
|
||||
println!("{RUSTBOT_EVENT}[Ready:S{}]: Connected to API as {}", framework.serenity_context.shard_id, ready.user.name);
|
||||
println!(
|
||||
"{RUSTBOT_EVENT}[Ready:S{}]: Build version: {} ({GIT_COMMIT_HASH}:{GIT_COMMIT_BRANCH})",
|
||||
framework.serenity_context.shard_id, *BOT_VERSION
|
||||
);
|
||||
println!(
|
||||
"{RUSTBOT_EVENT}[Ready:S{}]: Connected to API as {}",
|
||||
framework.serenity_context.shard_id, ready.user.name
|
||||
);
|
||||
|
||||
let message = CreateMessage::new();
|
||||
let ready_embed = CreateEmbed::new()
|
||||
@ -48,7 +62,9 @@ async fn ready_once(
|
||||
.thumbnail(ready.user.avatar_url().unwrap_or_default())
|
||||
.author(CreateEmbedAuthor::new(format!("{} is ready!", ready.user.name)));
|
||||
|
||||
ChannelId::new(BINARY_PROPERTIES.rustbot_logs).send_message(&framework.serenity_context.http, message.add_embed(ready_embed)).await?;
|
||||
ChannelId::new(BINARY_PROPERTIES.rustbot_logs)
|
||||
.send_message(&framework.serenity_context.http, message.add_embed(ready_embed))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -59,7 +75,9 @@ impl EventProcessor<'_> {
|
||||
data_about_bot: &Ready
|
||||
) -> RustbotResult<()> {
|
||||
if !READY_ONCE.swap(true, Relaxed) {
|
||||
ready_once(data_about_bot, self.framework).await.expect("Failed to call ready_once method");
|
||||
ready_once(data_about_bot, self.framework)
|
||||
.await
|
||||
.expect("Failed to call ready_once method");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -3,16 +3,22 @@ use super::{
|
||||
RUSTBOT_EVENT
|
||||
};
|
||||
|
||||
use std::num::NonZero;
|
||||
use rustbot_lib::RustbotResult;
|
||||
use poise::serenity_prelude::ShardStageUpdateEvent;
|
||||
use {
|
||||
poise::serenity_prelude::ShardStageUpdateEvent,
|
||||
rustbot_lib::RustbotResult,
|
||||
std::num::NonZero
|
||||
};
|
||||
|
||||
impl EventProcessor<'_> {
|
||||
pub async fn on_shards_ready(
|
||||
&self,
|
||||
total_shards: &NonZero<u16>
|
||||
) -> RustbotResult<()> {
|
||||
let shards = if *total_shards == NonZero::new(1).unwrap() { "shard is" } else { "shards are" };
|
||||
let shards = if *total_shards == NonZero::new(1).unwrap() {
|
||||
"shard is"
|
||||
} else {
|
||||
"shards are"
|
||||
};
|
||||
println!("{RUSTBOT_EVENT}[ShardsReady]: {total_shards} {shards} ready!");
|
||||
|
||||
Ok(())
|
||||
|
@ -1,23 +1,23 @@
|
||||
use crate::RUSTBOT_SCHEDULER;
|
||||
|
||||
use tokio::{
|
||||
task,
|
||||
time::{
|
||||
interval,
|
||||
Duration
|
||||
use {
|
||||
std::{
|
||||
future::Future,
|
||||
sync::Arc
|
||||
},
|
||||
tokio::{
|
||||
task,
|
||||
time::{
|
||||
interval,
|
||||
Duration
|
||||
}
|
||||
}
|
||||
};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
future::Future
|
||||
};
|
||||
|
||||
pub struct Scheduler;
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self)
|
||||
}
|
||||
pub fn new() -> Arc<Self> { Arc::new(Self) }
|
||||
|
||||
pub async fn spawn_job<F, E>(
|
||||
&self,
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustbot_lib"
|
||||
version = "0.1.19"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -23,15 +23,4 @@ fn main() {
|
||||
println!("cargo:rustc-env=GIT_COMMIT_BRANCH=not_found");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let hostname = std::process::Command::new("hostname")
|
||||
.output()
|
||||
.expect("Command execution failed: hostname");
|
||||
|
||||
if hostname.status.success() {
|
||||
let hostname = String::from_utf8(hostname.stdout).expect("Invalid UTF-8 sequence").trim().to_string();
|
||||
println!("cargo:rustc-env=DOCKER_HOSTNAME={}", &hostname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,45 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub struct ConfigMeta {
|
||||
pub env: &'static str,
|
||||
pub embed_color: u32,
|
||||
pub env: &'static str,
|
||||
pub embed_color: u32,
|
||||
pub rustbot_logs: u64,
|
||||
pub developers: Vec<u64>
|
||||
pub developers: Vec<u64>
|
||||
}
|
||||
|
||||
#[cfg(feature = "production")]
|
||||
pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(ConfigMeta::new);
|
||||
|
||||
#[cfg(not(feature = "production"))]
|
||||
pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(||
|
||||
ConfigMeta::new()
|
||||
.env("dev")
|
||||
.embed_color(0xf1d63c)
|
||||
);
|
||||
pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(|| ConfigMeta::new().env("dev").embed_color(0xF1D63C));
|
||||
|
||||
impl ConfigMeta {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
env: "prod",
|
||||
embed_color: 0xf1d63c,
|
||||
env: "prod",
|
||||
embed_color: 0xF1D63C,
|
||||
rustbot_logs: 1311282815601741844,
|
||||
developers: vec![
|
||||
190407856527376384 // toast.ts
|
||||
developers: vec![
|
||||
190407856527376384, // toast.ts
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Scalable functions below;
|
||||
#[cfg(not(feature = "production"))]
|
||||
fn env(mut self, env: &'static str) -> Self {
|
||||
fn env(
|
||||
mut self,
|
||||
env: &'static str
|
||||
) -> Self {
|
||||
self.env = env;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "production"))]
|
||||
fn embed_color(mut self, color: u32) -> Self {
|
||||
fn embed_color(
|
||||
mut self,
|
||||
color: u32
|
||||
) -> Self {
|
||||
self.embed_color = color;
|
||||
self
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use poise::serenity_prelude::UserId;
|
||||
use cargo_toml::Manifest;
|
||||
use std::sync::LazyLock;
|
||||
use {
|
||||
cargo_toml::Manifest,
|
||||
poise::serenity_prelude::UserId,
|
||||
std::sync::LazyLock
|
||||
};
|
||||
|
||||
#[cfg(feature = "production")]
|
||||
pub static GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH");
|
||||
@ -17,9 +19,7 @@ pub static BOT_VERSION: LazyLock<String> = LazyLock::new(|| {
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
pub fn format_timestamp(timestamp: i64) -> String {
|
||||
format!("<t:{timestamp}>\n<t:{timestamp}:R>")
|
||||
}
|
||||
pub fn format_timestamp(timestamp: i64) -> String { format!("<t:{timestamp}>\n<t:{timestamp}:R>") }
|
||||
|
||||
pub fn mention_dev(ctx: super::RustbotContext<'_>) -> Option<String> {
|
||||
let devs = super::config::BINARY_PROPERTIES.developers.clone();
|
||||
@ -53,18 +53,13 @@ pub fn format_duration(secs: u64) -> String {
|
||||
let minutes = (secs % 3600) / 60;
|
||||
let seconds = secs % 60;
|
||||
|
||||
let components = [
|
||||
(days, "d"),
|
||||
(hours, "h"),
|
||||
(minutes, "m"),
|
||||
(seconds, "s"),
|
||||
];
|
||||
let components = [(days, "d"), (hours, "h"), (minutes, "m"), (seconds, "s")];
|
||||
|
||||
let formatted_string: Vec<String> = components
|
||||
.iter()
|
||||
.filter(|&&(value, _)| value > 0)
|
||||
.map(|&(value, suffix)| format!("{value}{suffix}"))
|
||||
.collect();
|
||||
.iter()
|
||||
.filter(|&&(value, _)| value > 0)
|
||||
.map(|&(value, suffix)| format!("{value}{suffix}"))
|
||||
.collect();
|
||||
|
||||
formatted_string.join(", ")
|
||||
}
|
||||
|
4
run.sh
4
run.sh
@ -1,6 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
export DOCKER_HOSTNAME=$(hostname)
|
||||
export $(cat .env.bot | xargs)
|
||||
clear && cargo run
|
||||
unset DOCKER_HOSTNAME
|
||||
clear && cargo fmt && cargo run
|
||||
|
2
rust-toolchain
Normal file
2
rust-toolchain
Normal file
@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
20
rustfmt.toml
Normal file
20
rustfmt.toml
Normal file
@ -0,0 +1,20 @@
|
||||
edition = "2024"
|
||||
hex_literal_case = "Upper"
|
||||
binop_separator = "Front"
|
||||
brace_style = "SameLineWhere"
|
||||
fn_params_layout = "Vertical"
|
||||
imports_layout = "Vertical"
|
||||
imports_granularity = "One"
|
||||
fn_single_line = true
|
||||
format_strings = true
|
||||
max_width = 150
|
||||
tab_spaces = 2
|
||||
hard_tabs = false
|
||||
trailing_comma = "Never"
|
||||
match_block_trailing_comma = true
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
reorder_impl_items = true
|
||||
trailing_semicolon = false
|
||||
struct_field_align_threshold = 20
|
||||
condense_wildcard_suffixes = true
|
@ -1,26 +0,0 @@
|
||||
mod dev;
|
||||
mod eightball;
|
||||
mod ping;
|
||||
mod uptime;
|
||||
|
||||
pub use dev::dev;
|
||||
pub use eightball::eightball;
|
||||
pub use ping::ping;
|
||||
pub use uptime::uptime;
|
||||
|
||||
macro_rules! collect {
|
||||
() => {
|
||||
vec![
|
||||
// Developer command(s)
|
||||
commands::dev(),
|
||||
|
||||
// Utility commands
|
||||
commands::ping(),
|
||||
commands::uptime(),
|
||||
|
||||
// Unsorted mess
|
||||
commands::eightball(),
|
||||
]
|
||||
};
|
||||
}
|
||||
pub(crate) use collect;
|
@ -1,180 +0,0 @@
|
||||
use rustbot_lib::{
|
||||
RustbotContext,
|
||||
RustbotResult,
|
||||
config::BINARY_PROPERTIES
|
||||
};
|
||||
use poise::{
|
||||
serenity_prelude::UserId,
|
||||
builtins::paginate
|
||||
};
|
||||
|
||||
#[derive(poise::ChoiceParameter)]
|
||||
enum ResponseMode {
|
||||
Normal,
|
||||
Chicken
|
||||
}
|
||||
|
||||
/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
install_context = "Guild|User",
|
||||
interaction_context = "Guild|BotDm|PrivateChannel",
|
||||
rename = "8ball"
|
||||
)]
|
||||
pub async fn eightball(
|
||||
ctx: RustbotContext<'_>,
|
||||
#[description = "Your yes/no question"] question: String,
|
||||
#[description = "Response modes"] mode: Option<ResponseMode>
|
||||
) -> RustbotResult<()> {
|
||||
if question.to_ascii_lowercase().contains("niko, show list") {
|
||||
if ctx.author().id == UserId::new(BINARY_PROPERTIES.developers[0]) {
|
||||
let chunks: Vec<String> = RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect();
|
||||
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
|
||||
paginate(ctx, &pages).await?;
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
ctx.reply("No.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if question.to_ascii_lowercase().contains("niko, show chicken list") {
|
||||
if ctx.author().id == UserId::new(BINARY_PROPERTIES.developers[0]) {
|
||||
let chunks: Vec<String> = CHICKEN_RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect();
|
||||
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
|
||||
paginate(ctx, &pages).await?;
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
ctx.reply("No.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let rand_resp = match mode {
|
||||
Some(ResponseMode::Chicken) => get_random_chicken_response(),
|
||||
_ => get_random_response()
|
||||
};
|
||||
|
||||
ctx.reply(format!("> {question}\n{rand_resp}")).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const RESPONSES: [&str; 45] = [
|
||||
"Reply hazy. Look it up on Google.", // no
|
||||
"Meh — Figure it out yourself.", // no
|
||||
"I don't know, what do you think?", // no
|
||||
"Yes.", // yes
|
||||
"No.", // no
|
||||
"It is decidedly so", // yes
|
||||
"Signs point to... maybe... depends on... \
|
||||
hold on, let me get my glasses, this is getting \
|
||||
pretty tiny... depends on whether you'd be up \
|
||||
to getting to know your Magic 8-Ball a little better.", // no
|
||||
"Signs point to... ~~yes~~ no.", // no
|
||||
"Why do you want to know the answer? It's obviously a yes.", // yes
|
||||
"Outlook not so good.", // no
|
||||
"Outlook hazy.", // no
|
||||
"What are you, stupid?", // no
|
||||
"How the hell do you not know that?", // no
|
||||
"Really? Making a decision based on what the plastic 8-Ball says? Jesus...", // no
|
||||
"Try asking later...", // no
|
||||
"I don't know, whip out the ouija board and try again?", // no
|
||||
"The answer is yes.", // yes
|
||||
"Yes, actually no. Wait, nevermind.", // no
|
||||
"Maybeee...", // yes
|
||||
"Definitely!", // yes
|
||||
"It is decidedly so.", // yes
|
||||
"My reply is no.", // no
|
||||
"My sources confirms that the answer is no.\n\
|
||||
Source: :sparkles: *i made it up* :sparkles:", // no
|
||||
"As I see it, yes.", // yes
|
||||
"Don't count on it.", // no
|
||||
"Whoa! Why do I have to answer this?", // no
|
||||
"Highly unlikely.", // no
|
||||
"Sure, but with extreme cautions.", // yes
|
||||
"What kind of stupid question is that?? No! I'm not answering that!", // no
|
||||
"Try asking this to a chicken. Probably knows it better than I do!", // no
|
||||
"Not in a million years!", // no
|
||||
"As a matter of fact, yes.", // yes
|
||||
"It's a no, better go ask someone else.", // no
|
||||
"In the end, it's not a bad choice.", // yes
|
||||
"Nope, not today.", // no
|
||||
"Cross your fingers, the answer is yes!", // yes
|
||||
"Nope. *shakes head*", // no
|
||||
"The fortune cookie said yes.", // yes
|
||||
"Sorry, the fortune cookie over there said no.", // no
|
||||
"Sorry, not happening.", // no
|
||||
"I'll have to consult my sources... *flips coin*... no.", // no
|
||||
"I'll have to consult the magic 8-ball... *shakes*... no.", // no
|
||||
"I'm not sure to be honest, let's ask your friend. Oh wait...", // no
|
||||
"This question flew over my head, I'll pass.", // no
|
||||
"Oops, the Magic 8-Ball shattered itself when you asked that! I'll take that as a no.", // no
|
||||
];
|
||||
|
||||
const CHICKEN_RESPONSES: [&str; 54] = [
|
||||
"Cluck cluck... Reply hazy, try pecking Google.", // no
|
||||
"Meh... Figure it out yourself, or scratch around a bit.", // no
|
||||
"I don't know... what do you think? *pecks at ground*", // no
|
||||
"BAWK! YES!", // yes
|
||||
"Cluck... no.", // no
|
||||
"It is decidedly so! *flaps wings*", // yes
|
||||
"Signs point to... maybe... hold on, let me fluff my feathers... depends on whether you'd get to know your Magic Chicken a bit better.", // no
|
||||
"Signs point to... ~~yes~~ cluck no.", // no
|
||||
"Why do you want to know? It's a big cluckin' yes!", // yes
|
||||
"Outlook not so clucking good.", // no
|
||||
"Outlook cluckin' hazy.", // no
|
||||
"What are you, a lost chick? Cluck!", // no
|
||||
"How the cluck do you not know that?", // no
|
||||
"Really? Asking a chicken to decide your fate? *clucks judgmentally*", // no
|
||||
"Peck back later, I'm nesting...", // no
|
||||
"I don't know, try flapping your wings and ask again?", // no
|
||||
"The answer is a big ol' yes! *flaps happily*", // yes
|
||||
"Yes... wait, actually... no. Cluck, I'm confused.", // no
|
||||
"Maaaaybe... *chicken waddle*?", // yes
|
||||
"Definitely! *struts confidently*", // yes
|
||||
"It is decidedly so. *struts with pride*", // yes
|
||||
"My reply is a solid *cluck* no.", // no
|
||||
"My sources confirm it's a cluckin' no.\nSource: 🐔 *I made it up* 🐔", // no
|
||||
"As I see it, yes! *pecks approvingly*", // yes
|
||||
"Don't count on it. *cluck cluck*", // no
|
||||
"Whoa, why do I have to answer this? *fluffs feathers*", // no
|
||||
"Highly unlikely. *chicken stare*", // no
|
||||
"Sure, but with extreme cluckin' caution.", // yes
|
||||
"What kind of stupid question is that?? No! *angry clucks*", // no
|
||||
"Try asking this to a fellow chicken. They probably know better than I do!", // no
|
||||
"Cluck yes! *does a happy chicken dance*", // yes
|
||||
"No way, not even for a big bag of feed.", // no
|
||||
"Yes! *lays egg of approval*", // yes
|
||||
"It's a no, better go scratch somewhere else.", // no
|
||||
"Cluck-tastic! That's a definite yes.", // yes
|
||||
"Cluck yeah! *struts proudly*", // yes
|
||||
"Nope, not today. *shakes head*", // no
|
||||
"Feathers crossed, the answer is yes!", // yes
|
||||
"Chicken says nope. *tilts head*", // no
|
||||
"Absolutely! *clucks happily*", // yes
|
||||
"Not a chance. *fluffs feathers*", // no
|
||||
"Eggcellent choice! Yes!", // yes
|
||||
"Not in a million clucks!", // no
|
||||
"As a matter of cluck, yes! *clucks approvingly*", // yes
|
||||
"It's a nopity nope, better go ask another chicken.", // no
|
||||
"In the end, it's not a bad cluck", // yes
|
||||
"Nope, not today. *clucks sadly*", // no
|
||||
"Cross your feathers, the answer is yes!", // yes
|
||||
"The fortune cookie said yes. *clucks in agreement*", // yes
|
||||
"Sorry, the fortune cookie over there said no. *clucks in disagreement*", // no
|
||||
"I'll have to consult my sources... *flips corn*... no.", // no
|
||||
"I'll have to consult the magic 8-cluck... *shakes*... no.", // no
|
||||
"I'm not sure to be honest, let's ask your chicken friend. Oh wait...", // no
|
||||
"This question floated over my head, I'll pass. *clucks dismissively*", // no
|
||||
];
|
||||
|
||||
fn get_random_response() -> &'static str {
|
||||
RESPONSES[rand::random::<usize>() % RESPONSES.len()]
|
||||
}
|
||||
|
||||
fn get_random_chicken_response() -> &'static str {
|
||||
CHICKEN_RESPONSES[rand::random::<usize>() % CHICKEN_RESPONSES.len()]
|
||||
}
|
195
src/main.rs
195
src/main.rs
@ -1,27 +1,29 @@
|
||||
mod commands;
|
||||
mod shutdown;
|
||||
// https://cdn.toast-server.net/RustFSHiearchy.png
|
||||
// Using the new filesystem hierarchy
|
||||
|
||||
use rustbot_tokens::discord_token;
|
||||
use poise::serenity_prelude::{
|
||||
builder::CreateAllowedMentions,
|
||||
ClientBuilder,
|
||||
ActivityData,
|
||||
GatewayIntents
|
||||
};
|
||||
use rustbot_lib::{
|
||||
utils::{
|
||||
mention_dev,
|
||||
get_guild_name
|
||||
use {
|
||||
poise::serenity_prelude::{
|
||||
builder::CreateAllowedMentions,
|
||||
ActivityData,
|
||||
ClientBuilder,
|
||||
GatewayIntents
|
||||
},
|
||||
RustbotData,
|
||||
config::BINARY_PROPERTIES
|
||||
};
|
||||
use rustbot_events::events::processor;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
borrow::Cow
|
||||
rustbot_cmds::collect,
|
||||
rustbot_events::events::processor,
|
||||
rustbot_lib::{
|
||||
config::BINARY_PROPERTIES,
|
||||
utils::{
|
||||
get_guild_name,
|
||||
mention_dev
|
||||
},
|
||||
RustbotData
|
||||
},
|
||||
rustbot_tokens::discord_token,
|
||||
std::{
|
||||
borrow::Cow,
|
||||
sync::Arc
|
||||
}
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
@ -32,28 +34,29 @@ async fn main() {
|
||||
Some(Cow::Borrowed("pg!"))
|
||||
};
|
||||
|
||||
let commands = commands::collect!();
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands,
|
||||
pre_command: |ctx| Box::pin(async move {
|
||||
let get_guild_channel_name = match ctx.guild_channel().await {
|
||||
Some(channel) => format!("in #{}", channel.name.clone()),
|
||||
None => String::from("")
|
||||
};
|
||||
let prefix = match ctx.command().prefix_action {
|
||||
Some(_) => ctx.framework().options.prefix_options.prefix.as_ref().unwrap(),
|
||||
None => "/"
|
||||
};
|
||||
commands: collect!(),
|
||||
pre_command: |ctx| {
|
||||
Box::pin(async move {
|
||||
let get_guild_channel_name = match ctx.guild_channel().await {
|
||||
Some(channel) => format!("in #{}", channel.name.clone()),
|
||||
None => String::from("")
|
||||
};
|
||||
let prefix = match ctx.command().prefix_action {
|
||||
Some(_) => ctx.framework().options.prefix_options.prefix.as_ref().unwrap(),
|
||||
None => "/"
|
||||
};
|
||||
|
||||
println!(
|
||||
"Discord[{}:S{}]: {} ran {prefix}{} {get_guild_channel_name}",
|
||||
get_guild_name(ctx),
|
||||
ctx.serenity_context().shard_id,
|
||||
ctx.author().name,
|
||||
ctx.command().qualified_name,
|
||||
);
|
||||
}),
|
||||
println!(
|
||||
"Discord[{}:S{}]: {} ran {prefix}{} {get_guild_channel_name}",
|
||||
get_guild_name(ctx),
|
||||
ctx.serenity_context().shard_id,
|
||||
ctx.author().name,
|
||||
ctx.command().qualified_name,
|
||||
);
|
||||
})
|
||||
},
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix,
|
||||
ignore_bots: true,
|
||||
@ -62,52 +65,69 @@ async fn main() {
|
||||
execute_self_messages: false,
|
||||
..Default::default()
|
||||
},
|
||||
on_error: |error| Box::pin(async move {
|
||||
match error {
|
||||
poise::FrameworkError::Command { error, ctx, .. } => {
|
||||
println!("PoiseCommandError({}): {}", ctx.command().qualified_name, error);
|
||||
ctx.reply(format!(
|
||||
"Encountered an error during command execution, ask {} to check console for more details!",
|
||||
mention_dev(ctx).unwrap_or_default()
|
||||
)).await.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::EventHandler { error, event, .. } => println!("PoiseEventHandlerError({}): {}", event.snake_case_name(), error),
|
||||
poise::FrameworkError::NotAnOwner { ctx, .. } => {
|
||||
println!("PoiseNotAnOwner: {} tried to execute a developer-level command ({})", ctx.author().name, ctx.command().qualified_name);
|
||||
ctx.reply("Whoa, you discovered a hidden command! Too bad, I can't allow you to execute it as you're not my creator.").await.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::UnknownInteraction { interaction, .. } => println!(
|
||||
"PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})",
|
||||
interaction.user.name,
|
||||
interaction.data.name
|
||||
),
|
||||
poise::FrameworkError::UnknownCommand { msg, .. } => println!(
|
||||
"PoiseUnknownCommandError: {} tried to execute an unknown command ({})",
|
||||
msg.author.name,
|
||||
msg.content
|
||||
),
|
||||
poise::FrameworkError::ArgumentParse { ctx, error, .. } => {
|
||||
println!("PoiseArgumentParseError: {}", error);
|
||||
ctx.reply(format!("Error parsing argument(s): {error}")).await.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::CommandPanic { ctx, payload, .. } => {
|
||||
if let Some(payload) = payload.clone() {
|
||||
println!("PoiseCommandPanic: {payload}");
|
||||
ctx.reply(format!(
|
||||
"The command panicked, please tell my developer about this!\n**Error:**```\n{payload}\n```"
|
||||
)).await.expect("Error sending message");
|
||||
} else {
|
||||
println!("PoiseCommandPanic: No payload provided");
|
||||
let uh_oh = [
|
||||
"Well, this is concerning... Hopefully you notified my developer about this!",
|
||||
"The command panicked, but didn't leave any trace behind... Suspicious!",
|
||||
].join("\n");
|
||||
ctx.reply(uh_oh).await.expect("Error sending message");
|
||||
}
|
||||
},
|
||||
other => println!("PoiseOtherError: {other}")
|
||||
}
|
||||
}),
|
||||
on_error: |error| {
|
||||
Box::pin(async move {
|
||||
match error {
|
||||
poise::FrameworkError::Command { error, ctx, .. } => {
|
||||
println!("PoiseCommandError({}): {}", ctx.command().qualified_name, error);
|
||||
ctx
|
||||
.reply(format!(
|
||||
"Encountered an error during command execution, ask {} to check console for more details!",
|
||||
mention_dev(ctx).unwrap_or_default()
|
||||
))
|
||||
.await
|
||||
.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::EventHandler { error, event, .. } => println!("PoiseEventHandlerError({}): {}", event.snake_case_name(), error),
|
||||
poise::FrameworkError::NotAnOwner { ctx, .. } => {
|
||||
println!(
|
||||
"PoiseNotAnOwner: {} tried to execute a developer-level command ({})",
|
||||
ctx.author().name,
|
||||
ctx.command().qualified_name
|
||||
);
|
||||
ctx
|
||||
.reply("Whoa, you discovered a hidden command! Too bad, I can't allow you to execute it as you're not my creator.")
|
||||
.await
|
||||
.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::UnknownInteraction { interaction, .. } => println!(
|
||||
"PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})",
|
||||
interaction.user.name, interaction.data.name
|
||||
),
|
||||
poise::FrameworkError::UnknownCommand { msg, .. } => println!(
|
||||
"PoiseUnknownCommandError: {} tried to execute an unknown command ({})",
|
||||
msg.author.name, msg.content
|
||||
),
|
||||
poise::FrameworkError::ArgumentParse { ctx, error, .. } => {
|
||||
println!("PoiseArgumentParseError: {}", error);
|
||||
ctx
|
||||
.reply(format!("Error parsing argument(s): {error}"))
|
||||
.await
|
||||
.expect("Error sending message");
|
||||
},
|
||||
poise::FrameworkError::CommandPanic { ctx, payload, .. } => {
|
||||
if let Some(payload) = payload.clone() {
|
||||
println!("PoiseCommandPanic: {payload}");
|
||||
ctx
|
||||
.reply(format!(
|
||||
"The command panicked, please tell my developer about this!\n**Error:**```\n{payload}\n```"
|
||||
))
|
||||
.await
|
||||
.expect("Error sending message");
|
||||
} else {
|
||||
println!("PoiseCommandPanic: No payload provided");
|
||||
let uh_oh = [
|
||||
"Well, this is concerning... Hopefully you notified my developer about this!",
|
||||
"The command panicked, but didn't leave any trace behind... Suspicious!"
|
||||
]
|
||||
.join("\n");
|
||||
ctx.reply(uh_oh).await.expect("Error sending message");
|
||||
}
|
||||
},
|
||||
other => println!("PoiseOtherError: {other}")
|
||||
}
|
||||
})
|
||||
},
|
||||
allowed_mentions: Some(CreateAllowedMentions::default().empty_users()),
|
||||
initialize_owners: true,
|
||||
skip_checks_for_owners: true,
|
||||
@ -118,14 +138,13 @@ async fn main() {
|
||||
|
||||
let mut client = ClientBuilder::new(
|
||||
discord_token().await,
|
||||
GatewayIntents::GUILDS
|
||||
| GatewayIntents::GUILD_MESSAGES
|
||||
| GatewayIntents::MESSAGE_CONTENT
|
||||
GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT
|
||||
)
|
||||
.framework(framework)
|
||||
.data(Arc::new(RustbotData {}))
|
||||
.activity(ActivityData::custom("nep nep!"))
|
||||
.await.expect("Error creating client");
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
|
||||
let shard_manager = client.shard_manager.clone();
|
||||
|
||||
|
@ -7,16 +7,11 @@ use tokio::{
|
||||
};
|
||||
|
||||
pub async fn gracefully_shutdown() {
|
||||
let [mut s1, mut s2, mut s3] = [
|
||||
signal(SignalKind::interrupt()).unwrap(),
|
||||
signal(SignalKind::terminate()).unwrap(),
|
||||
signal(SignalKind::hangup()).unwrap()
|
||||
];
|
||||
let [mut s1, mut s2] = [signal(SignalKind::interrupt()).unwrap(), signal(SignalKind::hangup()).unwrap()];
|
||||
|
||||
select!(
|
||||
v = s1.recv() => v.unwrap(),
|
||||
v = s2.recv() => v.unwrap(),
|
||||
v = s3.recv() => v.unwrap()
|
||||
v = s2.recv() => v.unwrap()
|
||||
);
|
||||
|
||||
println!("\nRustbot says goodbye! 👋");
|
||||
|
@ -5,5 +5,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
poise = { workspace = true }
|
||||
tokenservice-client = { version = "0.4.1", registry = "gitea" }
|
||||
tokenservice-client = { version = "0.4.2", registry = "gitea" }
|
||||
tokio = { workspace = true }
|
||||
|
@ -1,20 +1,20 @@
|
||||
use poise::serenity_prelude::Token;
|
||||
use tokio::sync::Mutex;
|
||||
use std::{
|
||||
str::FromStr,
|
||||
sync::LazyLock
|
||||
};
|
||||
use tokenservice_client::{
|
||||
TokenService,
|
||||
TokenServiceApi
|
||||
use {
|
||||
poise::serenity_prelude::Token,
|
||||
std::{
|
||||
str::FromStr,
|
||||
sync::LazyLock
|
||||
},
|
||||
tokenservice_client::{
|
||||
TokenService,
|
||||
TokenServiceApi
|
||||
},
|
||||
tokio::sync::Mutex
|
||||
};
|
||||
|
||||
pub struct TSClient(TokenService);
|
||||
|
||||
impl Default for TSClient {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
impl TSClient {
|
||||
@ -34,11 +34,6 @@ impl TSClient {
|
||||
|
||||
static TSCLIENT: LazyLock<Mutex<TSClient>> = LazyLock::new(|| Mutex::new(TSClient::new()));
|
||||
|
||||
pub async fn token_path() -> TokenServiceApi {
|
||||
TSCLIENT.lock().await.get().await.unwrap()
|
||||
}
|
||||
pub async fn token_path() -> TokenServiceApi { TSCLIENT.lock().await.get().await.unwrap() }
|
||||
|
||||
pub async fn discord_token() -> Token {
|
||||
Token::from_str(&token_path().await.main)
|
||||
.expect("Serenity couldn't parse the bot token!")
|
||||
}
|
||||
pub async fn discord_token() -> Token { Token::from_str(&token_path().await.main).expect("Serenity couldn't parse the bot token!") }
|
||||
|
Loading…
Reference in New Issue
Block a user