From fc534965f4d87a5110f1ee558ea36994eecec73b Mon Sep 17 00:00:00 2001 From: Andrei Date: Sun, 9 Oct 2016 04:14:11 -0500 Subject: [PATCH] Add presence tracking --- disco/gateway/events.py | 19 ++++++++----------- disco/state.py | 5 +++++ disco/types/base.py | 15 ++++++++++++++- disco/types/user.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/disco/gateway/events.py b/disco/gateway/events.py index 99f6d9e..fab8f0c 100644 --- a/disco/gateway/events.py +++ b/disco/gateway/events.py @@ -3,8 +3,13 @@ from __future__ import print_function import inflection import six -from disco.types import Guild, Channel, User, GuildMember, Role, Message, VoiceState -from disco.types.base import Model, Field, snowflake, listof, text +from disco.types.user import User, Presence +from disco.types.channel import Channel +from disco.types.message import Message +from disco.types.voice import VoiceState +from disco.types.guild import Guild, GuildMember, Role + +from disco.types.base import Model, Field, snowflake, listof class GatewayEvent(Model): @@ -267,21 +272,13 @@ class MessageDeleteBulk(GatewayEvent): ids = Field(listof(snowflake)) +@wraps_model(Presence) class PresenceUpdate(GatewayEvent): """ Sent when a users presence is updated. """ - class Game(Model): - # TODO enum - type = Field(int) - name = Field(text) - url = Field(text) - - user = Field(User) guild_id = Field(snowflake) roles = Field(listof(snowflake)) - game = Field(Game) - status = Field(text) class TypingStart(GatewayEvent): diff --git a/disco/state.py b/disco/state.py index 0b30903..cec1687 100644 --- a/disco/state.py +++ b/disco/state.py @@ -80,6 +80,7 @@ class State(object): 'Ready', 'GuildCreate', 'GuildUpdate', 'GuildDelete', 'GuildMemberAdd', 'GuildMemberRemove', 'GuildMemberUpdate', 'GuildMembersChunk', 'GuildRoleCreate', 'GuildRoleUpdate', 'GuildRoleDelete', 'ChannelCreate', 'ChannelUpdate', 'ChannelDelete', 'VoiceStateUpdate', 'MessageCreate', + 'PresenceUpdate' ] def __init__(self, client, config=None): @@ -262,3 +263,7 @@ class State(object): return del self.guilds[event.guild_id].roles[event.role.id] + + def on_presence_update(self, event): + if event.user.id in self.users: + self.users[event.user.id].presence = event.presence diff --git a/disco/types/base.py b/disco/types/base.py index f91ea07..83bcb3d 100644 --- a/disco/types/base.py +++ b/disco/types/base.py @@ -2,6 +2,7 @@ import six import inspect import functools +from holster.enum import BaseEnumMeta from datetime import datetime as real_datetime DATETIME_FORMATS = [ @@ -10,10 +11,19 @@ DATETIME_FORMATS = [ ] +class ConversionError(Exception): + def __init__(self, field, raw, e): + super(ConversionError, self).__init__( + 'Failed to convert `{}` (`{}`) to {}: {}'.format( + raw, field.src_name, field.typ, e)) + + class FieldType(object): def __init__(self, typ): if isinstance(typ, FieldType) or inspect.isclass(typ) and issubclass(typ, Model): self.typ = typ + elif isinstance(typ, BaseEnumMeta): + self.typ = lambda raw, _: typ.get(raw) else: self.typ = lambda raw, _: typ(raw) @@ -48,7 +58,10 @@ class Field(FieldType): return self.default is not None def try_convert(self, raw, client): - return self.typ(raw, client) + try: + return self.typ(raw, client) + except Exception as e: + raise ConversionError(self, raw, e) class _Dict(FieldType): diff --git a/disco/types/user.py b/disco/types/user.py index a5952bc..0a1d006 100644 --- a/disco/types/user.py +++ b/disco/types/user.py @@ -1,3 +1,5 @@ +from holster.enum import Enum + from disco.types.base import Model, Field, snowflake, text, binary, with_equality, with_hash @@ -9,6 +11,8 @@ class User(Model, with_equality('id'), with_hash('id')): verified = Field(bool) email = Field(str) + presence = None + @property def mention(self): return '<@{}>'.format(self.id) @@ -21,3 +25,29 @@ class User(Model, with_equality('id'), with_hash('id')): def on_create(self): self.client.state.users[self.id] = self + + +GameType = Enum( + DEFAULT=0, + STREAMING=1, +) + +Status = Enum( + 'ONLINE', + 'IDLE', + 'DND', + 'INVISIBLE', + 'OFFLINE' +) + + +class Game(Model): + type = Field(GameType) + name = Field(text) + url = Field(text) + + +class Presence(Model): + user = Field(User) + game = Field(Game) + status = Field(Status)