#twilight #discord #third-party #discord-api #sticker #reaction

sparkle-impostor

A third party crate for Twilight to execute Discord webhooks that clone an existing message

1 unstable release

0.15.0 Aug 11, 2023

#1043 in Asynchronous

ISC license

64KB
1K SLoC

โœจ๐Ÿฅธ Sparkle Impostor

A third party crate for Twilight to execute Discord webhooks that clone an existing message

โœจ Features

This has grown to be a more complicated (and painful) project than expected, so let me list what it does

Opt-in features for edge-cases:

  • Clone attachments or stickers by linking to them or re-uploading them
  • Clone URL components
  • Clone messages sent after the original message, even combining them to reduce webhook executions
  • Clone reactions
  • Clone references by putting an embed
  • Clone messages in a thread/forum post or messages used to start a thread/forum post
  • Sanitize invalid usernames
  • Delete the original message and messages sent after

General features:

  • Replicate the author's user or member avatar, embeds, anything possible
  • Change any info about the new message, for example to clone to another channel
  • Handle rate-limit retries
  • Builder-pattern to keep your code clean
  • Avoid clones and unnecessary deserialization
  • Widely tested with integration tests (Almost 1:1 LOC for source and tests)

๐Ÿ˜‹ A Taste of Sparkle Impostor

This also serves as the example, since it includes most of the API surface

let mut source = MessageSource::from_message(&message, &http)
    .expect("message really can't be cloned (voice message etc)");

// example error handling
if let Err(_) = source.check_component() {
    panic!("invalid components scare me");
}

let later_messages = source.later_messages_batched().await?;

// a lot of edge cases
source
    .webhook_name("custom modified exclusive webhook name".to_owned())
    .handle_attachment_link()?
    .handle_sticker_link()?
    .handle_reaction()
    .await?
    .handle_reference()?
    .handle_thread()
    .await?
    .sanitize_username("?", "????")
    .create()
    .await?
    .handle_thread_created()
    .await?;

for later_message in later_messages {
    // create every message sent later
    later_message?.create().await?;
}

๐Ÿ“ฆ Cargo Features

  • upload: Enables methods for re-uploading attachments

๐Ÿ™ Feedback

Although widely tested, there may still be bugs, or you might have feature suggestions, please create issues for these!

๐Ÿงช Testing

The crate uses integration tests as opposed to unit tests to test real-world usage. It creates a message and clones it, then the tester checks if the message is cloned as expected

Before starting, set these environment variables, you can also put them in a .env file:

  • BOT_TOKEN: The token of the bot to use for testing
  • CHANNEL_ID: The channel in which the messages and webhooks will be crated
  • FORUM_CHANNEL_ID: The forum channel in which cloning messages/threads in forum channels will be tested
  • NOT_LAST_SOURCE_THREAD_ID: The bot will create a thread and spam to 200 in it the first time the tests are ran, to avoid doing this again, set this to the ID of this thread
  • GUILD_EMOJI_ID: ID of an emoji that's in the guild CHANNEL_ID is in

Required permissions in CHANNEL_ID and FORUM_CHANNEL_ID:

  • VIEW_CHANNEL
  • MANAGE_WEBHOOKS
  • SEND_MESSAGES

Required additional permissions in FORUM_CHANNEL_ID:

  • CREATE_POSTS
  • SEND_MESSAGES_IN_POSTS

Test with a single thread to avoid race conditions: cargo test --all-features -- --test-threads=1

Dependencies

~11โ€“23MB
~355K SLoC