User-App support
All checks were successful
Build and push Docker image / build (push) Successful in 7m22s
Build and push Docker image / deploy (push) Successful in 1m7s

This commit is contained in:
toast 2024-11-20 03:42:58 +11:00
parent f98eb4fd7b
commit 47453acecd
15 changed files with 507 additions and 205 deletions

564
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,27 @@
[package] [package]
name = "kon" name = "kon"
version = "0.4.1" version = "0.5.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
bb8 = "0.8.5" bb8 = "0.8.6"
bb8-redis = "0.17.0" bb8-redis = "0.17.0"
cargo_toml = "0.20.5" cargo_toml = "0.20.5"
feed-rs = "2.1.1" feed-rs = "2.2.0"
once_cell = "1.20.2" once_cell = "1.20.2"
poise = "0.6.1" poise = "0.6.1"
regex = "1.11.0" regex = "1.11.1"
reqwest = { version = "0.12.8", features = ["json", "native-tls-vendored"] } reqwest = { version = "0.12.9", features = ["json", "native-tls-vendored"] }
serde = "1.0.210" serde = "1.0.215"
serde_json = "1.0.128" serde_json = "1.0.133"
sysinfo = "0.32.0" sysinfo = "0.32.0"
tokenservice-client = { version = "0.4.0", registry = "gitea" } tokenservice-client = { version = "0.4.0", registry = "gitea" }
tokio = { version = "1.40.0", features = ["macros", "signal", "rt-multi-thread"] } tokio = { version = "1.41.1", features = ["macros", "signal", "rt-multi-thread"] }
uptime_lib = "0.3.1" uptime_lib = "0.3.1"
[patch.crates-io]
poise = { git = "https://github.com/serenity-rs/poise", branch = "next" }
[features] [features]
production = [] production = []

View File

@ -8,7 +8,7 @@ services:
- cache - cache
cache: cache:
container_name: kon-redis container_name: kon-redis
image: redis/redis-stack-server:7.4.0-v0 image: redis/redis-stack-server:7.4.0-v1
restart: unless-stopped restart: unless-stopped
ports: ports:
- 37935:6379/tcp - 37935:6379/tcp

View File

@ -6,13 +6,15 @@ pub mod ping;
pub mod status; pub mod status;
pub mod uptime; pub mod uptime;
type PoiseCtx<'a> = poise::Context<'a, (), Error>;
/// Deploy the commands globally or in a guild /// Deploy the commands globally or in a guild
#[poise::command( #[poise::command(
prefix_command, prefix_command,
owners_only, owners_only,
guild_only guild_only
)] )]
pub async fn deploy(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn deploy(ctx: PoiseCtx<'_>) -> Result<(), Error> {
poise::builtins::register_application_commands_buttons(ctx).await?; poise::builtins::register_application_commands_buttons(ctx).await?;
Ok(()) Ok(())
} }

View File

@ -187,15 +187,17 @@ async fn ilo_data(endpoint: RedfishEndpoint) -> Result<Box<dyn std::any::Any + S
/// Retrieve data from the HP iLO4 interface /// Retrieve data from the HP iLO4 interface
#[poise::command( #[poise::command(
slash_command, slash_command,
install_context = "Guild|User",
interaction_context = "Guild|BotDm|PrivateChannel",
subcommands("temperature", "power", "system") subcommands("temperature", "power", "system")
)] )]
pub async fn ilo(_: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn ilo(_: super::PoiseCtx<'_>) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Retrieve the server's temperature data /// Retrieve the server's temperature data
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn temperature(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
ctx.defer().await?; ctx.defer().await?;
let ilo = ilo_data(RedfishEndpoint::Thermal).await.unwrap(); let ilo = ilo_data(RedfishEndpoint::Thermal).await.unwrap();
let data = ilo.downcast_ref::<Chassis>().unwrap(); let data = ilo.downcast_ref::<Chassis>().unwrap();
@ -246,7 +248,7 @@ pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error
/// Retrieve the server's power data /// Retrieve the server's power data
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn power(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn power(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
ctx.defer().await?; ctx.defer().await?;
let ilo = ilo_data(RedfishEndpoint::Power).await.unwrap(); let ilo = ilo_data(RedfishEndpoint::Power).await.unwrap();
let data = ilo.downcast_ref::<Power>().unwrap(); let data = ilo.downcast_ref::<Power>().unwrap();
@ -272,7 +274,7 @@ pub async fn power(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
/// Retrieve the server's system data /// Retrieve the server's system data
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn system(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn system(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
ctx.defer().await?; ctx.defer().await?;
let (ilo_sys, ilo_event) = tokio::join!( let (ilo_sys, ilo_event) = tokio::join!(

View File

@ -21,9 +21,13 @@ use poise::{
}; };
/// Convert MIDI file to WAV /// Convert MIDI file to WAV
#[poise::command(context_menu_command = "MIDI -> WAV")] #[poise::command(
context_menu_command = "MIDI -> WAV",
install_context = "User",
interaction_context = "Guild|BotDm|PrivateChannel",
)]
pub async fn midi_to_wav( pub async fn midi_to_wav(
ctx: poise::Context<'_, (), Error>, ctx: super::PoiseCtx<'_>,
#[description = "MIDI file to be converted"] message: poise::serenity_prelude::Message #[description = "MIDI file to be converted"] message: poise::serenity_prelude::Message
) -> Result<(), Error> { ) -> Result<(), Error> {
let re = Regex::new(r"(?i)\.mid$").unwrap(); let re = Regex::new(r"(?i)\.mid$").unwrap();
@ -46,7 +50,7 @@ pub async fn midi_to_wav(
) )
.await.unwrap(); .await.unwrap();
return Err(Error::from(format!("Failed to download the file: {}", y))) return Err(Error::from(format!("Failed to download the file: {y}")))
} }
}; };
@ -63,7 +67,7 @@ pub async fn midi_to_wav(
.output(); .output();
// Just to add an info to console to tell what the bot is doing when MIDI file is downloaded. // Just to add an info to console to tell what the bot is doing when MIDI file is downloaded.
println!("Discord[{}:{}]: Processing MIDI file: \"{}\"", ctx.guild().unwrap().name, ctx.command().qualified_name, midi_path); println!("Discord[{}]: Processing MIDI file: \"{}\"", ctx.command().qualified_name, midi_path);
match output { match output {
Ok(_) => { Ok(_) => {
@ -73,8 +77,8 @@ pub async fn midi_to_wav(
if reply.is_err() { if reply.is_err() {
println!( println!(
"Discord[{}:{}]: Processed file couldn't be uploaded back to Discord channel due to upload limit", "Discord[{}]: Processed file couldn't be uploaded back to Discord channel due to upload limit",
ctx.guild().unwrap().name, ctx.command().qualified_name ctx.command().qualified_name
); );
ctx.send(CreateReply::default() ctx.send(CreateReply::default()
@ -93,7 +97,7 @@ pub async fn midi_to_wav(
.content("Command didn't execute successfully, check console for more information!") .content("Command didn't execute successfully, check console for more information!")
).await.unwrap(); ).await.unwrap();
return Err(Error::from(format!("Midi conversion failed: {}", y))) return Err(Error::from(format!("Midi conversion failed: {y}")))
} }
} }

View File

@ -2,7 +2,7 @@ use crate::Error;
/// Check if the bot is alive /// Check if the bot is alive
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn ping(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn ping(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
ctx.reply(format!("Powong! `{:?}`", ctx.ping().await)).await?; ctx.reply(format!("Powong! `{:?}`", ctx.ping().await)).await?;
Ok(()) Ok(())
} }

View File

@ -71,13 +71,13 @@ fn process_pms_statuses(servers: Vec<(String, Vec<Value>)>) -> Vec<(String, Stri
slash_command, slash_command,
subcommands("wg") subcommands("wg")
)] )]
pub async fn status(_: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn status(_: super::PoiseCtx<'_>) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Retrieve the server statuses from Wargaming /// Retrieve the server statuses from Wargaming
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn wg(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn wg(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
let pms_asia = token_path().await.wg_pms; let pms_asia = token_path().await.wg_pms;
let pms_eu = pms_asia.replace("asia", "eu"); let pms_eu = pms_asia.replace("asia", "eu");
let embed = CreateEmbed::new().color(BINARY_PROPERTIES.embed_color); let embed = CreateEmbed::new().color(BINARY_PROPERTIES.embed_color);

View File

@ -42,12 +42,12 @@ fn get_os_info() -> String {
}); });
} }
format!("{} {}", name, version) format!("{name} {version}")
} }
/// Retrieve host and bot uptimes /// Retrieve host and bot uptimes
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn uptime(ctx: super::PoiseCtx<'_>) -> Result<(), Error> {
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();
@ -68,7 +68,7 @@ pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
} }
let stat_msg = [ let stat_msg = [
format!("**{} {}** `{}:{}`", _bot.name, BOT_VERSION.as_str(), GIT_COMMIT_HASH, GIT_COMMIT_BRANCH), format!("**{} {}** `{GIT_COMMIT_HASH}:{GIT_COMMIT_BRANCH}`", _bot.name, BOT_VERSION.as_str()),
format!(">>> System: `{}`", format_duration(sys_uptime)), format!(">>> System: `{}`", format_duration(sys_uptime)),
format!("Process: `{}`", format_duration(proc_uptime)), format!("Process: `{}`", format_duration(proc_uptime)),
format!("CPU: `{}`", cpu[0].brand()), format!("CPU: `{}`", cpu[0].brand()),

View File

@ -27,6 +27,7 @@ impl RedisController {
async fn create_pool(manager: RedisConnectionManager) -> Pool<RedisConnectionManager> { async fn create_pool(manager: RedisConnectionManager) -> Pool<RedisConnectionManager> {
let mut backoff = 1; let mut backoff = 1;
let redis_err = "Redis[Error]: {{ e }}, retrying in {{ backoff }} seconds";
loop { loop {
match Pool::builder().max_size(20).retry_connection(true).build(manager.clone()).await { match Pool::builder().max_size(20).retry_connection(true).build(manager.clone()).await {
@ -40,19 +41,19 @@ impl RedisController {
return pool.clone(); return pool.clone();
}, },
Err(e) => { Err(e) => {
eprintln!("Redis[Error]: {}, retrying in {} seconds", e, backoff); eprintln!("{}", redis_err.replace("{{ e }}", &e.to_string()).replace("{{ backoff }}", &backoff.to_string()));
Self::apply_backoff(&mut backoff).await; Self::apply_backoff(&mut backoff).await;
} }
} }
}, },
Err(e) => { Err(e) => {
eprintln!("Redis[ConnError]: {}, retrying in {} seconds", e, backoff); eprintln!("{}", redis_err.replace("{{ e }}", &e.to_string()).replace("{{ backoff }}", &backoff.to_string()));
Self::apply_backoff(&mut backoff).await; Self::apply_backoff(&mut backoff).await;
} }
} }
} }
Err(e) => { Err(e) => {
eprintln!("Redis[PoolError]: {}, retrying in {} seconds", e, backoff); eprintln!("Redis[PoolError]: {e}, retrying in {backoff} seconds");
Self::apply_backoff(&mut backoff).await; Self::apply_backoff(&mut backoff).await;
} }
} }

View File

@ -1,6 +1,7 @@
use std::sync::LazyLock; use std::sync::LazyLock;
pub struct ConfigMeta { pub struct ConfigMeta {
pub env: String,
pub embed_color: i32, pub embed_color: i32,
pub ready_notify: u64, pub ready_notify: u64,
pub rss_channel: u64, pub rss_channel: u64,
@ -14,6 +15,7 @@ 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("dev")
.embed_color(0xf1d63c) .embed_color(0xf1d63c)
.ready_notify(865673694184996888) .ready_notify(865673694184996888)
.rss_channel(865673694184996888) .rss_channel(865673694184996888)
@ -22,6 +24,7 @@ pub static BINARY_PROPERTIES: LazyLock<ConfigMeta> = LazyLock::new(||
impl ConfigMeta { impl ConfigMeta {
fn new() -> Self { fn new() -> Self {
Self { Self {
env: "prod".to_string(),
embed_color: 0x5a99c7, embed_color: 0x5a99c7,
ready_notify: 865673694184996888, ready_notify: 865673694184996888,
rss_channel: 865673694184996888, rss_channel: 865673694184996888,
@ -33,6 +36,12 @@ impl ConfigMeta {
} }
// Scalable functions below; // Scalable functions below;
#[cfg(not(feature = "production"))]
fn env(mut self, env: &str) -> Self {
self.env = env.to_string();
self
}
#[cfg(not(feature = "production"))] #[cfg(not(feature = "production"))]
fn embed_color(mut self, color: i32) -> Self { fn embed_color(mut self, color: i32) -> Self {
self.embed_color = color; self.embed_color = color;

View File

@ -17,7 +17,7 @@ impl HttpClient {
pub async fn get(&self, url: &str, ua: &str) -> Result<Response, Error> { pub async fn get(&self, url: &str, ua: &str) -> Result<Response, Error> {
let response = self.0.get(url).header( let response = self.0.get(url).header(
reqwest::header::USER_AGENT, reqwest::header::USER_AGENT,
format!("Kon ({}-{}) - {}/reqwest", super::utils::BOT_VERSION.as_str(), crate::GIT_COMMIT_HASH, ua) format!("Kon ({}-{}) - {ua}/reqwest", super::utils::BOT_VERSION.as_str(), crate::GIT_COMMIT_HASH)
) )
.timeout(Duration::from_secs(30)) .timeout(Duration::from_secs(30))
.send() .send()
@ -26,11 +26,11 @@ impl HttpClient {
match response { match response {
Ok(res) => Ok(res), Ok(res) => Ok(res),
Err(y) if y.is_timeout() => { Err(y) if y.is_timeout() => {
eprintln!("{ERROR_PREFIX} Request timed out for \"{}\"", url); eprintln!("{ERROR_PREFIX} Request timed out for \"{url}\"");
Err(y) Err(y)
}, },
Err(y) if y.is_connect() => { Err(y) if y.is_connect() => {
eprintln!("{ERROR_PREFIX} Connection failed for \"{}\"", url); eprintln!("{ERROR_PREFIX} Connection failed for \"{url}\"");
Err(y) Err(y)
}, },
Err(y) => Err(y) Err(y) => Err(y)

View File

@ -16,11 +16,11 @@ use std::{
}; };
fn task_info(name: &str, message: &str) { fn task_info(name: &str, message: &str) {
println!("TaskScheduler[{}]: {}", name, message) println!("TaskScheduler[{name}]: {message}")
} }
fn task_err(name: &str, message: &str) { fn task_err(name: &str, message: &str) {
eprintln!("TaskScheduler[{}:Error]: {}", name, message) eprintln!("TaskScheduler[{name}:Error]: {message}")
} }
static TASK_RUNNING: AtomicBool = AtomicBool::new(false); static TASK_RUNNING: AtomicBool = AtomicBool::new(false);
@ -36,9 +36,9 @@ where
TASK_RUNNING.store(true, Ordering::SeqCst); TASK_RUNNING.store(true, Ordering::SeqCst);
spawn(async move { spawn(async move {
if let Err(y) = task(ctx_cl).await { if let Err(y) = task(ctx_cl).await {
eprintln!("TaskScheduler[Main:Error]: Failed to execute the task, error reason: {}", y); eprintln!("TaskScheduler[Main:Error]: Failed to execute the task, error reason: {y}");
if let Some(source) = y.source() { if let Some(source) = y.source() {
eprintln!("TaskScheduler[Main:Error]: Failed to execute the task, this is caused by: {:#?}", source); eprintln!("TaskScheduler[Main:Error]: Failed to execute the task, this is caused by: {source:#?}");
} }
} }
TASK_RUNNING.store(false, Ordering::SeqCst); TASK_RUNNING.store(false, Ordering::SeqCst);

View File

@ -11,7 +11,7 @@ pub static BOT_VERSION: LazyLock<String> = LazyLock::new(|| {
.unwrap() .unwrap()
.version .version
.unwrap(); .unwrap();
format!("v{}", cargo_version) format!("v{cargo_version}")
}); });
static TSCLIENT: LazyLock<Mutex<TSClient>> = LazyLock::new(|| Mutex::new(TSClient::new())); static TSCLIENT: LazyLock<Mutex<TSClient>> = LazyLock::new(|| Mutex::new(TSClient::new()));
@ -28,7 +28,7 @@ pub fn mention_dev(ctx: poise::Context<'_, (), crate::Error>) -> Option<String>
for dev in devs { for dev in devs {
if app_owners.contains(&UserId::new(dev)) { if app_owners.contains(&UserId::new(dev)) {
mentions.push(format!("<@{}>", dev)); mentions.push(format!("<@{dev}>"));
} }
} }
@ -47,15 +47,15 @@ pub fn format_duration(secs: u64) -> String {
let mut formatted_string = String::new(); let mut formatted_string = String::new();
if days > 0 { if days > 0 {
formatted_string.push_str(&format!("{}d, ", days)); formatted_string.push_str(&format!("{days}d, "));
} }
if hours > 0 || days > 0 { if hours > 0 || days > 0 {
formatted_string.push_str(&format!("{}h, ", hours)); formatted_string.push_str(&format!("{hours}h, "));
} }
if minutes > 0 || hours > 0 { if minutes > 0 || hours > 0 {
formatted_string.push_str(&format!("{}m, ", minutes)); formatted_string.push_str(&format!("{minutes}m, "));
} }
formatted_string.push_str(&format!("{}s", seconds)); formatted_string.push_str(&format!("{seconds}s"));
formatted_string formatted_string
} }
@ -75,8 +75,8 @@ pub fn format_bytes(bytes: u64) -> String {
} }
if unit == "B" { if unit == "B" {
format!("{}{}", value, unit) format!("{value}{unit}")
} else { } else {
format!("{:.2}{}", value, unit) format!("{value:.2}{unit}")
} }
} }

View File

@ -19,6 +19,7 @@ use crate::internals::{
use std::{ use std::{
sync::Arc, sync::Arc,
borrow::Cow,
thread::current thread::current
}; };
use poise::serenity_prelude::{ use poise::serenity_prelude::{
@ -57,7 +58,7 @@ async fn on_ready(
println!("Event[Ready][Notice]: Session limit: {}/{}", session.remaining, session.total); println!("Event[Ready][Notice]: Session limit: {}/{}", session.remaining, session.total);
} }
println!("Event[Ready]: Build version: {} ({}:{})", *BOT_VERSION, GIT_COMMIT_HASH, GIT_COMMIT_BRANCH); println!("Event[Ready]: Build version: {} ({GIT_COMMIT_HASH}:{GIT_COMMIT_BRANCH})", *BOT_VERSION);
println!("Event[Ready]: Connected to API as {}", ready.user.name); println!("Event[Ready]: Connected to API as {}", ready.user.name);
let message = CreateMessage::new(); let message = CreateMessage::new();
@ -72,16 +73,15 @@ async fn on_ready(
} }
async fn event_processor( async fn event_processor(
ctx: &Context, framework: poise::FrameworkContext<'_, (), Error>,
event: &FullEvent, event: &FullEvent
_framework: poise::FrameworkContext<'_, (), Error>
) -> Result<(), Error> { ) -> Result<(), Error> {
if let FullEvent::Ready { .. } = event { if let FullEvent::Ready { .. } = event {
let thread_id = format!("{:?}", current().id()); let thread_id = format!("{:?}", current().id());
let thread_num: String = thread_id.chars().filter(|c| c.is_ascii_digit()).collect(); let thread_num: String = thread_id.chars().filter(|c| c.is_ascii_digit()).collect();
println!("Event[Ready]: Task Scheduler operating on thread {}", thread_num); println!("Event[Ready]: Task Scheduler operating on thread {thread_num}");
let ctx = Arc::new(ctx.clone()); let ctx = Arc::new(framework.serenity_context.clone());
run_task(ctx.clone(), rss).await; run_task(ctx.clone(), rss).await;
} }
@ -90,6 +90,12 @@ async fn event_processor(
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let prefix = if BINARY_PROPERTIES.env.contains("dev") {
Some(Cow::Borrowed("kon!"))
} else {
Some(Cow::Borrowed("k!"))
};
let framework = poise::Framework::builder() let framework = poise::Framework::builder()
.options(poise::FrameworkOptions { .options(poise::FrameworkOptions {
commands: vec![ commands: vec![
@ -101,7 +107,7 @@ async fn main() {
commands::uptime::uptime() commands::uptime::uptime()
], ],
prefix_options: poise::PrefixFrameworkOptions { prefix_options: poise::PrefixFrameworkOptions {
prefix: Some(String::from("konata")), prefix,
mention_as_prefix: false, mention_as_prefix: false,
case_insensitive_commands: true, case_insensitive_commands: true,
ignore_bots: true, ignore_bots: true,
@ -113,29 +119,32 @@ async fn main() {
Some(guild) => guild.name.clone(), Some(guild) => guild.name.clone(),
None => String::from("Direct Message") None => String::from("Direct Message")
}; };
println!("Discord[{}]: {} ran /{}", get_guild_name, ctx.author().name, ctx.command().qualified_name); println!(
"Discord[{get_guild_name}]: {} ran /{}",
ctx.author().name,
ctx.command().qualified_name
);
}), }),
on_error: |error| Box::pin(async move { on_error: |error| Box::pin(async move {
match error { match error {
poise::FrameworkError::Command { error, ctx, .. } => { poise::FrameworkError::Command { error, ctx, .. } => {
println!("PoiseCommandError({}): {}", ctx.command().qualified_name, error); println!("PoiseCommandError({}): {error}", ctx.command().qualified_name);
ctx.reply(format!( ctx.reply(format!(
"Encountered an error during command execution, ask {} to check console for more details!", "Encountered an error during command execution, ask {} to check console for more details!",
mention_dev(ctx).unwrap_or_default() mention_dev(ctx).unwrap_or_default()
)).await.expect("Error sending message"); )).await.expect("Error sending message");
}, },
poise::FrameworkError::EventHandler { error, event, .. } => println!("PoiseEventHandlerError({}): {}", event.snake_case_name(), error), poise::FrameworkError::EventHandler { error, event, .. } => println!("PoiseEventHandlerError({}): {error}", event.snake_case_name()),
poise::FrameworkError::Setup { error, .. } => println!("PoiseSetupError: {}", error),
poise::FrameworkError::UnknownInteraction { interaction, .. } => println!( poise::FrameworkError::UnknownInteraction { interaction, .. } => println!(
"PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})", "PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})",
interaction.user.name, interaction.user.name,
interaction.data.name interaction.data.name
), ),
other => println!("PoiseOtherError: {}", other) other => println!("PoiseOtherError: {other}")
} }
}), }),
initialize_owners: true, initialize_owners: true,
event_handler: |ctx, event, framework, _| Box::pin(event_processor(ctx, event, framework)), event_handler: |framework, event| Box::pin(event_processor(framework, event)),
..Default::default() ..Default::default()
}) })
.setup(|ctx, ready, framework| Box::pin(on_ready(ctx, ready, framework))) .setup(|ctx, ready, framework| Box::pin(on_ready(ctx, ready, framework)))
@ -151,6 +160,6 @@ async fn main() {
.await.expect("Error creating client"); .await.expect("Error creating client");
if let Err(why) = client.start().await { if let Err(why) = client.start().await {
println!("Error starting client: {:#?}", why); println!("Error starting client: {why:#?}");
} }
} }