Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ambiguity between Guild Joining and Unavailable Guilds becoming Available #2372

Open
fdnt7 opened this issue Sep 9, 2024 · 0 comments · May be fixed by #2377
Open

Ambiguity between Guild Joining and Unavailable Guilds becoming Available #2372

fdnt7 opened this issue Sep 9, 2024 · 0 comments · May be fixed by #2377
Assignees

Comments

@fdnt7
Copy link

fdnt7 commented Sep 9, 2024

Summary

twilight-model on the latest commit (f58b540 as of writing) deserialises these two distinct events:

  • Joining a new guild
  • A previously unavailable guild becoming available

as the same object, namely GuildCreate::Available(Guild { unavailable: false, .. }). This behaviour should be undesirable, as information was lost about which event it was.

Steps to reproduce

  1. Copy the minimal bot setup as stated in the twilight-gateway example here. Pin twilight-http, twilight-gateway and twilight-model to revision f58b540.
  2. Apply the following diff:
10a11
> use twilight_model::gateway::payload::incoming::GuildCreate;
60c61,70
<         tracing::debug!(?event, shard = ?shard.id(), "received event");
---
>         match event {
>             Event::Ready(_) => tracing::info!("Bot is ready"),
>             Event::GuildCreate(guild_create) => {
>                 match *guild_create {
>                     GuildCreate::Available(guild) => tracing::info!(?guild.unavailable, ?guild.id, "Available"),
>                     GuildCreate::Unavailable(guild) => tracing::info!(?guild.unavailable, ?guild.id, "Unavailable"),
>                 }
>             }
>             _ => continue
>         }
  1. Prepare a bot account. Before running the bot, add it to some guild with some ID ID1.
  2. Run the bot via running DISCORD_TOKEN="..." cargo run, replacing ... with the bot's token.
  3. Wait until "Bot is ready" appears in the log. Then, add the bot to another guild with some ID ID2.

Expected Behaviour

Upon the same time as "Bot is ready" appears in the log, the guild of ID ID1 should become available, appearing in the logs as an event of a guild becoming available. This is a documented behaviour as scenario 1. Then, as the bot is added to another guild of ID ID2, it should appear in the logs as an event of joining a guild. These two events are distinct so the logs should reflect that.

Actual Behaviour

The logs are as shown:

YYYY-MM-DDTHH:MM:SS.FFFFF0Z  INFO rust_playground: Bot is ready
YYYY-MM-DDTHH:MM:SS.FFFFF1Z  INFO rust_playground: Available guild.unavailable=false guild.id=Id<GuildMarker>(ID1)
YYYY-MM-DDTHH:MM:SS.FFFFF2Z  INFO rust_playground: Available guild.unavailable=false guild.id=Id<GuildMarker>(ID2)

(Time information is redacted, but time FFFFF0 and FFFFF1 should be negligibly near each other, and FFFFF2 should be different than the other two timestamps.)

Due to how twilight deserialises these two distinct events, they both show up in the logs as the exact same thing as shown by the logs above, losing the information about whether which was originally sent.

Additional Information

Although not documented, it can be verified that the Discord Gateway differentiate these two events as the following:

  • Upon receiving GuildCreate, if the unavailable field is sent, then the guild became available.
  • If the field is not sent, then the current user joined a new guild.

And this is exactly how Hikari, a python Discord API library, handle this: It separates the event into GuildJoin and GuildAvailable, and upon ShardReady, the unavailable guilds become available with GuildAvailable, and guild joins register as GuildJoin, correctly differentiating the two.
Here's the python code which was used to verify:

import os
import logging

import hikari

bot = hikari.GatewayBot(token=os.environ["DISCORD_TOKEN"])

@bot.listen()
async def shard_ready(event: hikari.ShardReadyEvent) -> None:
    logging.info("Bot is ready")

@bot.listen()
async def guild_available(event: hikari.GuildAvailableEvent) -> None:
    logging.info(f"Available {event.guild.id}")

@bot.listen()
async def guild_join(event: hikari.GuildJoinEvent) -> None:
    logging.info(f"Join {event.guild.id}")


bot.run()

There was a discussion on this Twilight Discord guild a long time ago, but it seems like the thread has been abandoned, so I am bringing this up again (as I was the original poster). As far as I remembered, there was a discussion about how Hikari simply drops events with unavailable field present and is true in GuildCreate (as seen here) and how that was not the preferred way to handle events in Twilight, which I thought was a fair point. However, Twilight can both remain this crucial differentiation and still keep every information about the event as it was received, without dropping any events, as well.

I've seen and tried both #2330 and #2361, which seems related. Pinning to their individual revisions, neither of them addresses this issue.

@Erk- Erk- self-assigned this Sep 12, 2024
Erk- added a commit that referenced this issue Oct 5, 2024
Unavailable would assume false if the field was false if it was not
sent.

The ability to tell the difference can be used to tell the difference
between a guild becoming available and joining a new guild.

Resolves #2372
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants