예제 #1
0
 def deserialize_integration_delete_event(
     self, shard: gateway_shard.GatewayShard,
     payload: data_binding.JSONObject
 ) -> guild_events.IntegrationDeleteEvent:
     application_id: typing.Optional[snowflakes.Snowflake] = None
     if (raw_application_id := payload.get("application_id")) is not None:
         application_id = snowflakes.Snowflake(raw_application_id)
예제 #2
0
    def deserialize_channel_pins_update_event(
        self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
    ) -> channel_events.PinsUpdateEvent:
        channel_id = snowflakes.Snowflake(payload["channel_id"])

        # Turns out this _can_ be None or not present. Only set it if it is actually available.
        if (raw := payload.get("last_pin_timestamp")) is not None:
            last_pin_timestamp: typing.Optional[datetime.datetime] = time.iso8601_datetime_string_to_datetime(raw)
예제 #3
0
    async def on_guild_delete(self, shard: gateway_shard.GatewayShard,
                              payload: data_binding.JSONObject) -> None:
        """See https://discord.com/developers/docs/topics/gateway#guild-delete for more info."""
        event: typing.Union[guild_events.GuildUnavailableEvent,
                            guild_events.GuildLeaveEvent]
        if payload.get("unavailable", False):
            event = self._app.event_factory.deserialize_guild_unavailable_event(
                shard, payload)

            if self._cache:
                self._cache.set_guild_availability(event.guild_id, False)

        else:
            event = self._app.event_factory.deserialize_guild_leave_event(
                shard, payload)

            if self._cache:
                #  TODO: this doesn't work in all intent scenarios
                self._cache.delete_guild(event.guild_id)
                self._cache.clear_voice_states_for_guild(event.guild_id)
                self._cache.clear_invites_for_guild(event.guild_id)
                self._cache.clear_members_for_guild(event.guild_id)
                self._cache.clear_presences_for_guild(event.guild_id)
                self._cache.clear_guild_channels_for_guild(event.guild_id)
                self._cache.clear_emojis_for_guild(event.guild_id)
                self._cache.clear_roles_for_guild(event.guild_id)

        await self.dispatch(event)
예제 #4
0
 async def on_guild_delete(self, shard: gateway_shard.GatewayShard,
                           payload: data_binding.JSONObject) -> None:
     """See https://discord.com/developers/docs/topics/gateway#guild-delete for more info."""
     if payload.get("unavailable", False):
         await self.dispatch(
             self._app.event_factory.deserialize_guild_unavailable_event(
                 shard, payload))
     else:
         await self.dispatch(
             self._app.event_factory.deserialize_guild_leave_event(
                 shard, payload))
예제 #5
0
    def deserialize_guild_member_chunk_event(
            self, shard: gateway_shard.GatewayShard,
            payload: data_binding.JSONObject) -> shard_events.MemberChunkEvent:
        guild_id = snowflakes.Snowflake(payload["guild_id"])
        index = int(payload["chunk_index"])
        count = int(payload["chunk_count"])
        members = {
            snowflakes.Snowflake(m["user"]["id"]):
            self._app.entity_factory.deserialize_member(m, guild_id=guild_id)
            for m in payload["members"]
        }
        # Note, these IDs may be returned as ints or strings based on whether they're over a certain value.
        not_found = [snowflakes.Snowflake(sn) for sn in payload["not_found"]
                     ] if "not_found" in payload else []

        if presence_payloads := payload.get("presences"):
            presences = {
                snowflakes.Snowflake(p["user"]["id"]):
                self._app.entity_factory.deserialize_member_presence(
                    p, guild_id=guild_id)
                for p in presence_payloads
            }
예제 #6
0
 def _split_reaction_emoji(
     self, emoji_payload: data_binding.JSONObject, /
 ) -> typing.Tuple[typing.Optional[snowflakes.Snowflake], typing.Union[
         str, emojis_models.UnicodeEmoji, None]]:
     if (emoji_id := emoji_payload.get("id")) is not None:
         return snowflakes.Snowflake(emoji_id), emoji_payload["name"]
예제 #7
0
    async def on_guild_create(  # noqa: C901 - Function too complex
            self, shard: gateway_shard.GatewayShard,
            payload: data_binding.JSONObject) -> None:
        """See https://discord.com/developers/docs/topics/gateway#guild-create for more info."""
        event: typing.Union[guild_events.GuildAvailableEvent,
                            guild_events.GuildJoinEvent, None]

        if "unavailable" in payload and self._enabled_for_event(
                guild_events.GuildAvailableEvent):
            event = self._event_factory.deserialize_guild_available_event(
                shard, payload)
        elif "unavailable" not in payload and self._enabled_for_event(
                guild_events.GuildJoinEvent):
            event = self._event_factory.deserialize_guild_join_event(
                shard, payload)
        else:
            event = None

        if event:
            # We also filter here to prevent iterating over them and calling a function that won't do anything
            channels = event.channels if self._cache_enabled_for(
                config.CacheComponents.GUILD_CHANNELS) else None
            emojis = event.emojis if self._cache_enabled_for(
                config.CacheComponents.EMOJIS) else None
            guild = event.guild if self._cache_enabled_for(
                config.CacheComponents.GUILDS) else None
            guild_id = event.guild.id
            members = event.members if self._cache_enabled_for(
                config.CacheComponents.MEMBERS) else None
            presences = event.presences if self._cache_enabled_for(
                config.CacheComponents.PRESENCES) else None
            roles = event.roles if self._cache_enabled_for(
                config.CacheComponents.ROLES) else None
            voice_states = event.voice_states if self._cache_enabled_for(
                config.CacheComponents.VOICE_STATES) else None

        elif self._cache:
            _LOGGER.log(
                ux.TRACE,
                "Skipping on_guild_create dispatch due to lack of any registered listeners"
            )
            gd = self._entity_factory.deserialize_gateway_guild(payload)

            channels = gd.channels() if self._cache_enabled_for(
                config.CacheComponents.GUILD_CHANNELS) else None
            emojis = gd.emojis() if self._cache_enabled_for(
                config.CacheComponents.EMOJIS) else None
            guild = gd.guild() if self._cache_enabled_for(
                config.CacheComponents.GUILDS) else None
            guild_id = gd.id
            members = gd.members() if self._cache_enabled_for(
                config.CacheComponents.MEMBERS) else None
            presences = gd.presences() if self._cache_enabled_for(
                config.CacheComponents.PRESENCES) else None
            roles = gd.roles() if self._cache_enabled_for(
                config.CacheComponents.ROLES) else None
            voice_states = gd.voice_states() if self._cache_enabled_for(
                config.CacheComponents.VOICE_STATES) else None

        else:
            _LOGGER.log(
                ux.TRACE,
                "Skipping on_guild_create raw dispatch due to lack of any registered listeners or cache need"
            )

            channels = None
            emojis = None
            guild = None
            guild_id = snowflakes.Snowflake(payload["id"])
            members = None
            presences = None
            roles = None
            voice_states = None

        if self._cache:
            if guild:
                self._cache.update_guild(guild)

            if channels:
                self._cache.clear_guild_channels_for_guild(guild_id)
                for channel in channels.values():
                    self._cache.set_guild_channel(channel)

            if emojis:
                self._cache.clear_emojis_for_guild(guild_id)
                for emoji in emojis.values():
                    self._cache.set_emoji(emoji)

            if roles:
                self._cache.clear_roles_for_guild(guild_id)
                for role in roles.values():
                    self._cache.set_role(role)

            if members:
                # TODO: do we really want to invalidate these all after an outage.
                self._cache.clear_members_for_guild(guild_id)
                for member in members.values():
                    self._cache.set_member(member)

            if presences:
                self._cache.clear_presences_for_guild(guild_id)
                for presence in presences.values():
                    self._cache.set_presence(presence)

            if voice_states:
                self._cache.clear_voice_states_for_guild(guild_id)
                for voice_state in voice_states.values():
                    self._cache.set_voice_state(voice_state)

        presences_declared = self._intents & intents_.Intents.GUILD_PRESENCES

        # When intents are enabled Discord will only send other member objects on the guild create
        # payload if presence intents are also declared, so if this isn't the case then we also want
        # to chunk small guilds.
        if (self._intents & intents_.Intents.GUILD_MEMBERS
                and (payload.get("large") or not presences_declared) and
            (self._cache_enabled_for(config.CacheComponents.MEMBERS)
             or self._enabled_for_event(shard_events.MemberChunkEvent))):
            # We create a task here instead of awaiting the result to avoid any rate-limits from delaying dispatch.
            nonce = f"{shard.id}.{_fixed_size_nonce()}"

            if event:
                event.chunk_nonce = nonce

            coroutine = _request_guild_members(
                shard,
                guild_id,
                include_presences=bool(presences_declared),
                nonce=nonce)
            asyncio.create_task(
                coroutine,
                name=f"{shard.id}:{guild_id} guild create members request")

        if event:
            await self.dispatch(event)