Update template with changes
This commit is contained in:
parent
1afad09caf
commit
56e1419b32
881
Cargo.lock
generated
881
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ cargo_toml = "0.20.5"
|
|||||||
poise = "0.6.1"
|
poise = "0.6.1"
|
||||||
regex = "1.11.0"
|
regex = "1.11.0"
|
||||||
serde = "1.0.210"
|
serde = "1.0.210"
|
||||||
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.40.0", features = ["macros", "signal", "rt-multi-thread"] }
|
||||||
reqwest = { version = "0.12.8", features = ["native-tls-vendored"] }
|
reqwest = { version = "0.12.8", features = ["native-tls-vendored"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
mod ready;
|
mod ready;
|
||||||
mod shards;
|
mod shards;
|
||||||
|
|
||||||
|
use poise::serenity_prelude::FullEvent;
|
||||||
use rustbot_lib::{
|
use rustbot_lib::{
|
||||||
RustbotError,
|
RustbotFwCtx,
|
||||||
RustbotData
|
RustbotResult
|
||||||
};
|
|
||||||
use poise::{
|
|
||||||
FrameworkContext,
|
|
||||||
serenity_prelude::FullEvent
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const RUSTBOT_EVENT: &str = "RustbotEvent";
|
pub const RUSTBOT_EVENT: &str = "RustbotEvent";
|
||||||
|
|
||||||
struct EventProcessor<'a> {
|
struct EventProcessor<'a> {
|
||||||
framework: FrameworkContext<'a, RustbotData, RustbotError>
|
framework: RustbotFwCtx<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn processor(
|
pub async fn processor(
|
||||||
framework: FrameworkContext<'_, RustbotData, RustbotError>,
|
framework: RustbotFwCtx<'_>,
|
||||||
event: &FullEvent
|
event: &FullEvent
|
||||||
) -> Result<(), RustbotError> {
|
) -> RustbotResult<()> {
|
||||||
let processor = EventProcessor { framework };
|
let processor = EventProcessor { framework };
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::PoiseFwCtx;
|
|
||||||
use super::{
|
use super::{
|
||||||
EventProcessor,
|
EventProcessor,
|
||||||
RUSTBOT_EVENT
|
RUSTBOT_EVENT
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustbot_lib::{
|
use rustbot_lib::{
|
||||||
RustbotError,
|
RustbotFwCtx,
|
||||||
|
RustbotResult,
|
||||||
utils::{
|
utils::{
|
||||||
BOT_VERSION,
|
BOT_VERSION,
|
||||||
GIT_COMMIT_HASH,
|
GIT_COMMIT_HASH,
|
||||||
@ -15,7 +15,7 @@ use rustbot_lib::{
|
|||||||
};
|
};
|
||||||
use std::sync::atomic::{
|
use std::sync::atomic::{
|
||||||
AtomicBool,
|
AtomicBool,
|
||||||
Ordering
|
Ordering::Relaxed
|
||||||
};
|
};
|
||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
Ready,
|
Ready,
|
||||||
@ -29,8 +29,8 @@ static READY_ONCE: AtomicBool = AtomicBool::new(false);
|
|||||||
|
|
||||||
async fn ready_once(
|
async fn ready_once(
|
||||||
ready: &Ready,
|
ready: &Ready,
|
||||||
framework: PoiseFwCtx<'_>
|
framework: RustbotFwCtx<'_>
|
||||||
) -> Result<(), RustbotError> {
|
) -> RustbotResult<()> {
|
||||||
#[cfg(not(feature = "production"))]
|
#[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);
|
||||||
@ -57,8 +57,8 @@ impl EventProcessor<'_> {
|
|||||||
pub async fn on_ready(
|
pub async fn on_ready(
|
||||||
&self,
|
&self,
|
||||||
data_about_bot: &Ready
|
data_about_bot: &Ready
|
||||||
) -> Result<(), RustbotError> {
|
) -> RustbotResult<()> {
|
||||||
if !READY_ONCE.swap(true, Ordering::Relaxed) {
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,14 +4,14 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
use rustbot_lib::RustbotError;
|
use rustbot_lib::RustbotResult;
|
||||||
use poise::serenity_prelude::ShardStageUpdateEvent;
|
use poise::serenity_prelude::ShardStageUpdateEvent;
|
||||||
|
|
||||||
impl EventProcessor<'_> {
|
impl EventProcessor<'_> {
|
||||||
pub async fn on_shards_ready(
|
pub async fn on_shards_ready(
|
||||||
&self,
|
&self,
|
||||||
total_shards: &NonZero<u16>
|
total_shards: &NonZero<u16>
|
||||||
) -> Result<(), RustbotError> {
|
) -> 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!");
|
println!("{RUSTBOT_EVENT}[ShardsReady]: {total_shards} {shards} ready!");
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ impl EventProcessor<'_> {
|
|||||||
pub async fn on_shards_stageupdate(
|
pub async fn on_shards_stageupdate(
|
||||||
&self,
|
&self,
|
||||||
event: &ShardStageUpdateEvent
|
event: &ShardStageUpdateEvent
|
||||||
) -> Result<(), RustbotError> {
|
) -> RustbotResult<()> {
|
||||||
println!("{RUSTBOT_EVENT}[ShardStageUpdate:S{}]: {event:#?}", event.shard_id);
|
println!("{RUSTBOT_EVENT}[ShardStageUpdate:S{}]: {event:#?}", event.shard_id);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,19 +1,10 @@
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
|
|
||||||
// use serde_json::json;
|
// use serde_json::json;
|
||||||
use rustbot_lib::{
|
/* use poise::serenity_prelude::{
|
||||||
RustbotData,
|
|
||||||
RustbotError
|
|
||||||
};
|
|
||||||
use poise::{
|
|
||||||
FrameworkContext,
|
|
||||||
/* serenity_prelude::{
|
|
||||||
Context,
|
Context,
|
||||||
WebhookId
|
WebhookId
|
||||||
} */
|
}; */
|
||||||
};
|
|
||||||
|
|
||||||
type PoiseFwCtx<'a> = FrameworkContext<'a, RustbotData, RustbotError>;
|
|
||||||
|
|
||||||
/* async fn hook_logger(
|
/* async fn hook_logger(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub struct ConfigMeta {
|
pub struct ConfigMeta {
|
||||||
pub env: String,
|
pub env: &'static str,
|
||||||
pub embed_color: u32,
|
pub embed_color: u32,
|
||||||
pub rustbot_logs: u64,
|
pub rustbot_logs: u64,
|
||||||
pub developers: Vec<u64>
|
pub developers: Vec<u64>
|
||||||
@ -13,16 +13,16 @@ pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(ConfigMeta::n
|
|||||||
#[cfg(not(feature = "production"))]
|
#[cfg(not(feature = "production"))]
|
||||||
pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(||
|
pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(||
|
||||||
ConfigMeta::new()
|
ConfigMeta::new()
|
||||||
.env(String::from("dev"))
|
.env("dev")
|
||||||
.embed_color(0xf1d63c)
|
.embed_color(0xf1d63c)
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ConfigMeta {
|
impl ConfigMeta {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
env: String::from("prod"),
|
env: "prod",
|
||||||
embed_color: 0xf1d63c,
|
embed_color: 0xf1d63c,
|
||||||
rustbot_logs: 1276874302314254448,
|
rustbot_logs: 1311282815601741844,
|
||||||
developers: vec![
|
developers: vec![
|
||||||
190407856527376384 // toast.ts
|
190407856527376384 // toast.ts
|
||||||
]
|
]
|
||||||
@ -31,7 +31,7 @@ impl ConfigMeta {
|
|||||||
|
|
||||||
// Scalable functions below;
|
// Scalable functions below;
|
||||||
#[cfg(not(feature = "production"))]
|
#[cfg(not(feature = "production"))]
|
||||||
fn env(mut self, env: String) -> Self {
|
fn env(mut self, env: &'static str) -> Self {
|
||||||
self.env = env;
|
self.env = env;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,7 @@ mod data;
|
|||||||
pub use data::RustbotData;
|
pub use data::RustbotData;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub type RustbotError = Box<dyn std::error::Error + Send + Sync>;
|
type RustbotError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
pub type RustbotCtx<'a> = poise::Context<'a, RustbotData, RustbotError>;
|
pub type RustbotContext<'a> = poise::Context<'a, RustbotData, RustbotError>;
|
||||||
|
pub type RustbotFwCtx<'a> = poise::FrameworkContext<'a, RustbotData, RustbotError>;
|
||||||
|
pub type RustbotResult<T> = Result<T, RustbotError>;
|
||||||
|
@ -21,7 +21,7 @@ pub fn format_timestamp(timestamp: i64) -> String {
|
|||||||
format!("<t:{timestamp}>\n<t:{timestamp}:R>")
|
format!("<t:{timestamp}>\n<t:{timestamp}:R>")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mention_dev(ctx: super::RustbotCtx<'_>) -> Option<String> {
|
pub fn mention_dev(ctx: super::RustbotContext<'_>) -> Option<String> {
|
||||||
let devs = super::config::BINARY_PROPERTIES.developers.clone();
|
let devs = super::config::BINARY_PROPERTIES.developers.clone();
|
||||||
let app_owners = ctx.framework().options().owners.clone();
|
let app_owners = ctx.framework().options().owners.clone();
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ pub fn mention_dev(ctx: super::RustbotCtx<'_>) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_guild_name(ctx: super::RustbotCtx<'_>) -> String {
|
pub fn get_guild_name(ctx: super::RustbotContext<'_>) -> String {
|
||||||
match ctx.guild() {
|
match ctx.guild() {
|
||||||
Some(guild) => guild.name.clone().to_string(),
|
Some(guild) => guild.name.clone().to_string(),
|
||||||
None => String::from("DM")
|
None => String::from("DM")
|
||||||
@ -63,7 +63,7 @@ pub fn format_duration(secs: u64) -> String {
|
|||||||
let formatted_string: Vec<String> = components
|
let formatted_string: Vec<String> = components
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(value, _)| value > 0)
|
.filter(|&&(value, _)| value > 0)
|
||||||
.map(|&(value, suffix)| format!("{}{}", value, suffix))
|
.map(|&(value, suffix)| format!("{value}{suffix}"))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
formatted_string.join(", ")
|
formatted_string.join(", ")
|
||||||
|
@ -8,8 +8,6 @@ pub use eightball::eightball;
|
|||||||
pub use ping::ping;
|
pub use ping::ping;
|
||||||
pub use uptime::uptime;
|
pub use uptime::uptime;
|
||||||
|
|
||||||
type PoiseContext<'a> = rustbot_lib::RustbotCtx<'a>;
|
|
||||||
|
|
||||||
macro_rules! collect {
|
macro_rules! collect {
|
||||||
() => {
|
() => {
|
||||||
vec![
|
vec![
|
||||||
|
@ -1,53 +1,82 @@
|
|||||||
use crate::RustbotError;
|
use rustbot_lib::{
|
||||||
use super::PoiseContext;
|
RustbotContext,
|
||||||
|
RustbotResult
|
||||||
|
};
|
||||||
use poise::{
|
use poise::{
|
||||||
CreateReply,
|
CreateReply,
|
||||||
serenity_prelude::ChannelId
|
serenity_prelude::{
|
||||||
|
ChannelId,
|
||||||
|
ShardId,
|
||||||
|
ShardRunnerInfo
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async fn format_shard_info(
|
||||||
|
id: &ShardId,
|
||||||
|
runner: &ShardRunnerInfo,
|
||||||
|
ctx: &RustbotContext<'_>
|
||||||
|
) -> String {
|
||||||
|
let mut string = String::new();
|
||||||
|
|
||||||
|
let heartbeat = match runner.latency {
|
||||||
|
Some(lat) => format!("`{}ms`", lat.as_millis()),
|
||||||
|
None => "Waiting for heartbeat...".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = runner.stage.to_string();
|
||||||
|
let shard_count = ctx.cache().shard_count();
|
||||||
|
let guild_count = ctx.cache().guilds().into_iter().filter(|g| g.shard_id(shard_count) == id.0).count() as u64;
|
||||||
|
|
||||||
|
string.push_str(&format!("**Shard {id}**\n"));
|
||||||
|
string.push_str(&format!("> Heartbeat: {heartbeat}\n"));
|
||||||
|
string.push_str(&format!("> Status: `{status}`\n"));
|
||||||
|
string.push_str(&format!("> Guilds: **{guild_count}**"));
|
||||||
|
|
||||||
|
string
|
||||||
|
}
|
||||||
|
|
||||||
/// Developer commands
|
/// Developer commands
|
||||||
#[poise::command(
|
#[poise::command(
|
||||||
slash_command,
|
|
||||||
prefix_command,
|
prefix_command,
|
||||||
|
slash_command,
|
||||||
owners_only,
|
owners_only,
|
||||||
|
install_context = "Guild|User",
|
||||||
|
interaction_context = "Guild|BotDm|PrivateChannel",
|
||||||
subcommands("deploy", "servers", "shards", "echo")
|
subcommands("deploy", "servers", "shards", "echo")
|
||||||
)]
|
)]
|
||||||
pub async fn dev(_: PoiseContext<'_>) -> Result<(), RustbotError> {
|
pub async fn dev(_: RustbotContext<'_>) -> RustbotResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deploy commands to this guild or globally
|
/// Deploy commands to this guild or globally
|
||||||
#[poise::command(prefix_command)]
|
#[poise::command(prefix_command)]
|
||||||
async fn deploy(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
async fn deploy(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||||
poise::builtins::register_application_commands_buttons(ctx).await?;
|
poise::builtins::register_application_commands_buttons(ctx).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View how many servers the bot is in
|
/// View how many servers the bot is in
|
||||||
#[poise::command(prefix_command)]
|
#[poise::command(slash_command)]
|
||||||
async fn servers(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
async fn servers(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||||
poise::builtins::servers(ctx).await?;
|
poise::builtins::servers(ctx).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the status of available shards
|
/// View the status of available shards
|
||||||
#[poise::command(prefix_command)]
|
#[poise::command(slash_command)]
|
||||||
async fn shards(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
async fn shards(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||||
let shard_runners = ctx.framework().shard_manager().runners.clone();
|
let shard_runners = ctx.framework().shard_manager().runners.clone();
|
||||||
let runners = shard_runners.lock().await;
|
let runners = shard_runners.lock().await;
|
||||||
|
|
||||||
|
if runners.is_empty() {
|
||||||
|
ctx.reply("`ShardsReady` event hasn't fired yet!").await?;
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let mut shard_info = Vec::new();
|
let mut shard_info = Vec::new();
|
||||||
for (id, runner) in runners.iter() {
|
for (id, runner) in runners.iter() {
|
||||||
shard_info.push(format!(
|
let info = format_shard_info(id, runner, &ctx).await;
|
||||||
"**Shard {}**\n> Heartbeat: {}\n> Status: `{}`",
|
shard_info.push(info);
|
||||||
id,
|
|
||||||
match runner.latency {
|
|
||||||
Some(lat) => format!("`{}ms`", lat.as_millis()),
|
|
||||||
None => "Waiting for heartbeat...".to_string()
|
|
||||||
},
|
|
||||||
runner.stage
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.reply(shard_info.join("\n\n")).await?;
|
ctx.reply(shard_info.join("\n\n")).await?;
|
||||||
@ -58,11 +87,11 @@ async fn shards(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
|||||||
/// Turn your message into a bot message
|
/// Turn your message into a bot message
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(slash_command)]
|
||||||
async fn echo(
|
async fn echo(
|
||||||
ctx: super::PoiseContext<'_>,
|
ctx: RustbotContext<'_>,
|
||||||
#[description = "Message to be echoed as a bot"] message: String,
|
#[description = "Message to be echoed as a bot"] message: String,
|
||||||
#[description = "Channel to send this to"]
|
#[description = "Channel to send this to"]
|
||||||
#[channel_types("Text", "PublicThread", "PrivateThread")] channel: Option<ChannelId>
|
#[channel_types("Text", "PublicThread", "PrivateThread")] channel: Option<ChannelId>
|
||||||
) -> Result<(), RustbotError> {
|
) -> RustbotResult<()> {
|
||||||
ctx.defer_ephemeral().await?;
|
ctx.defer_ephemeral().await?;
|
||||||
|
|
||||||
let channel = match channel {
|
let channel = match channel {
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
use crate::RustbotError;
|
use rustbot_lib::{
|
||||||
use super::PoiseContext;
|
RustbotContext,
|
||||||
|
RustbotResult,
|
||||||
use rustbot_lib::config::BINARY_PROPERTIES;
|
config::BINARY_PROPERTIES
|
||||||
|
};
|
||||||
use poise::{
|
use poise::{
|
||||||
serenity_prelude::UserId,
|
serenity_prelude::UserId,
|
||||||
builtins::paginate
|
builtins::paginate
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(poise::ChoiceParameter)]
|
||||||
|
enum ResponseMode {
|
||||||
|
Normal,
|
||||||
|
Chicken
|
||||||
|
}
|
||||||
|
|
||||||
/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer
|
/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer
|
||||||
#[poise::command(
|
#[poise::command(
|
||||||
slash_command,
|
slash_command,
|
||||||
|
install_context = "Guild|User",
|
||||||
|
interaction_context = "Guild|BotDm|PrivateChannel",
|
||||||
rename = "8ball"
|
rename = "8ball"
|
||||||
)]
|
)]
|
||||||
pub async fn eightball(
|
pub async fn eightball(
|
||||||
ctx: PoiseContext<'_>,
|
ctx: RustbotContext<'_>,
|
||||||
#[description = "Your yes/no question"] question: String
|
#[description = "Your yes/no question"] question: String,
|
||||||
) -> Result<(), RustbotError> {
|
#[description = "Response modes"] mode: Option<ResponseMode>
|
||||||
if question.to_ascii_lowercase().contains("rustbot, show list") {
|
) -> RustbotResult<()> {
|
||||||
|
if question.to_ascii_lowercase().contains("niko, show list") {
|
||||||
if ctx.author().id == UserId::new(BINARY_PROPERTIES.developers[0]) {
|
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 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();
|
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
|
||||||
@ -29,7 +39,7 @@ pub async fn eightball(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if question.to_ascii_lowercase().contains("rustbot, show chicken list") {
|
if question.to_ascii_lowercase().contains("niko, show chicken list") {
|
||||||
if ctx.author().id == UserId::new(BINARY_PROPERTIES.developers[0]) {
|
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 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();
|
let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect();
|
||||||
@ -42,10 +52,9 @@ pub async fn eightball(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rand_resp = if question.to_ascii_lowercase().contains("chicken") {
|
let rand_resp = match mode {
|
||||||
get_random_chicken_response()
|
Some(ResponseMode::Chicken) => get_random_chicken_response(),
|
||||||
} else {
|
_ => get_random_response()
|
||||||
get_random_response()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.reply(format!("> {question}\n{rand_resp}")).await?;
|
ctx.reply(format!("> {question}\n{rand_resp}")).await?;
|
||||||
@ -53,7 +62,7 @@ pub async fn eightball(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const RESPONSES: [&str; 30] = [
|
const RESPONSES: [&str; 45] = [
|
||||||
"Reply hazy. Look it up on Google.", // no
|
"Reply hazy. Look it up on Google.", // no
|
||||||
"Meh — Figure it out yourself.", // no
|
"Meh — Figure it out yourself.", // no
|
||||||
"I don't know, what do you think?", // no
|
"I don't know, what do you think?", // no
|
||||||
@ -88,9 +97,24 @@ const RESPONSES: [&str; 30] = [
|
|||||||
"Sure, but with extreme cautions.", // yes
|
"Sure, but with extreme cautions.", // yes
|
||||||
"What kind of stupid question is that?? No! I'm not answering that!", // no
|
"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
|
"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; 35] = [
|
const CHICKEN_RESPONSES: [&str; 54] = [
|
||||||
"Cluck cluck... Reply hazy, try pecking Google.", // no
|
"Cluck cluck... Reply hazy, try pecking Google.", // no
|
||||||
"Meh... Figure it out yourself, or scratch around a bit.", // no
|
"Meh... Figure it out yourself, or scratch around a bit.", // no
|
||||||
"I don't know... what do you think? *pecks at ground*", // no
|
"I don't know... what do you think? *pecks at ground*", // no
|
||||||
@ -126,6 +150,25 @@ const CHICKEN_RESPONSES: [&str; 35] = [
|
|||||||
"Yes! *lays egg of approval*", // yes
|
"Yes! *lays egg of approval*", // yes
|
||||||
"It's a no, better go scratch somewhere else.", // no
|
"It's a no, better go scratch somewhere else.", // no
|
||||||
"Cluck-tastic! That's a definite yes.", // yes
|
"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 {
|
fn get_random_response() -> &'static str {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::RustbotError;
|
|
||||||
use super::PoiseContext;
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use rustbot_lib::{
|
||||||
|
RustbotContext,
|
||||||
|
RustbotResult
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct StatusPage {
|
struct StatusPage {
|
||||||
@ -18,9 +19,13 @@ struct Summary {
|
|||||||
mean: f64
|
mean: f64
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check latency of the bot's WS connection and Discord's API
|
/// Check latency between bot and WebSocket as well as Discord's API latency
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(
|
||||||
pub async fn ping(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
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")
|
let statuspage: StatusPage = reqwest::get("https://discordstatus.com/metrics-display/5k2rt9f7pmny/day.json")
|
||||||
.await.unwrap()
|
.await.unwrap()
|
||||||
.json()
|
.json()
|
||||||
@ -29,6 +34,7 @@ pub async fn ping(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
|||||||
let mut latencies = Vec::new();
|
let mut latencies = Vec::new();
|
||||||
latencies.push(format!("Discord: `{:.0?}ms`", statuspage.metrics[0].summary.mean));
|
latencies.push(format!("Discord: `{:.0?}ms`", statuspage.metrics[0].summary.mean));
|
||||||
latencies.push(format!("WebSocket: `{:.0?}`", ctx.ping().await));
|
latencies.push(format!("WebSocket: `{:.0?}`", ctx.ping().await));
|
||||||
|
latencies.push(format!("Shard ID: `{}`", ctx.serenity_context().shard_id));
|
||||||
|
|
||||||
ctx.reply(latencies.join("\n")).await?;
|
ctx.reply(latencies.join("\n")).await?;
|
||||||
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
use crate::RustbotError;
|
|
||||||
use super::PoiseContext;
|
|
||||||
|
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
use uptime_lib::get;
|
use uptime_lib::get;
|
||||||
use std::{
|
use std::{
|
||||||
@ -17,11 +14,15 @@ use std::{
|
|||||||
BufReader
|
BufReader
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
use rustbot_lib::utils::{
|
use rustbot_lib::{
|
||||||
|
RustbotContext,
|
||||||
|
RustbotResult,
|
||||||
|
utils::{
|
||||||
BOT_VERSION,
|
BOT_VERSION,
|
||||||
GIT_COMMIT_HASH,
|
GIT_COMMIT_HASH,
|
||||||
GIT_COMMIT_BRANCH,
|
GIT_COMMIT_BRANCH,
|
||||||
format_duration
|
format_duration
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_os_info() -> String {
|
fn get_os_info() -> String {
|
||||||
@ -63,7 +64,7 @@ fn fmt_mem(bytes: u64) -> String {
|
|||||||
|
|
||||||
/// Retrieve host and bot uptimes
|
/// Retrieve host and bot uptimes
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(slash_command)]
|
||||||
pub async fn uptime(ctx: PoiseContext<'_>) -> Result<(), RustbotError> {
|
pub async fn uptime(ctx: RustbotContext<'_>) -> RustbotResult<()> {
|
||||||
let bot = ctx.http().get_current_user().await.unwrap();
|
let bot = ctx.http().get_current_user().await.unwrap();
|
||||||
let mut sys = System::new_all();
|
let mut sys = System::new_all();
|
||||||
sys.refresh_all();
|
sys.refresh_all();
|
||||||
|
24
src/main.rs
24
src/main.rs
@ -1,8 +1,9 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
|
mod shutdown;
|
||||||
// https://cdn.toast-server.net/RustFSHiearchy.png
|
// https://cdn.toast-server.net/RustFSHiearchy.png
|
||||||
// Using the new filesystem hierarchy
|
// Using the new filesystem hierarchy
|
||||||
|
|
||||||
use rustbot_tokens::token_path;
|
use rustbot_tokens::discord_token;
|
||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
builder::CreateAllowedMentions,
|
builder::CreateAllowedMentions,
|
||||||
ClientBuilder,
|
ClientBuilder,
|
||||||
@ -14,7 +15,6 @@ use rustbot_lib::{
|
|||||||
mention_dev,
|
mention_dev,
|
||||||
get_guild_name
|
get_guild_name
|
||||||
},
|
},
|
||||||
RustbotError,
|
|
||||||
RustbotData,
|
RustbotData,
|
||||||
config::BINARY_PROPERTIES
|
config::BINARY_PROPERTIES
|
||||||
};
|
};
|
||||||
@ -47,20 +47,19 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Discord[{}:S{}]: {} ran {}{} {}",
|
"Discord[{}:S{}]: {} ran {prefix}{} {get_guild_channel_name}",
|
||||||
get_guild_name(ctx),
|
get_guild_name(ctx),
|
||||||
ctx.serenity_context().shard_id,
|
ctx.serenity_context().shard_id,
|
||||||
ctx.author().name,
|
ctx.author().name,
|
||||||
prefix,
|
|
||||||
ctx.command().qualified_name,
|
ctx.command().qualified_name,
|
||||||
get_guild_channel_name);
|
);
|
||||||
}),
|
}),
|
||||||
prefix_options: poise::PrefixFrameworkOptions {
|
prefix_options: poise::PrefixFrameworkOptions {
|
||||||
prefix,
|
prefix,
|
||||||
case_insensitive_commands: true,
|
|
||||||
ignore_bots: true,
|
ignore_bots: true,
|
||||||
execute_self_messages: false,
|
|
||||||
mention_as_prefix: false,
|
mention_as_prefix: false,
|
||||||
|
case_insensitive_commands: true,
|
||||||
|
execute_self_messages: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
on_error: |error| Box::pin(async move {
|
on_error: |error| Box::pin(async move {
|
||||||
@ -118,7 +117,7 @@ async fn main() {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut client = ClientBuilder::new(
|
let mut client = ClientBuilder::new(
|
||||||
&token_path().await.main,
|
discord_token().await,
|
||||||
GatewayIntents::GUILDS
|
GatewayIntents::GUILDS
|
||||||
| GatewayIntents::GUILD_MESSAGES
|
| GatewayIntents::GUILD_MESSAGES
|
||||||
| GatewayIntents::MESSAGE_CONTENT
|
| GatewayIntents::MESSAGE_CONTENT
|
||||||
@ -128,7 +127,14 @@ async fn main() {
|
|||||||
.activity(ActivityData::custom("nep nep!"))
|
.activity(ActivityData::custom("nep nep!"))
|
||||||
.await.expect("Error creating client");
|
.await.expect("Error creating client");
|
||||||
|
|
||||||
|
let shard_manager = client.shard_manager.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
shutdown::gracefully_shutdown().await;
|
||||||
|
shard_manager.shutdown_all().await;
|
||||||
|
});
|
||||||
|
|
||||||
if let Err(why) = client.start_autosharded().await {
|
if let Err(why) = client.start_autosharded().await {
|
||||||
println!("Error starting client: {:#?}", why);
|
println!("Error starting client: {why:#?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/shutdown.rs
Normal file
23
src/shutdown.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use tokio::{
|
||||||
|
select,
|
||||||
|
signal::unix::{
|
||||||
|
signal,
|
||||||
|
SignalKind
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn gracefully_shutdown() {
|
||||||
|
let [mut s1, mut s2, mut s3] = [
|
||||||
|
signal(SignalKind::interrupt()).unwrap(),
|
||||||
|
signal(SignalKind::terminate()).unwrap(),
|
||||||
|
signal(SignalKind::hangup()).unwrap()
|
||||||
|
];
|
||||||
|
|
||||||
|
select!(
|
||||||
|
v = s1.recv() => v.unwrap(),
|
||||||
|
v = s2.recv() => v.unwrap(),
|
||||||
|
v = s3.recv() => v.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nRustbot says goodbye! 👋");
|
||||||
|
}
|
@ -6,6 +6,6 @@ Only things that are needing to be changed before deploying this template to rea
|
|||||||
- library (rustbot_lib), and its references
|
- library (rustbot_lib), and its references
|
||||||
- tsclient (rustbot_tokens), and its references
|
- tsclient (rustbot_tokens), and its references
|
||||||
|
|
||||||
Search by Rustbot in its usual form (all-caps, pascalcase, and such) to find all the references that need to be changed too.
|
Search by Rustbot in its usual form (ALL-CAPS, PascalCase, and such) to find all the references that need to be changed too.
|
||||||
|
|
||||||
(and delete this file too!)
|
(and delete this file too!)
|
||||||
|
@ -4,5 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
poise = { workspace = true }
|
||||||
tokenservice-client = { version = "0.4.1", registry = "gitea" }
|
tokenservice-client = { version = "0.4.1", registry = "gitea" }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
use std::sync::LazyLock;
|
use poise::serenity_prelude::Token;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
use std::{
|
||||||
|
str::FromStr,
|
||||||
|
sync::LazyLock
|
||||||
|
};
|
||||||
use tokenservice_client::{
|
use tokenservice_client::{
|
||||||
TokenService,
|
TokenService,
|
||||||
TokenServiceApi
|
TokenServiceApi
|
||||||
@ -33,3 +37,8 @@ static TSCLIENT: LazyLock<Mutex<TSClient>> = LazyLock::new(|| Mutex::new(TSClien
|
|||||||
pub async fn token_path() -> TokenServiceApi {
|
pub async fn token_path() -> TokenServiceApi {
|
||||||
TSCLIENT.lock().await.get().await.unwrap()
|
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!")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user