Crate sparkle_convenience
source ·Expand description
A wrapper over Twilight that’s designed to be convenient to use, without relying on callbacks and mostly following Twilight patterns while making your life easier
Concise Startup
use sparkle_convenience::Bot;
Bot::new(
"forgot to leak my token".to_owned(),
Intents::GUILD_MESSAGES,
EventTypeFlags::INTERACTION_CREATE,
)
.await?;
Yes that’s really it… Bot
has all the things you’d need from Twilight
Interaction Handling
use sparkle_convenience::{
error::conversion::IntoError,
interaction::extract::{InteractionDataExt, InteractionExt},
reply::Reply,
Bot,
};
let handle = bot.interaction_handle(&interaction);
match interaction.name().ok()? {
"pay_respects" => {
handle.defer(true).await?;
// More on error handling below
handle.check_permissions(Permissions::MANAGE_GUILD)?;
// Say this is a user command
let _very_respected_user = interaction.data.ok()?.command().ok()?.target_id.ok()?;
// There are similar methods for autocomplete and modal responses
handle
.followup(
Reply::new()
.ephemeral()
.content("You have -1 respect now".to_owned()),
)
.await?;
}
_ => {}
}
Error Handling
User-Facing Errors
use sparkle_convenience::{
error::{conversion::IntoError, ErrorExt, UserError},
http::message::CreateMessageExt,
prettify::Prettify,
reply::Reply,
};
async fn wave(
client: &Client,
channel_id: Id<ChannelMarker>,
message_id: Id<MessageMarker>,
) -> Result<()> {
client
.create_reaction(
channel_id,
message_id,
&RequestReactionType::Unicode { name: "👋" },
)
.await?;
Ok(())
}
async fn handle_message(client: &Client, message: Message) -> Result<()> {
if let Err(mut err) = wave(client, message.channel_id, message.id).await {
// For example if the message was already deleted (probably by some moderation bot..)
if err.ignore() {
return Ok(());
}
// Not needed in interactions thanks to `InteractionHandle::check_permissions`
err.with_permissions(Permissions::READ_MESSAGE_HISTORY | Permissions::ADD_REACTIONS);
client
.create_message(message.channel_id)
.with_reply(&err_reply(&err))?
.execute_ignore_permissions()
.await?;
// `CustomError` is for your own errors
if let Some(err) = err.internal::<CustomError>() {
return Err(err);
}
}
Ok(())
}
// Returns a reply that you can conveniently use in messages, interactions, even webhooks
fn err_reply(err: &anyhow::Error) -> Reply {
let message = if let Some(UserError::MissingPermissions(permissions)) = err.user() {
format!(
"Give me those sweet permissions:\n{}",
permissions.unwrap().prettify() // Also provided by this crate
)
} else {
"Uh oh...".to_owned()
};
Reply::new().ephemeral().content(message)
}
Internal Errors
use sparkle_convenience::Bot;
bot.set_logging_channel(Id::new(123)).await?;
bot.set_logging_file("log.txt".to_owned());
if let Err(err) = handle_event().await {
// Executes a webhook in the channel
// (error message is in an attachment so don't worry if it's too long)
// And appends the error to the file
bot.log(format!("{err:?}")).await;
};
DMs
use sparkle_convenience::http::HttpExt;
client
.dm_user(user_id)
.await?
.content("This bot is brought to you by Skillshare")?
.await?;
Modules
Convenient error handling
Making HTTP requests conveniently
Convenient interaction handling
Formatting types into user-readable pretty strings
The
reply::Reply
structStructs
All data required to make a bot run