Skip to content

Commit

Permalink
Refactoring message event hierarchy; other tidyups. (#227)
Browse files Browse the repository at this point in the history
* Refactoring message event hierarchy; other tidyups.

I will outline the other tidyups before the main change, as they are only
brief.

- PRIVATE* intents are now named DM* intents to match terminology across
  the rest of the library.
- hikari.utilities.mappings is renamed to hikari.utilities.collections.
- IDTable from hikari.utilities.cache is moved to hikari.utilities.collections,
  has been refactored and fully tested, and altered to be slightly more
  efficient.
- IDTable is now named SnowflakeSet.

Cache mappings have been renamed to be a little clearer as to what
they really are doing.

- DMChannelMRUMutableMapping is now named DMChannelCacheMapping.
- MappedCollection is now named ExtendedMutableMapping.
- DictionaryCollection is now named FreezableDict.
- MRIMutableMapping is now named TimedCacheMap.
- CMRIMutableMapping is now named LimitedCapacityCacheMap.

Message hierarchy changes
-------------------------

Due to the fundamental differences between create/update/delete events and
information they contain for messages, I have concluded that the complexity
created by having these staggered classes is not overly helpful in writing
robust error-safe code. It is definitely not worth the extra overhead, as
there is almost no cases where this is overly useful where you could use
this in such a way that using two event listeners would not be more
terse and idiomatic.

Therefore, GuildMessageEvent and DMMessageEvent no longer exist. The new
hierarchy is as follows instead:

```
  Event
   |
   |-- ShardEvent
   '    |
   '    |-- MessageEvent
        '    |
        '    |-- MessageCreateEvent
             |    |
             |    |-- GuildMessageCreateEvent
             |    '-- DMMessageCreateEvent
             |
             |-- MessageUpdateEvent
             |    |-- GuildMessageUpdateEvent
             |    '-- DMMessageUpdateEvent
             |
             '-- MessageDeleteEvent
                  |-- GuildMessageDeleteEvent
                  '-- DMMessageDeleteEvent
```

** Bulk deletion events **

Bulk deletion events have been merged with deletion events.
The reason for doing this is because Discord already provides
little to no useful information for singular message deletions
other than the message id, the guild id, and the channel id.
This means that no stateless information about what was in the
message nor who made it or who even deleted it originally
can be discovered without polling message history before the
event can occur (which is basically impossible), or by
maintaining a long-lived message cache (which is not yet
supported fully on this API). This would also need heavy audit
log polling to be somewhat effective.

This is pretty much a limitation of how Discord operates,
unfortunately.

This means the only reasonable use case for this event currently
is for tracking any kind of message deletion. The bulk delete
event shares practically the same shape as the singular deletion
event, and anyone listening on deletion events for handling of
things like pagination will therefore almost always want to
listen to both events.

The interface for this event model is now to provide three
attributes to handle detecting which messages were deleted:

  - `message_ids`: will be a `SnowflakeSet` of each ID that
    was deleted. In singular message deletion cases, this
    will always have a single item.
  - `message_id`: to match with the `MessageEvent` interface,
    and to provide a shorthand for cases where people really
    do want to handle only a singular message deletion, rather
    than an operation where you would just iterate across
    the SnowflakeSet. For bulk deletions this will return the
    first deleted message (implementation detail makes this
    the smallest magnitude snowflake that is sent).
  - `is_bulk`: true if a bulk deletion, false if not.

Additionally, since it is undocumented, bulk deletions in DMs
will now result in a NotImplementedError should they occur
(which unless Discord break their API contract, should not
happen).

It is worth noting message deletion events no longer have a
`message` attribute either, as this was pretty much a complete
waste of space given nothing could be in it in the first place
other than the id, channel_id and guild_id.

** Message Update Events **

Now that we have ditched the previous structure for messages,
we can make several attributes such as `author` and `guild_id`
simpler on the PartialMessage model that only the
MessageUpdateEvent uses. You now only have to `None`-check
the `guild_id`, and the `author` should always be present.

** Message Create Events **

This interface is mostly the same, other than having some
property definitions refactored.

* Fixing message update events to cater for optional author.

* Added handling for members in message edits being optional.

* Fix annotations for guild message creates with author property.
  • Loading branch information
Nekokatt authored Sep 27, 2020
1 parent 41146f8 commit 0548d6b
Show file tree
Hide file tree
Showing 20 changed files with 1,350 additions and 898 deletions.
9 changes: 7 additions & 2 deletions hikari/api/event_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ def deserialize_message_delete_event(

def deserialize_message_delete_bulk_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
) -> message_events.MessageBulkDeleteEvent:
) -> message_events.MessageDeleteEvent:
"""Parse a raw payload from Discord into a message delete bulk event object.
Parameters
Expand All @@ -541,8 +541,13 @@ def deserialize_message_delete_bulk_event(
Returns
-------
hikari.events.message_events.MessageBulkDeleteEvent
hikari.events.message_events.MessageDeleteEvent
The parsed message delete bulk event object.
Raises
------
builtins.NotImplementedError
If a bulk delete occurs in a DM channel.
"""

def deserialize_message_reaction_add_event(
Expand Down
4 changes: 2 additions & 2 deletions hikari/audit_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@

from hikari import snowflakes
from hikari.utilities import attr_extensions
from hikari.utilities import collections
from hikari.utilities import enums
from hikari.utilities import mapping

if typing.TYPE_CHECKING:
from hikari import channels
Expand Down Expand Up @@ -347,7 +347,7 @@ def __getitem__(self, slice_: slice, /) -> typing.Sequence[AuditLogEntry]:
def __getitem__(
self, index_or_slice: typing.Union[int, slice], /
) -> typing.Union[AuditLogEntry, typing.Sequence[AuditLogEntry]]:
return mapping.get_index_or_slice(self.entries, index_or_slice)
return collections.get_index_or_slice(self.entries, index_or_slice)

def __iter__(self) -> typing.Iterator[AuditLogEntry]:
return iter(self.entries.values())
Expand Down
14 changes: 7 additions & 7 deletions hikari/events/channel_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
from hikari.api import shard as gateway_shard


@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.DM_MESSAGES)
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class ChannelEvent(shard_events.ShardEvent, abc.ABC):
"""Event base for any channel-bound event in guilds or private messages."""
Expand Down Expand Up @@ -231,7 +231,7 @@ async def fetch_channel(self) -> channels.PrivateChannel:
return channel


@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.DM_MESSAGES)
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class ChannelCreateEvent(ChannelEvent, abc.ABC):
"""Base event for any channel being created."""
Expand Down Expand Up @@ -280,7 +280,7 @@ def guild_id(self) -> snowflakes.Snowflake:
return self.channel.guild_id


@base_events.requires_intents(intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.DM_MESSAGES)
@attr_extensions.with_copy
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class DMChannelCreateEvent(DMChannelEvent, ChannelCreateEvent):
Expand All @@ -302,7 +302,7 @@ class DMChannelCreateEvent(DMChannelEvent, ChannelCreateEvent):
"""


@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.DM_MESSAGES)
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class ChannelUpdateEvent(ChannelEvent, abc.ABC):
"""Base event for any channel being updated."""
Expand Down Expand Up @@ -351,7 +351,7 @@ def guild_id(self) -> snowflakes.Snowflake:
return self.channel.guild_id


@base_events.requires_intents(intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.DM_MESSAGES)
@attr_extensions.with_copy
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class DMChannelUpdateEvent(DMChannelEvent, ChannelUpdateEvent):
Expand All @@ -373,7 +373,7 @@ class DMChannelUpdateEvent(DMChannelEvent, ChannelUpdateEvent):
"""


@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.GUILDS, intents.Intents.DM_MESSAGES)
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class ChannelDeleteEvent(ChannelEvent, abc.ABC):
"""Base event for any channel being deleted."""
Expand Down Expand Up @@ -433,7 +433,7 @@ async def fetch_channel(self) -> typing.NoReturn:


# TODO: can this actually ever get fired?
@base_events.requires_intents(intents.Intents.PRIVATE_MESSAGES)
@base_events.requires_intents(intents.Intents.DM_MESSAGES)
@attr_extensions.with_copy
@attr.s(kw_only=True, slots=True, weakref_slot=False)
class DMChannelDeleteEvent(DMChannelEvent, ChannelDeleteEvent):
Expand Down
Loading

0 comments on commit 0548d6b

Please sign in to comment.