You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
741 lines
18 KiB
741 lines
18 KiB
from __future__ import print_function
|
|
|
|
import six
|
|
|
|
from disco.types.user import User, Presence
|
|
from disco.types.channel import Channel, PermissionOverwrite
|
|
from disco.types.message import Message, MessageReactionEmoji
|
|
from disco.types.voice import VoiceState
|
|
from disco.types.guild import Guild, GuildMember, Role, GuildEmoji
|
|
from disco.types.base import Model, ModelMeta, Field, ListField, AutoDictField, UNSET, snowflake, datetime
|
|
from disco.util.string import underscore
|
|
|
|
# Mapping of discords event name to our event classes
|
|
EVENTS_MAP = {}
|
|
|
|
|
|
class GatewayEventMeta(ModelMeta):
|
|
def __new__(mcs, name, parents, dct):
|
|
obj = super(GatewayEventMeta, mcs).__new__(mcs, name, parents, dct)
|
|
|
|
if name != 'GatewayEvent':
|
|
EVENTS_MAP[underscore(name).upper()] = obj
|
|
|
|
return obj
|
|
|
|
|
|
class GatewayEvent(six.with_metaclass(GatewayEventMeta, Model)):
|
|
"""
|
|
The GatewayEvent class wraps various functionality for events passed to us
|
|
over the gateway websocket, and serves as a simple proxy to inner values for
|
|
some wrapped event-types (e.g. MessageCreate only contains a message, so we
|
|
proxy all attributes to the inner message object).
|
|
"""
|
|
|
|
@staticmethod
|
|
def from_dispatch(client, data):
|
|
"""
|
|
Create a new GatewayEvent instance based on event data.
|
|
"""
|
|
cls = EVENTS_MAP.get(data['t'])
|
|
if not cls:
|
|
raise Exception('Could not find cls for {} ({})'.format(data['t'], data))
|
|
|
|
return cls.create(data['d'], client)
|
|
|
|
@classmethod
|
|
def create(cls, obj, client):
|
|
"""
|
|
Create this GatewayEvent class from data and the client.
|
|
"""
|
|
cls.raw_data = obj
|
|
|
|
# If this event is wrapping a model, pull its fields
|
|
if hasattr(cls, '_wraps_model'):
|
|
alias, model = cls._wraps_model
|
|
|
|
data = {
|
|
k: obj.pop(k) for k in six.iterkeys(model._fields) if k in obj
|
|
}
|
|
|
|
obj[alias] = data
|
|
|
|
obj = cls(obj, client)
|
|
|
|
if hasattr(cls, '_attach'):
|
|
field, to = cls._attach
|
|
setattr(getattr(obj, to[0]), to[1], getattr(obj, field))
|
|
|
|
return obj
|
|
|
|
def __getattr__(self, name):
|
|
try:
|
|
_proxy = object.__getattribute__(self, '_proxy')
|
|
except AttributeError:
|
|
return object.__getattribute__(self, name)
|
|
|
|
return getattr(getattr(self, _proxy), name)
|
|
|
|
|
|
def debug(func=None, match=None):
|
|
def deco(cls):
|
|
old_init = cls.__init__
|
|
|
|
def new_init(self, obj, *args, **kwargs):
|
|
if not match or match(obj):
|
|
if func:
|
|
print(func(obj))
|
|
else:
|
|
print(obj)
|
|
|
|
old_init(self, obj, *args, **kwargs)
|
|
|
|
cls.__init__ = new_init
|
|
return cls
|
|
return deco
|
|
|
|
|
|
def wraps_model(model, alias=None):
|
|
alias = alias or model.__name__.lower()
|
|
|
|
def deco(cls):
|
|
cls._fields[alias] = Field(model)
|
|
cls._fields[alias].name = alias
|
|
cls._wraps_model = (alias, model)
|
|
cls._proxy = alias
|
|
return cls
|
|
return deco
|
|
|
|
|
|
def proxy(field):
|
|
def deco(cls):
|
|
cls._proxy = field
|
|
return cls
|
|
return deco
|
|
|
|
|
|
def attach(field, to=None):
|
|
def deco(cls):
|
|
cls._attach = (field, to)
|
|
return cls
|
|
return deco
|
|
|
|
|
|
class Ready(GatewayEvent):
|
|
"""
|
|
Sent after the initial gateway handshake is complete. Contains data required
|
|
for bootstrapping the client's states.
|
|
|
|
Attributes
|
|
----------
|
|
version : int
|
|
The gateway version.
|
|
session_id : str
|
|
The session ID.
|
|
user : :class:`disco.types.user.User`
|
|
The user object for the authenticated account.
|
|
guilds : list[:class:`disco.types.guild.Guild`
|
|
All guilds this account is a member of. These are shallow guild objects.
|
|
private_channels list[:class:`disco.types.channel.Channel`]
|
|
All private channels (DMs) open for this account.
|
|
"""
|
|
version = Field(int, alias='v')
|
|
session_id = Field(str)
|
|
user = Field(User)
|
|
guilds = ListField(Guild)
|
|
private_channels = ListField(Channel)
|
|
|
|
|
|
class Resumed(GatewayEvent):
|
|
"""
|
|
Sent after a resume completes.
|
|
"""
|
|
|
|
|
|
@wraps_model(Guild)
|
|
class GuildCreate(GatewayEvent):
|
|
"""
|
|
Sent when a guild is joined, or becomes available.
|
|
|
|
Attributes
|
|
----------
|
|
guild : :class:`disco.types.guild.Guild`
|
|
The guild being created (e.g. joined).
|
|
unavailable : bool
|
|
If false, this guild is coming online from a previously unavailable state,
|
|
and if UNSET, this is a normal guild join event.
|
|
"""
|
|
unavailable = Field(bool)
|
|
presences = ListField(Presence)
|
|
|
|
@property
|
|
def created(self):
|
|
"""
|
|
Shortcut property which is true when we actually joined the guild.
|
|
"""
|
|
return self.unavailable is UNSET
|
|
|
|
|
|
@wraps_model(Guild)
|
|
class GuildUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a guild is updated.
|
|
|
|
Attributes
|
|
----------
|
|
guild : :class:`disco.types.guild.Guild`
|
|
The updated guild object.
|
|
"""
|
|
|
|
|
|
class GuildDelete(GatewayEvent):
|
|
"""
|
|
Sent when a guild is deleted, left, or becomes unavailable.
|
|
|
|
Attributes
|
|
----------
|
|
id : snowflake
|
|
The ID of the guild being deleted.
|
|
unavailable : bool
|
|
If true, this guild is becoming unavailable, if UNSET this is a normal
|
|
guild leave event.
|
|
"""
|
|
id = Field(snowflake)
|
|
unavailable = Field(bool)
|
|
|
|
@property
|
|
def deleted(self):
|
|
"""
|
|
Shortcut property which is true when we actually have left the guild.
|
|
"""
|
|
return self.unavailable is UNSET
|
|
|
|
|
|
@wraps_model(Channel)
|
|
class ChannelCreate(GatewayEvent):
|
|
"""
|
|
Sent when a channel is created.
|
|
|
|
Attributes
|
|
----------
|
|
channel : :class:`disco.types.channel.Channel`
|
|
The channel which was created.
|
|
"""
|
|
|
|
|
|
@wraps_model(Channel)
|
|
class ChannelUpdate(ChannelCreate):
|
|
"""
|
|
Sent when a channel is updated.
|
|
|
|
Attributes
|
|
----------
|
|
channel : :class:`disco.types.channel.Channel`
|
|
The channel which was updated.
|
|
"""
|
|
overwrites = AutoDictField(PermissionOverwrite, 'id', alias='permission_overwrites')
|
|
|
|
|
|
@wraps_model(Channel)
|
|
class ChannelDelete(ChannelCreate):
|
|
"""
|
|
Sent when a channel is deleted.
|
|
|
|
Attributes
|
|
----------
|
|
channel : :class:`disco.types.channel.Channel`
|
|
The channel being deleted.
|
|
"""
|
|
|
|
|
|
class ChannelPinsUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a channel's pins are updated.
|
|
|
|
Attributes
|
|
----------
|
|
channel_id : snowflake
|
|
ID of the channel where pins where updated.
|
|
last_pin_timestamp : datetime
|
|
The time the last message was pinned.
|
|
"""
|
|
channel_id = Field(snowflake)
|
|
last_pin_timestamp = Field(datetime)
|
|
|
|
|
|
@proxy(User)
|
|
class GuildBanAdd(GatewayEvent):
|
|
"""
|
|
Sent when a user is banned from a guild.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild the user is being banned from.
|
|
user : :class:`disco.types.user.User`
|
|
The user being banned from the guild.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
user = Field(User)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
@proxy(User)
|
|
class GuildBanRemove(GuildBanAdd):
|
|
"""
|
|
Sent when a user is unbanned from a guild.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild the user is being unbanned from.
|
|
user : :class:`disco.types.user.User`
|
|
The user being unbanned from the guild.
|
|
"""
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
class GuildEmojisUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a guild's emojis are updated.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild the emojis are being updated in.
|
|
emojis : list[:class:`disco.types.guild.Emoji`]
|
|
The new set of emojis for the guild.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
emojis = ListField(GuildEmoji)
|
|
|
|
|
|
class GuildIntegrationsUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a guild's integrations are updated.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild integrations where updated in.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
|
|
|
|
class GuildMembersChunk(GatewayEvent):
|
|
"""
|
|
Sent in response to a member's chunk request.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild this member chunk is for.
|
|
members : list[:class:`disco.types.guild.GuildMember`]
|
|
The chunk of members.
|
|
not_found : list[snowflake]
|
|
An array of invalid requested guild members.
|
|
presences : list[:class:`disco.types.user.Presence`]
|
|
An array of requested member presence states.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
members = ListField(GuildMember)
|
|
not_found = ListField(snowflake)
|
|
presences = ListField(Presence)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
@wraps_model(GuildMember, alias='member')
|
|
class GuildMemberAdd(GatewayEvent):
|
|
"""
|
|
Sent when a user joins a guild.
|
|
|
|
Attributes
|
|
----------
|
|
member : :class:`disco.types.guild.GuildMember`
|
|
The member that has joined the guild.
|
|
"""
|
|
|
|
|
|
@proxy('user')
|
|
class GuildMemberRemove(GatewayEvent):
|
|
"""
|
|
Sent when a user leaves a guild (via leaving, kicking, or banning).
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild the member left from.
|
|
user : :class:`disco.types.user.User`
|
|
The user who was removed from the guild.
|
|
"""
|
|
user = Field(User)
|
|
guild_id = Field(snowflake)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
@wraps_model(GuildMember, alias='member')
|
|
class GuildMemberUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a guilds member is updated.
|
|
|
|
Attributes
|
|
----------
|
|
member : :class:`disco.types.guild.GuildMember`
|
|
The member being updated
|
|
"""
|
|
|
|
|
|
@proxy('role')
|
|
@attach('guild_id', to=('role', 'guild_id'))
|
|
class GuildRoleCreate(GatewayEvent):
|
|
"""
|
|
Sent when a role is created.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild where the role was created.
|
|
role : :class:`disco.types.guild.Role`
|
|
The role that was created.
|
|
"""
|
|
role = Field(Role)
|
|
guild_id = Field(snowflake)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
class GuildRoleUpdate(GuildRoleCreate):
|
|
"""
|
|
Sent when a role is updated.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild where the role was created.
|
|
role : :class:`disco.types.guild.Role`
|
|
The role that was created.
|
|
"""
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
class GuildRoleDelete(GatewayEvent):
|
|
"""
|
|
Sent when a role is deleted.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild where the role is being deleted.
|
|
role_id : snowflake
|
|
The id of the role being deleted.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
role_id = Field(snowflake)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
@wraps_model(Message)
|
|
class MessageCreate(GatewayEvent):
|
|
"""
|
|
Sent when a message is created.
|
|
|
|
Attributes
|
|
----------
|
|
message : :class:`disco.types.message.Message`
|
|
The message being created.
|
|
guild_id : snowflake
|
|
The ID of the guild this message comes from.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
|
|
|
|
@wraps_model(Message)
|
|
class MessageUpdate(MessageCreate):
|
|
"""
|
|
Sent when a message is updated/edited.
|
|
|
|
Attributes
|
|
----------
|
|
message : :class:`disco.types.message.Message`
|
|
The message being updated.
|
|
guild_id : snowflake
|
|
The ID of the guild this message exists in.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
|
|
|
|
class MessageDelete(GatewayEvent):
|
|
"""
|
|
Sent when a message is deleted.
|
|
|
|
Attributes
|
|
----------
|
|
id : snowflake
|
|
The ID of message being deleted.
|
|
channel_id : snowflake
|
|
The ID of the channel the message was deleted in.
|
|
guild_id : snowflake
|
|
The ID of the guild this message existed in.
|
|
"""
|
|
id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
guild_id = Field(snowflake)
|
|
|
|
@property
|
|
def channel(self):
|
|
return self.client.state.channels.get(self.channel_id)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.channel.guild
|
|
|
|
|
|
class MessageDeleteBulk(GatewayEvent):
|
|
"""
|
|
Sent when multiple messages are deleted from a channel.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The guild the messages are being deleted in.
|
|
channel_id : snowflake
|
|
The channel the messages are being deleted in.
|
|
ids : list[snowflake]
|
|
List of messages being deleted in the channel.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
ids = ListField(snowflake)
|
|
|
|
@property
|
|
def channel(self):
|
|
return self.client.state.channels.get(self.channel_id)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.channel.guild
|
|
|
|
|
|
@wraps_model(Presence)
|
|
class PresenceUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a user's presence is updated.
|
|
|
|
Attributes
|
|
----------
|
|
presence : :class:`disco.types.user.Presence`
|
|
The updated presence object.
|
|
guild_id : snowflake
|
|
The guild this presence update is for.
|
|
roles : list[snowflake]
|
|
List of roles the user from the presence is part of.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
roles = ListField(snowflake)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.client.state.guilds.get(self.guild_id)
|
|
|
|
|
|
class TypingStart(GatewayEvent):
|
|
"""
|
|
Sent when a user begins typing in a channel.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The ID of the guild where the user is typing.
|
|
channel_id : snowflake
|
|
The ID of the channel where the user is typing.
|
|
user_id : snowflake
|
|
The ID of the user who is typing.
|
|
timestamp : datetime
|
|
When the user started typing.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
user_id = Field(snowflake)
|
|
timestamp = Field(datetime)
|
|
|
|
|
|
@wraps_model(VoiceState, alias='state')
|
|
class VoiceStateUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a users voice state changes.
|
|
|
|
Attributes
|
|
----------
|
|
state : :class:`disco.models.voice.VoiceState`
|
|
The voice state which was updated.
|
|
"""
|
|
|
|
|
|
class VoiceServerUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a voice server is updated.
|
|
|
|
Attributes
|
|
----------
|
|
token : str
|
|
The token for the voice server.
|
|
endpoint : str
|
|
The endpoint for the voice server.
|
|
guild_id : snowflake
|
|
The guild ID this voice server update is for.
|
|
"""
|
|
token = Field(str)
|
|
endpoint = Field(str)
|
|
guild_id = Field(snowflake)
|
|
|
|
|
|
class WebhooksUpdate(GatewayEvent):
|
|
"""
|
|
Sent when a channels webhooks are updated.
|
|
|
|
Attributes
|
|
----------
|
|
channel_id : snowflake
|
|
The channel ID this webhooks update is for.
|
|
guild_id : snowflake
|
|
The guild ID this webhooks update is for.
|
|
"""
|
|
channel_id = Field(snowflake)
|
|
guild_id = Field(snowflake)
|
|
|
|
|
|
class MessageReactionAdd(GatewayEvent):
|
|
"""
|
|
Sent when a reaction is added to a message.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The guild ID the message is in.
|
|
channel_id : snowflake
|
|
The channel ID the message is in.
|
|
message_id : snowflake
|
|
The ID of the message for which the reaction was added too.
|
|
user_id : snowflake
|
|
The ID of the user who added the reaction.
|
|
emoji : :class:`disco.types.message.MessageReactionEmoji`
|
|
The emoji which was added.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
message_id = Field(snowflake)
|
|
user_id = Field(snowflake)
|
|
emoji = Field(MessageReactionEmoji)
|
|
|
|
def delete(self):
|
|
self.client.api.channels_messages_reactions_delete(
|
|
self.channel_id,
|
|
self.message_id,
|
|
self.emoji.to_string() if self.emoji.id else self.emoji.name,
|
|
self.user_id,
|
|
)
|
|
|
|
@property
|
|
def channel(self):
|
|
return self.client.state.channels.get(self.channel_id)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.channel.guild
|
|
|
|
|
|
class MessageReactionRemove(GatewayEvent):
|
|
"""
|
|
Sent when a reaction is removed from a message.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The guild ID the message is in.
|
|
channel_id : snowflake
|
|
The channel ID the message is in.
|
|
message_id : snowflake
|
|
The ID of the message for which the reaction was removed from.
|
|
user_id : snowflake
|
|
The ID of the user who originally added the reaction.
|
|
emoji : :class:`disco.types.message.MessageReactionEmoji`
|
|
The emoji which was removed.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
message_id = Field(snowflake)
|
|
user_id = Field(snowflake)
|
|
emoji = Field(MessageReactionEmoji)
|
|
|
|
@property
|
|
def channel(self):
|
|
return self.client.state.channels.get(self.channel_id)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.channel.guild
|
|
|
|
|
|
class MessageReactionRemoveAll(GatewayEvent):
|
|
"""
|
|
Sent when all reactions are removed from a message.
|
|
|
|
Attributes
|
|
----------
|
|
guild_id : snowflake
|
|
The guild ID the message is in.
|
|
channel_id : snowflake
|
|
The channel ID the message is in.
|
|
message_id : snowflake
|
|
The ID of the message for which the reactions where removed from.
|
|
"""
|
|
guild_id = Field(snowflake)
|
|
channel_id = Field(snowflake)
|
|
message_id = Field(snowflake)
|
|
|
|
@property
|
|
def channel(self):
|
|
return self.client.state.channels.get(self.channel_id)
|
|
|
|
@property
|
|
def guild(self):
|
|
return self.channel.guild
|
|
|
|
|
|
@wraps_model(User)
|
|
class UserUpdate(GatewayEvent):
|
|
"""
|
|
Sent when the client user is updated.
|
|
|
|
Attributes
|
|
-----
|
|
user : :class:`disco.types.user.User`
|
|
The updated user object.
|
|
"""
|
|
|
|
|
|
class PresencesReplace(GatewayEvent):
|
|
"""
|
|
Sent after a Gateway outage.
|
|
"""
|
|
pass
|
|
|