Compare commits

..

1 Commits

Author SHA1 Message Date
b9816fab96 Experiment the role field in Serenity 2025-01-19 14:13:47 +11:00
15 changed files with 386 additions and 646 deletions

150
Cargo.lock generated

@ -160,9 +160,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.10.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "bytestring"
@ -582,22 +582,10 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets",
]
[[package]]
name = "gimli"
version = "0.31.1"
@ -1026,7 +1014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi",
"windows-sys 0.52.0",
]
@ -1237,7 +1225,7 @@ version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy 0.7.35",
"zerocopy",
]
[[package]]
@ -1274,8 +1262,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
dependencies = [
"bytes",
"getrandom 0.2.15",
"rand 0.8.5",
"getrandom",
"rand",
"ring",
"rustc-hash",
"rustls",
@ -1317,19 +1305,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.0",
"zerocopy 0.8.18",
"rand_chacha",
"rand_core",
]
[[package]]
@ -1339,17 +1316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.0",
"rand_core",
]
[[package]]
@ -1358,17 +1325,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.15",
]
[[package]]
name = "rand_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
dependencies = [
"getrandom 0.3.1",
"zerocopy 0.8.18",
"getrandom",
]
[[package]]
@ -1489,7 +1446,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"getrandom",
"libc",
"spin",
"untrusted",
@ -1504,7 +1461,6 @@ dependencies = [
"rustbot_cmds",
"rustbot_events",
"rustbot_lib",
"rustbot_tasks",
"rustbot_tokens",
"tokio",
]
@ -1513,11 +1469,11 @@ dependencies = [
name = "rustbot_cmds"
version = "0.1.0"
dependencies = [
"bytes",
"poise",
"rand 0.9.0",
"rand",
"reqwest",
"rustbot_lib",
"rustbot_tokens",
"serde",
"sysinfo",
"uptime_lib",
@ -1531,6 +1487,13 @@ dependencies = [
"rustbot_lib",
]
[[package]]
name = "rustbot_jobs"
version = "0.1.0"
dependencies = [
"tokio",
]
[[package]]
name = "rustbot_lib"
version = "0.1.0"
@ -1539,15 +1502,6 @@ dependencies = [
"poise",
]
[[package]]
name = "rustbot_tasks"
version = "0.1.0"
dependencies = [
"poise",
"rustbot_lib",
"tokio",
]
[[package]]
name = "rustbot_tokens"
version = "0.1.0"
@ -1686,9 +1640,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.218"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
@ -1704,9 +1658,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.218"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@ -1715,9 +1669,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.139"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
checksum = "336a0c23cf42a38d9eaa7cd22c7040d04e1228a19a933890805ffd00a16437d2"
dependencies = [
"itoa",
"memchr",
@ -1749,7 +1703,7 @@ dependencies = [
[[package]]
name = "serenity"
version = "0.12.4"
source = "git+https://github.com/serenity-rs/serenity?branch=next#45fb401e38c61e84b08ed368ac61a1d92805d949"
source = "git+https://github.com/nwerosama/serenity?branch=update-emoji#ef416bf3ff8b9423bb5bba9e44d2ba3192e8db02"
dependencies = [
"aformat",
"arrayvec",
@ -1975,7 +1929,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
dependencies = [
"cfg-if",
"fastrand",
"getrandom 0.2.15",
"getrandom",
"once_cell",
"rustix",
"windows-sys 0.59.0",
@ -2090,9 +2044,9 @@ dependencies = [
[[package]]
name = "tokenservice-client"
version = "0.4.3"
version = "0.4.2"
source = "registry+https://git.toast-server.net/toast/_cargo-index"
checksum = "71e3aeafcfb59464d7350349b4f78e3c33a9700a7015e44a24492952ef28170b"
checksum = "6c6f3da21601ea1072262024198c099bea1688714f13b13c36cc7f4a88c6b203"
dependencies = [
"reqwest",
"serde",
@ -2294,7 +2248,7 @@ dependencies = [
"http",
"httparse",
"log",
"rand 0.8.5",
"rand",
"rustls",
"rustls-pki-types",
"sha1",
@ -2435,15 +2389,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
@ -2762,15 +2707,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags",
]
[[package]]
name = "write16"
version = "1.0.0"
@ -2814,16 +2750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2"
dependencies = [
"zerocopy-derive 0.8.18",
"zerocopy-derive",
]
[[package]]
@ -2837,17 +2764,6 @@ dependencies = [
"syn 2.0.96",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
]
[[package]]
name = "zerofrom"
version = "0.1.5"

@ -7,37 +7,39 @@ edition = "2024"
members = [
"cmds",
"events",
"tasks",
"jobs",
"library",
"tsclient"
]
[workspace.dependencies]
bytes = "1.10.0"
cargo_toml = "0.21.0"
poise = "0.6.1"
regex = "1.11.1"
serde = "1.0.217"
rand = "0.9.0"
rand = "0.8.5"
sysinfo = "0.33.1"
time = "0.3.37"
uptime_lib = "0.3.1"
tokio = { version = "1.43.0", features = ["rt-multi-thread", "macros", "signal"] }
tokio = { version = "1.43.0", features = ["macros", "signal", "rt-multi-thread"] }
reqwest = { version = "0.12.12", features = ["native-tls-vendored"] }
rustbot_lib = { path = "library" }
rustbot_tokens = { path = "tsclient" }
[dependencies]
poise = { workspace = true }
rustbot_cmds = { path = "cmds" }
rustbot_events = { path = "events" }
rustbot_lib = { workspace = true }
rustbot_tokens = { path = "tsclient" }
rustbot_tasks = { path = "tasks" }
rustbot_tokens = { workspace = true }
tokio = { workspace = true }
[patch.crates-io]
poise = { git = "https://github.com/serenity-rs/poise", branch = "serenity-next" }
[patch."https://github.com/serenity-rs/serenity"]
serenity = { git = "https://github.com/nwerosama/serenity", branch = "update-emoji" }
[features]
production = ["rustbot_lib/production", "rustbot_events/production"]
not_ready = ["rustbot_lib/not_ready"]

@ -2,7 +2,7 @@ FROM scratch AS base
WORKDIR /builder
COPY . .
FROM adelielinux/adelie:1.0-beta6@sha256:7126a96c19be064a487ba7176baa58200a26ce8fda02b851b4a0bef760b1f469
FROM alpine:3.21@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099
LABEL org.opencontainers.image.source="https://git.toast-server.net/toast/Rustbot"
RUN apk add --no-cache libgcc
WORKDIR /rustbot

@ -4,11 +4,11 @@ version = "0.1.0"
edition = "2024"
[dependencies]
bytes = { workspace = true }
poise = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true }
rustbot_lib = { workspace = true }
rustbot_tokens = { workspace = true }
serde = { workspace = true }
sysinfo = { workspace = true }
uptime_lib = { workspace = true }

@ -1,12 +1,14 @@
mod dev;
mod eightball;
mod ping;
mod role_test;
mod uptime;
pub use {
dev::dev,
eightball::eightball,
ping::ping,
role_test::role_test,
uptime::uptime
};
@ -21,6 +23,7 @@ macro_rules! collect {
$crate::uptime(),
// Unsorted mess
$crate::eightball(),
$crate::role_test(),
]
};
}

@ -1,22 +1,13 @@
use {
bytes::Bytes,
poise::{
CreateReply,
serenity_prelude::{
CreateAttachment,
UserId
}
builtins::paginate,
serenity_prelude::UserId
},
rand::random,
rustbot_lib::{
RustbotContext,
RustbotResult,
config::BINARY_PROPERTIES
},
std::fmt::{
Display,
Formatter,
Result
}
};
@ -25,24 +16,7 @@ enum ResponseMode {
Normal,
Chicken,
#[name = "Chaotic & Unhinged"]
Chaotic,
#[name = "UwU"]
Uwu
}
impl Display for ResponseMode {
fn fmt(
&self,
f: &mut Formatter<'_>
) -> Result {
let resp = match self {
ResponseMode::Normal => "Normal",
ResponseMode::Chicken => "Chicken",
ResponseMode::Chaotic => "Chaotic & Unhinged",
ResponseMode::Uwu => "UwU"
};
write!(f, "{resp}")
}
Chaotic
}
/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer
@ -57,7 +31,7 @@ pub async fn eightball(
#[description = "Your yes/no question"] question: String,
#[description = "Response modes"] mode: Option<ResponseMode>
) -> RustbotResult<()> {
if question.to_ascii_lowercase().contains("rustbot, show list") {
if question.to_ascii_lowercase().contains("niko, show list") {
show_list(ctx, mode.clone().unwrap_or(ResponseMode::Normal)).await?;
return Ok(())
}
@ -65,7 +39,6 @@ pub async fn eightball(
let rand_resp = match mode {
Some(ResponseMode::Chicken) => get_random_chicken_response(),
Some(ResponseMode::Chaotic) => get_random_chaotic_response(),
Some(ResponseMode::Uwu) => get_random_uwu_response(),
_ => get_random_response()
};
@ -85,377 +58,219 @@ async fn show_list(
return Ok(());
}
let selected_responses = match list_type {
ResponseMode::Normal => RESPONSES.to_vec(),
ResponseMode::Chicken => CHICKEN_RESPONSES.to_vec(),
ResponseMode::Chaotic => CHAOTIC_RESPONSES.to_vec(),
ResponseMode::Uwu => UWU_RESPONSES.to_vec()
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 total_yes = selected_responses.iter().filter(|&&(_, yes)| yes).count();
let total_no = selected_responses.len() - total_yes;
let response_strings: Vec<String> = selected_responses.iter().map(|&(resp, _)| resp.to_string()).collect();
let response_mode = format!("Response mode: {list_type}");
let content = [
response_mode.clone(),
"Totals:".to_string(),
format!(" - Yes: {total_yes}"),
format!(" - No: {total_no}"),
format!(" - Strings: {}", selected_responses.len()),
"-".to_string().repeat(response_mode.len()),
response_strings.join("\n")
]
.join("\n");
let filename = match list_type {
ResponseMode::Normal => "responses.txt",
ResponseMode::Chicken => "chicken_responses.txt",
ResponseMode::Chaotic => "chaotic_responses.txt",
ResponseMode::Uwu => "uwu_responses.txt"
};
ctx
.send(CreateReply::new().attachment(CreateAttachment::bytes(Bytes::from(content), filename)))
.await?;
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
paginate(ctx, &pages).await?;
Ok(())
}
const RESPONSES: [(&str, bool); 55] = [
("Reply hazy. Look it up on Google.", false),
("Meh — Figure it out yourself.", false),
("I don't know, what do you think?", false),
("Yes.", true),
("No.", false),
("It is decidedly so", true),
(
"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.",
false
),
("Signs point to... ~~yes~~ no.", false),
("Why do you want to know the answer? It's obviously a yes.", true),
("Outlook not so good.", false),
("Outlook hazy.", false),
("What are you, stupid?", false),
("How the hell do you not know that?", false),
("Really? Making a decision based on what the plastic 8-Ball says? Jesus...", false),
("Try asking later...", false),
("I don't know, whip out the ouija board and try again?", false),
("The answer is yes.", true),
("Yes, actually no. Wait, nevermind.", false),
("Maybeee...", true),
("Definitely!", true),
("It is decidedly so.", true),
("My reply is no.", false),
(
"My sources confirms that the answer is no.\nSource: :sparkles: *i made it up* :sparkles;",
false
),
("As I see it, yes.", true),
("Don't count on it.", false),
("Whoa! Why do I have to answer this?", false),
("Highly unlikely.", false),
("Sure, but with extreme cautions.", true),
("What kind of stupid question is that?? No! I'm not answering that!", false),
("Try asking this to a chicken. Probably knows it better than I do!", false),
("Not in a million years!", false),
("As a matter of fact, yes.", true),
("It's a no, better go ask someone else.", false),
("In the end, it's not a bad choice.", true),
("Nope, not today.", false),
("Cross your fingers, the answer is yes!", true),
("Nope. *shakes head*", false),
("The fortune cookie said yes.", true),
("Sorry, the fortune cookie over there said no.", false),
("Sorry, not happening.", false),
("I'll have to consult my sources... *flips coin*... no.", false),
("I'll have to consult the magic 8-ball... *shakes*... no.", false),
("I'm not sure to be honest, let's ask your friend. Oh wait...", false),
("This question flew over my head, I'll pass.", false),
(
"Oops, the Magic 8-Ball shattered itself when you asked that! I'll take that as a no.",
false
),
("Absolutely not, but keep trying!", false),
("Yes, in a galaxy far far away!", true),
("Ask yourself and find the answer.", false),
("The stars align for a yes.", true),
("Chances are slim, but possible.", false),
("Without a doubt, the universe agrees.", true),
("Better not tell you now.", false),
("Certainly in your favor.", true),
("Look within for the answer.", false),
("Everything points to yes!", true)
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, bool); 54] = [
("Cluck cluck... Reply hazy, try pecking Google.", false),
("Meh... Figure it out yourself, or scratch around a bit.", false),
("I don't know... what do you think? *pecks at ground*", false),
("BAWK! YES!", true),
("Cluck... no.", false),
("It is decidedly so! *flaps wings*", true),
(
"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.",
false
),
("Signs point to... ~~yes~~ cluck no.", false),
("Why do you want to know? It's a big cluckin' yes!", true),
("Outlook not so clucking good.", false),
("Outlook cluckin' hazy.", false),
("What are you, a lost chick? Cluck!", false),
("How the cluck do you not know that?", false),
("Really? Asking a chicken to decide your fate? *clucks judgmentally*", false),
("Peck back later, I'm nesting...", false),
("I don't know, try flapping your wings and ask again?", false),
("The answer is a big ol' yes! *flaps happily*", true),
("Yes... wait, actually... no. Cluck, I'm confused.", false),
("Maaaaybe... *chicken waddle*?", true),
("Definitely! *struts confidently*", true),
("It is decidedly so. *struts with pride*", true),
("My reply is a solid *cluck* no.", false),
("My sources confirm it's a cluckin' no.\nSource: 🐔 *I made it up* 🐔", false),
("As I see it, yes! *pecks approvingly*", true),
("Don't count on it. *cluck cluck*", false),
("Whoa, why do I have to answer this? *fluffs feathers*", false),
("Highly unlikely. *chicken stare*", false),
("Sure, but with extreme cluckin' caution.", true),
("What kind of stupid question is that?? No! *angry clucks*", false),
("Try asking this to a fellow chicken. They probably know better than I do!", false),
("Cluck yes! *does a happy chicken dance*", true),
("No way, not even for a big bag of feed.", false),
("Yes! *lays egg of approval*", true),
("It's a no, better go scratch somewhere else.", false),
("Cluck-tastic! That's a definite yes.", true),
("Cluck yeah! *struts proudly*", true),
("Nope, not today. *shakes head*", false),
("Feathers crossed, the answer is yes!", true),
("Chicken says nope. *tilts head*", false),
("Absolutely! *clucks happily*", true),
("Not a chance. *fluffs feathers*", false),
("Eggcellent choice! Yes!", true),
("Not in a million clucks!", false),
("As a matter of cluck, yes! *clucks approvingly*", true),
("It's a nopity nope, better go ask another chicken.", false),
("In the end, it's not a bad cluck", true),
("Nope, not today. *clucks sadly*", false),
("Cross your feathers, the answer is yes!", true),
("The fortune cookie said yes. *clucks in agreement*", true),
("Sorry, the fortune cookie over there said no. *clucks in disagreement*", false),
("I'll have to consult my sources... *flips corn*... no.", false),
("I'll have to consult the magic 8-cluck... *shakes*... no.", false),
("I'm not sure to be honest, let's ask your chicken friend. Oh wait...", false),
("This question floated over my head, I'll pass. *clucks dismissively*", false)
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, bool); 143] = [
("Oops! The Magic 8-Ball shattered upon hearing your question. Coincidence?", false),
("Reply hazy. Ask Google's evil twin, Froogle.", false),
("Meh — Consult the ancient texts of Netflix subtitles.", false),
("I don't know, but your cat probably does.", false),
("Yes, but only if you wear a clown wig.", true),
("No. Unless the moon winks at you first.", false),
("It is decidedly a resounding honk-honk!", true),
("Signs point to... maybe... or not... or wait... oh look, a squirrel!", false),
("Signs point to... ~~yes~~ pancakes. Definitely pancakes.", false),
("Why do you want to know? It's obviously a yes — trust the donut prophecy.", true),
("Outlook not so good. Blame Mercury retrograde or your Wi-Fi.", false),
("Outlook hazy. Consult the nearest fortune-telling hamster.", false),
("What are you, a toaster in disguise?", false),
("How the heck do you not know this? Ask a sock puppet!", false),
("Really? Making life choices based on a magic ball? Bold move, friend.", false),
("Try asking later... when I'm less busy binge-watching.", false),
("I don't know, summon a raven and whisper your question into the void.", false),
("The answer is yes, as foretold by the mystical spaghetti.", true),
("Yes, actually no. Wait, yes? Let's go with potato.", false),
("Maybeee... if the stars align and your pizza has extra cheese.", true),
("Definitely! Unless gravity stops working.", true),
("It is decidedly so. So what? Buy a llama and see what happens.", true),
("My reply is no, and also banana pudding.", false),
("My sources confirm that the answer is no.\nSource: A suspicious pigeon.", false),
("As I see it, yes. As the chicken sees it, no. Trust who you like.", true),
("Don't count on it. Count on marshmallows instead.", false),
("Whoa! Why do I have to answer this? Ask a rubber duck.", false),
("Highly unlikely. Unless it's Tuesday on Mars.", false),
("Sure, but with extreme caution and a tinfoil hat.", true),
("What kind of silly question is that?? No! Also, here's a kazoo.", false),
("Try asking this to a chicken. They're the true oracles.", false),
("Not in a million years! Unless the earth is made of cheese.", false),
("As a matter of fact, yes. And it's raining tacos.", true),
("It's a no, but the raccoons might know better.", false),
("In the end, it's not a bad choice. Or is it? Mwahaha.", true),
("Nope, not today. Try tomorrow after coffee.", false),
("Cross your fingers! Or better yet, cross the streams.", true),
("Nope. *shakes head like a very judgmental parrot*", false),
("The fortune cookie said yes, but it was written in crayon.", true),
("Sorry, the fortune cookie over there said no. Blame it.", false),
("Sorry, not happening. But you get a virtual sticker for trying!", false),
("I'll have to consult my sources... *flips a pancake*... no.", false),
("I'll have to consult the magic 8-ball... *shakes it violently*... still no.", false),
("I'm not sure, but your imaginary friend says yes.", true),
("This question flew over my head, so I'll just say 'llama'.", false),
("The answer is yes, but only if you do it while wearing socks on your hands.", true),
("No, and I think you broke the space-time continuum by asking.", false),
("Why not? What's the worst that could happen? Oh wait...", false),
("The stars say yes, but the planets are still debating.", true),
("The universe just facepalmed at your question.", false),
("Ask again while juggling flaming pineapples for a clearer answer.", false),
("Nope, not unless you bribe me with tacos.", false),
("I consulted the oracle... she's out to lunch. Try later.", false),
("Yes, but only if you can lick your elbow right now.", true),
("No, because I said so and I'm very wise. Also, I'm a plastic ball.", false),
("Yes. No. Wait, I've lost track. Did you hear that noise?", false),
("Absolutely, as long as you bring me a rubber chicken as tribute.", true),
("I asked a wizard, and they just laughed hysterically.", false),
("The spirits say no, but the ghosts are nodding yes.", false),
("Yes, if you believe in unicorns and the power of friendship.", true),
("No, and also you might want to move. Something's behind you.", false),
("Ask again, but this time with interpretive dance.", false),
("Definitely! Unless the moon turns into cheese. Then no.", true),
("I see... wait, no, I don't see. My crystal ball is buffering.", false),
("Sure! But only after a karaoke duet with a raccoon.", true),
("Yes, but only if you promise not to tell the ducks.", true),
("No way, unless you can recite the alphabet backwards in one breath.", false),
("Ask the magic mushroom. It's way more in touch with reality than I am.", false),
("No, because gravity disagrees with your premise.", false),
("Yes, but first you must complete the sacred quest for nachos.", true),
("The answer is hidden in the folds of your laundry. Go check.", false),
("I would answer, but I'm legally obligated to stay mysterious.", false),
("The council of cats says yes, but only if you meow like one.", true),
("No, but only because the Magic 8-Ball union forbids it.", false),
("Yes, if the dog wags its tail twice before the clock strikes midnight.", true),
("Try again after doing three cartwheels and making a wish.", false),
("The ducks in my dreams say no. They're rarely wrong.", false),
("Not today, Satan. Not today.", false),
("Yes, but only on Wednesdays during a full moon.", true),
("No, because bananas don't grow in winter.", false),
("The answer is locked in a time capsule. Check back in 50 years.", false),
("I don't know, but it smells like trouble.", false),
("Why not? The penguins approve, and that's good enough for me.", true),
("Sure, but only if you say 'bubblegum' ten times fast.", true),
("No, unless you can outsmart a sentient toaster.", false),
("The answer is yes, but it comes with a plot twist.", true),
("Flip a coin, spin three times, and consult your nearest cactus. Good luck!", false),
("Only on the condition that you buy me a donut.", true),
("Yes, but proceed at your own risk. The llamas are watching.", true),
("Yes, but only if you drive like a maniac.", true),
("Absolutely, and the crabs are hosting a rave.", true),
("No, but a mischievous gnome just winked at me, so.. yes.", true),
("Yes, but you'll have to fight off a pack of ninja turtles first.", true),
("Nope. The Magic 8-Ball union called for a strike, try later.", false),
("The answer is clear: definitely a turtle. Wait, what was the question again?", false),
("Yes, but only if you perform the forbidden kazoo solo.", true),
("No, because I just consulted a very grumpy cloud.", false),
("Sure, but beware of the ominous whispers in the wind.", true),
("Absolutely not! Unless you bribe me with pancakes... then maybe.", false),
("The prophecy foretells a yes, but only after you do a somersault.", true),
("Negative, captain! The squirrels have spoken.", false),
("Ask again after you defeat a level 70 pancake god.", false),
("Yes, but only if you shout 'pineapple' while hopping on one foot.", true),
("The stars say no, but the pigeons disagree. Trust your instincts.", false),
("Yes, but at great personal risk to your snack supply.", true),
("No way. Unless you're wearing a hat shaped like a pineapple.", false),
("Consult the oracle of toasters. They hold the real truth.", false),
("The vibes are off. Try again with a disco ball in hand.", false),
("Yes, but the llamas demand a dance-off first.", true),
("Nope. Also, why does your question smell like burnt toast?", false),
("Yes, but the fabric of reality might unravel. Worth it?", true),
("No, because an interdimensional ferret stole the answer.", false),
("Absolutely! But only if you chant 'banana' three times at sunrise.", true),
("No, unless you appease the gummy bear council with offerings.", false),
("Maybe, but the answer is hidden in the Great Taco of Wisdom.", false),
("Yes, but don't trust the robot vacuum. It knows too much.", true),
("I see a yes in your future... or a spaghetti monster. Hard to say.", true),
("Ask a sock puppet again, but this time in interpretive mime.", false),
("It's a no, but the goldfish thinks otherwise. Who do you trust?", false),
("Signs point to yes, but only if you name a star after a pineapple.", true),
("The answer is no. Unless it's opposite day, then yes.", false),
("Yes, but only if the answer doesn't involve marmalade.", true),
("I'm sorry, Dave, I can't do that. Oh wait, wrong universe. No.", false),
("The Magic 8-Ball has declared a state of confusion, try again.", false),
("Yes, but it might result in spontaneous interpretive breakdancing.", true),
("The frogs are undecided. Maybe bribe them with flies?", false),
("A resounding yes! Unless you're allergic to good luck.", true),
("No, and also stop shaking me so hard! I'm fragile!", false),
("Yes, but only if you can out-dance a crab at karaoke night.", true),
("Nope, the answer is currently orbiting Jupiter. Check back in a century.", false),
("ASK AGAIN—wait, no, don't! I'm on break", false),
("Hahahahaha.. no!", false),
("I'm an 8-ball, not your therapist.. But yes!", true),
("God has increased your difficulty to insane, 8-ball said go ahead!", true),
("**Error 404:** Answer not found", false),
("All signs to point to—ỳ̸̹͈́e̵̥̝͐̋s̶̺͍̉", true),
("The spirits are busy! Leave a message after the beep. *extremely loud beep*", false),
("Sorry, I accidentally threw your question into the trash.", false),
("Yes!! Now go and cause some mayhem!!!", true),
("Yes, you weirdo...", true),
("ya", true),
(
"Bro, you spoke some gibberish sentence to the god, he sighed and signalled **yes** back!",
true
),
("Yes, but tell no one. THEY are listening!", true)
const CHAOTIC_RESPONSES: [&str; 90] = [
"Oops! The Magic 8-Ball shattered upon hearing your question. Coincidence?", // no
"Reply hazy. Ask Googles 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? Its 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 Im 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? Lets 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 its Tuesday on Mars.", // no
"Sure, but with extreme caution and a tinfoil hat.", // yes
"What kind of silly question is that?? No! Also, heres a kazoo.", // no
"Try asking this to a chicken. Theyre the true oracles.", // no
"Not in a million years! Unless the earth is made of cheese.", // no
"As a matter of fact, yes. And its raining tacos.", // yes
"It's a no, but the raccoons might know better.", // no
"In the end, its 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 Ill 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? Whats 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... shes out to lunch. Try later.", // no
"Yes, but only if you can lick your elbow right now.", // yes
"No, because I said so and Im very wise. Also, Im a plastic ball.", // no
"Yes. No. Wait, Ive 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. Somethings 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 dont 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. Its 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 Im 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. Theyre rarely wrong.", // no
"Not today, Satan. Not today.", // no
"Yes, but only on Wednesdays during a full moon.", // yes
"No, because bananas dont grow in winter.", // no
"The answer is locked in a time capsule. Check back in 50 years.", // no
"I dont know, but it smells like trouble.", // no
"Why not? The penguins approve, and thats 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
];
const UWU_RESPONSES: [(&str, bool); 50] = [
("Oopsie! The magic baww got fwightened by youw question, sowwy! >_<", false),
("Hmmm... wet me consuwt my pwushie cowwection... OwO it's a 'maybe?'", false),
("Oh nyo~ the staws awe too shy to answew >w<", false),
("Yes! UwU but onwy if you give me a headpat fiwst!", true),
("Nyope! But I bet chu' can twy again watew! >w<", false),
("Mmmm... I dink it's a 'pwobabwy?' OwO", true),
("The mysticaw fwuffbaww says 'no', but chu awe stiww amazing! >w<", false),
("Oh my fwuff! It's a big YES! UwU", true),
("No way, but chu can get a snuggwe instead! UwU", false),
("Hmmm... nyani?? The answew wawned away! O.O", false),
("Yippee! The answew is absowutewy YES, nyu~!", true),
("Nuuuuu, the wittwe magic is feewing shy... twy again watew, pwomise!", false),
("Hewwo? Hewwo? Magic baww says... oh, it feww asweep >w<", false),
("Maybe! But onwy if chu' twy wif youw happiest smiwe! UwU", true),
("No, but chu awe stiww pwetty bwoomin' paw-some!", false),
("The fwuffies awe undecided... ask a bun bun fwiend! >w<", false),
("Yes, but onwy if chu bwink wike a wittwe kitty! ^w^", true),
("Magic baww is wooking into it... uh-oh! It got stuck in fwuff o.O", false),
("Noooo, but chu can have a tummy wub to cheew chu up! UwU", false),
("Mmmm... I smeww a 'yes', wike fwuffy pancakies! >w<", true),
("Huwwo? Staws awe purring, chu' get a soft nyes~", true),
("Oops, chu bwew my mind wif dat one. Wet's caww it a nyope~", false),
("The answew is a fwuffy YES! Now go do a happy dance~ UwU", true),
("Nyani?? Magic baww says 'no', but chu awe stiww cute >_<", false),
("Hmm, I dink chu awe wooking fow... YESSS! UwU", true),
("Nyu-uh! But chu can twy asking a cheeky pidgeon! UwU", false),
("Yes! But chu must pwomise to make fwiends wif a cuddwy bunny~", true),
("Mmmm... nyope! Sowwy, but chu'we stiww bwoomin' pawsome! >w<", false),
("Yes, yes, aww the yesses in the wowwd fow chu! >w<", true),
("Nyooooope! But chu awe too fwuffy to be sad >w<", false),
("OwO it's a paw-sitive YES fwom me uwu!", true),
("UwU Magic fwuff says 'nyope', but gives chu a cozy bwankie!", false),
("M-m-maybe! Chu might need to twy a cute head tiwt fiwst~", false),
("Yes, UwU! But make suwe to cwink a toastie wif milkies~", true),
("Mmmm... I dink chu awe onto something gweat! It's YESSS! UwU", true),
("Nyaww, magic baww says no, but chu awe stiww adorable~ >w<", false),
("The staws awe wispiewing 'Yes' just fow chu! >w<", true),
("Oh nyo, the cosmic fwuff says 'nyope', but chu awe bwoomin' bwootiful!", false),
("Yes! Go fo' it wike a puppy chasing da sunshine~", true),
("Nuh-uh, not dis time. But chu'we so fwuffin' cute dat it's okay! UwU", false),
("Pawsitively YES! But pwomise chu'ww keep being pwecious~ >_<", true),
("Nyaww, it's a 'no', but chu awe stiww pwetty amazing! UwU", false),
("Yes! Go get it wike a kitty pwouncing on its favouwite toyyy! OwO", true),
("Hmmm... Magic fwuffies awe undeciwded. Twy a hug fiwst? >w<", false),
("Oh nyes! But chu must say 'Nyan nyan' to seaw da deaw!", true),
("Nyani?? Magic baww says nyope, but a kissy on da cheek fixes evewyfing! UwU", false),
("OwO The magic wainbows awe wifting chu to a 'yes'! Go fow it!", true),
("Oh nyo... the fwuffies awe shy dis time. Twy again wif an extwa cwute smiwe~ >w<", false),
("OwO yus yus! Definitewy a big YES!!", true),
("Uwu~ oh nyo, it wooks wike a no... sowwy!", false)
];
fn get_random_response() -> &'static str { RESPONSES[random::<usize>() % RESPONSES.len()] }
fn get_random_response() -> &'static str { RESPONSES[random::<u32>() as usize % RESPONSES.len()].0 }
fn get_random_chicken_response() -> &'static str { CHICKEN_RESPONSES[random::<usize>() % CHICKEN_RESPONSES.len()] }
fn get_random_chicken_response() -> &'static str { CHICKEN_RESPONSES[random::<u32>() as usize % CHICKEN_RESPONSES.len()].0 }
fn get_random_chaotic_response() -> &'static str { CHAOTIC_RESPONSES[random::<u32>() as usize % CHAOTIC_RESPONSES.len()].0 }
fn get_random_uwu_response() -> &'static str { UWU_RESPONSES[random::<u32>() as usize % UWU_RESPONSES.len()].0 }
fn get_random_chaotic_response() -> &'static str { CHAOTIC_RESPONSES[random::<usize>() % CHAOTIC_RESPONSES.len()] }

@ -0,0 +1,66 @@
use {
poise::serenity_prelude::{
Attachment,
CreateAttachment,
EmojiId,
RoleId
},
rustbot_lib::{
RustbotContext,
RustbotResult
}
};
fn extract_role_id(input: &str) -> Option<u64> {
let trimmed = input.trim();
if trimmed.starts_with("<@&") && trimmed.ends_with(">") {
trimmed[3..trimmed.len() - 1].parse().ok()
} else {
trimmed.parse().ok()
}
}
/// Role test
#[poise::command(slash_command, subcommands("create", "edit"), install_context = "Guild", interaction_context = "Guild")]
pub async fn role_test(_: RustbotContext<'_>) -> RustbotResult<()> { Ok(()) }
/// Role test create
#[poise::command(slash_command, install_context = "Guild", interaction_context = "Guild")]
pub async fn create(
ctx: RustbotContext<'_>,
img: Attachment
) -> RustbotResult<()> {
ctx.defer().await?;
let attachment = CreateAttachment::url(ctx.http(), img.url.to_string(), img.filename).await?;
let e = ctx
.guild_id()
.unwrap()
.create_emoji(ctx.http(), "nep", &attachment.to_base64(), vec![RoleId::new(1292024065170608150)], None)
.await?;
ctx.reply(format!("{} = {:?}", e.name, e.roles)).await?;
Ok(())
}
/// Role test edit
#[poise::command(slash_command, install_context = "Guild", interaction_context = "Guild")]
pub async fn edit(
ctx: RustbotContext<'_>,
emoji_id: String,
roles: String
) -> RustbotResult<()> {
ctx.defer().await?;
let role_vec: Vec<RoleId> = roles.split(',').filter_map(extract_role_id).map(RoleId::new).collect();
let e = ctx
.guild_id()
.unwrap()
.edit_emoji(ctx.http(), EmojiId::new(emoji_id.parse().unwrap()), "nep", Some(role_vec), None)
.await?;
ctx.reply(format!("{} = {:?}", e.name, e.roles)).await?;
Ok(())
}

@ -14,11 +14,13 @@ impl EventProcessor<'_> {
&self,
total_shards: &NonZero<u16>
) -> RustbotResult<()> {
let is_singular = total_shards.get() == 1;
println!(
"{RUSTBOT_EVENT}[ShardsReady]: {total_shards} {} ready!",
if is_singular { "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(())
}
@ -27,6 +29,7 @@ impl EventProcessor<'_> {
event: &ShardStageUpdateEvent
) -> RustbotResult<()> {
println!("{RUSTBOT_EVENT}[ShardStageUpdate:S{}]: {event:#?}", event.shard_id);
Ok(())
}
}

@ -1,9 +1,7 @@
[package]
name = "rustbot_tasks"
name = "rustbot_jobs"
version = "0.1.0"
edition = "2024"
[dependencies]
tokio = { workspace = true }
rustbot_lib = {workspace = true }
poise = { workspace = true }

3
jobs/src/lib.rs Executable file

@ -0,0 +1,3 @@
pub mod tasks;
const RUSTBOT_SCHEDULER: &str = "RustbotScheduler";

43
jobs/src/tasks.rs Executable file

@ -0,0 +1,43 @@
use crate::RUSTBOT_SCHEDULER;
use {
std::{
future::Future,
sync::Arc
},
tokio::{
task,
time::{
Duration,
interval
}
}
};
pub struct Scheduler;
impl Scheduler {
pub fn new() -> Arc<Self> { Arc::new(Self) }
pub async fn spawn_job<F, E>(
&self,
interval_secs: u64,
job: Arc<dyn Fn() -> F + Send + Sync + 'static>
) where
F: Future<Output = Result<(), E>> + Send + 'static,
E: std::fmt::Debug
{
let mut interval = interval(Duration::from_secs(interval_secs));
loop {
interval.tick().await;
let job_clone = job.clone();
task::spawn(async move {
if let Err(y) = job_clone().await {
eprintln!("{RUSTBOT_SCHEDULER}[Job:Error]: {y:?}");
}
});
}
}
}

@ -17,7 +17,6 @@ use {
config::BINARY_PROPERTIES,
utils::get_guild_name
},
rustbot_tasks::spawn_task,
rustbot_tokens::discord_token,
std::{
borrow::Cow,
@ -27,9 +26,11 @@ use {
#[tokio::main]
async fn main() {
let prefix = Some(Cow::Borrowed(if BINARY_PROPERTIES.env.contains("prod") { "pg." } else { "pg!" }));
let data = Arc::new(RustbotData {});
let prefix = if BINARY_PROPERTIES.env.contains("prod") {
Some(Cow::Borrowed("pg."))
} else {
Some(Cow::Borrowed("pg!"))
};
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
@ -40,10 +41,10 @@ async fn main() {
Some(channel) => format!("in #{}", channel.name.clone()),
None => String::from("")
};
let prefix = ctx
.command()
.prefix_action
.map_or("/", |_| ctx.framework().options.prefix_options.prefix.as_ref().unwrap());
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}",
@ -76,14 +77,11 @@ async fn main() {
GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT
)
.framework(framework)
.data(Arc::clone(&data))
.data(Arc::new(RustbotData {}))
.activity(ActivityData::custom("nep nep!"))
.await
.expect("Error creating client");
spawn_task(example_task::ExampleTask, Arc::clone(&data)).await;
spawn_task(example_task2::ExampleTask2, Arc::clone(&data)).await;
let shard_manager = client.shard_manager.clone();
tokio::spawn(async move {
@ -95,65 +93,3 @@ async fn main() {
println!("Error starting client: {why:#?}");
}
}
mod example_task {
use {
poise::serenity_prelude::async_trait,
rustbot_lib::{
RustbotData,
RustbotResult
},
rustbot_tasks::TaskCoordinator,
std::sync::Arc,
tokio::time::Duration
};
#[derive(Clone)]
pub struct ExampleTask;
#[async_trait]
impl TaskCoordinator for ExampleTask {
fn name(&self) -> &'static str { "example_task" }
fn interval(&self) -> Duration { Duration::from_secs(10) }
async fn run(
&self,
_: Arc<RustbotData>
) -> RustbotResult<()> {
println!("hello from ExampleTask !");
Ok(())
}
}
}
mod example_task2 {
use {
poise::serenity_prelude::async_trait,
rustbot_lib::{
RustbotData,
RustbotResult
},
rustbot_tasks::TaskCoordinator,
std::sync::Arc,
tokio::time::Duration
};
#[derive(Clone)]
pub struct ExampleTask2;
#[async_trait]
impl TaskCoordinator for ExampleTask2 {
fn name(&self) -> &'static str { "example_task2" }
fn interval(&self) -> Duration { Duration::from_secs(5) }
async fn run(
&self,
_: Arc<RustbotData>
) -> RustbotResult<()> {
println!("hello from ExampleTask2 !");
Ok(())
}
}
}

@ -7,16 +7,11 @@ use tokio::{
};
pub async fn gracefully_shutdown() {
let [mut s1, mut s2, mut s3] = [
signal(SignalKind::interrupt()).unwrap(),
signal(SignalKind::hangup()).unwrap(),
signal(SignalKind::terminate()).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! 👋");

@ -2,7 +2,7 @@ Only things that are needing to be changed before deploying this template to rea
- The project name (Rustbot)
- Dockerfile image tag and its service in compose file
- events (rustbot_events), and its references
- tasks (rustbot_tasks), and its references
- jobs (rustbot_jobs), and its references
- library (rustbot_lib), and its references
- tsclient (rustbot_tokens), and its references

@ -1,40 +0,0 @@
use {
poise::serenity_prelude::async_trait,
rustbot_lib::{
RustbotData,
RustbotResult
},
std::sync::Arc,
tokio::time::{
Duration,
interval
}
};
#[async_trait]
pub trait TaskCoordinator: Send + Sync {
fn name(&self) -> &'static str;
fn interval(&self) -> Duration;
async fn run(
&self,
data: Arc<RustbotData>
) -> RustbotResult<()>;
}
pub async fn spawn_task<T: TaskCoordinator + 'static>(
task: T,
data: Arc<RustbotData>
) {
let t_name = task.name().to_string();
let t_interval = task.interval();
tokio::spawn(async move {
let mut interval = interval(t_interval);
loop {
interval.tick().await;
if let Err(e) = task.run(data.clone()).await {
eprintln!("TaskCoordinator[Err:{t_name}] {e}")
}
}
});
}