Browse Source

Better interface to reactions, etc cleanup

pull/9/head
Andrei 9 years ago
parent
commit
ef4e87f7fb
  1. 8
      disco/api/http.py
  2. 13
      disco/api/ratelimit.py
  3. 6
      disco/cli.py
  4. 4
      disco/client.py
  5. 6
      disco/gateway/sharder.py
  6. 3
      disco/types/channel.py
  7. 15
      disco/types/guild.py
  8. 37
      disco/types/message.py
  9. 31
      disco/util/logging.py

8
disco/api/http.py

@ -18,6 +18,12 @@ HTTPMethod = Enum(
) )
def to_bytes(obj):
if isinstance(obj, six.text_type):
return obj.encode('utf-8')
return obj
class Routes(object): class Routes(object):
""" """
Simple Python object-enum of all method/url route combinations available to Simple Python object-enum of all method/url route combinations available to
@ -194,6 +200,7 @@ class HTTPClient(LoggingClass):
kwargs['headers'] = self.headers kwargs['headers'] = self.headers
# Build the bucket URL # Build the bucket URL
args = {to_bytes(k): to_bytes(v) for k, v in six.iteritems(args)}
filtered = {k: (v if v in ('guild', 'channel') else '') for k, v in six.iteritems(args)} filtered = {k: (v if v in ('guild', 'channel') else '') for k, v in six.iteritems(args)}
bucket = (route[0].value, route[1].format(**filtered)) bucket = (route[0].value, route[1].format(**filtered))
@ -202,6 +209,7 @@ class HTTPClient(LoggingClass):
# Make the actual request # Make the actual request
url = self.BASE_URL + route[1].format(**args) url = self.BASE_URL + route[1].format(**args)
self.log.info('%s %s', route[0].value, url)
r = requests.request(route[0].value, url, **kwargs) r = requests.request(route[0].value, url, **kwargs)
# Update rate limiter # Update rate limiter

13
disco/api/ratelimit.py

@ -1,8 +1,10 @@
import time import time
import gevent import gevent
from disco.util.logging import LoggingClass
class RouteState(object):
class RouteState(LoggingClass):
""" """
An object which stores ratelimit state for a given method/url route An object which stores ratelimit state for a given method/url route
combination (as specified in :class:`disco.api.http.Routes`). combination (as specified in :class:`disco.api.http.Routes`).
@ -36,6 +38,9 @@ class RouteState(object):
self.update(response) self.update(response)
def __repr__(self):
return '<RouteState {}>'.format(' '.join(self.route))
@property @property
def chilled(self): def chilled(self):
""" """
@ -92,12 +97,14 @@ class RouteState(object):
raise Exception('Cannot cooldown for negative time period; check clock sync') raise Exception('Cannot cooldown for negative time period; check clock sync')
self.event = gevent.event.Event() self.event = gevent.event.Event()
gevent.sleep((self.reset_time - time.time()) + .5) delay = (self.reset_time - time.time()) + .5
self.log.debug('Cooling down bucket %s for %s seconds', self, delay)
gevent.sleep(delay)
self.event.set() self.event.set()
self.event = None self.event = None
class RateLimiter(object): class RateLimiter(LoggingClass):
""" """
A in-memory store of ratelimit states for all routes we've ever called. A in-memory store of ratelimit states for all routes we've ever called.

6
disco/cli.py

@ -41,7 +41,7 @@ def disco_main(run=False):
from disco.client import Client, ClientConfig from disco.client import Client, ClientConfig
from disco.bot import Bot, BotConfig from disco.bot import Bot, BotConfig
from disco.util.token import is_valid_token from disco.util.token import is_valid_token
from holster.log import set_logging_levels from disco.util.logging import setup_logging
if os.path.exists(args.config): if os.path.exists(args.config):
config = ClientConfig.from_file(args.config) config = ClientConfig.from_file(args.config)
@ -61,8 +61,8 @@ def disco_main(run=False):
AutoSharder(config).run() AutoSharder(config).run()
return return
logging.basicConfig(level=logging.INFO) # TODO: make configurable
set_logging_levels() setup_logging(level=logging.INFO)
client = Client(config) client = Client(config)

4
disco/client.py

@ -13,7 +13,7 @@ from disco.util.logging import LoggingClass
from disco.util.backdoor import DiscoBackdoorServer from disco.util.backdoor import DiscoBackdoorServer
class ClientConfig(LoggingClass, Config): class ClientConfig(Config):
""" """
Configuration for the :class:`Client`. Configuration for the :class:`Client`.
@ -46,7 +46,7 @@ class ClientConfig(LoggingClass, Config):
encoder = 'json' encoder = 'json'
class Client(object): class Client(LoggingClass):
""" """
Class representing the base entry point that should be used in almost all Class representing the base entry point that should be used in almost all
implementation cases. This class wraps the functionality of both the REST API implementation cases. This class wraps the functionality of both the REST API

6
disco/gateway/sharder.py

@ -5,22 +5,20 @@ import gevent
import logging import logging
import marshal import marshal
from holster.log import set_logging_levels
from disco.client import Client from disco.client import Client
from disco.bot import Bot, BotConfig from disco.bot import Bot, BotConfig
from disco.api.client import APIClient from disco.api.client import APIClient
from disco.gateway.ipc import GIPCProxy from disco.gateway.ipc import GIPCProxy
from disco.util.logging import setup_logging
from disco.util.snowflake import calculate_shard from disco.util.snowflake import calculate_shard
from disco.util.serializer import dump_function, load_function from disco.util.serializer import dump_function, load_function
def run_shard(config, id, pipe): def run_shard(config, id, pipe):
logging.basicConfig( setup_logging(
level=logging.INFO, level=logging.INFO,
format='{} [%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s'.format(id) format='{} [%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s'.format(id)
) )
set_logging_levels()
config.shard_id = id config.shard_id = id
client = Client(config) client = Client(config)

3
disco/types/channel.py

@ -186,6 +186,9 @@ class Channel(SlottedModel, Permissible):
""" """
return MessageIterator(self.client, self, **kwargs) return MessageIterator(self.client, self, **kwargs)
def get_message(self, message):
return self.client.api.channels_messages_get(self.id, to_snowflake(message))
def get_invites(self): def get_invites(self):
""" """
Returns Returns

15
disco/types/guild.py

@ -10,6 +10,7 @@ from disco.types.base import SlottedModel, Field, snowflake, listof, dictof, tex
from disco.types.user import User, Presence from disco.types.user import User, Presence
from disco.types.voice import VoiceState from disco.types.voice import VoiceState
from disco.types.channel import Channel from disco.types.channel import Channel
from disco.types.message import Emoji
from disco.types.permissions import PermissionValue, Permissions, Permissible from disco.types.permissions import PermissionValue, Permissions, Permissible
@ -22,7 +23,9 @@ VerificationLevel = Enum(
) )
class GuildSubType(SlottedModel): class GuildSubType(object):
__slots__ = []
guild_id = Field(None) guild_id = Field(None)
@cached_property @cached_property
@ -30,7 +33,7 @@ class GuildSubType(SlottedModel):
return self.client.state.guilds.get(self.guild_id) return self.client.state.guilds.get(self.guild_id)
class Emoji(GuildSubType): class GuildEmoji(Emoji, GuildSubType):
""" """
An emoji object An emoji object
@ -54,7 +57,7 @@ class Emoji(GuildSubType):
roles = Field(listof(snowflake)) roles = Field(listof(snowflake))
class Role(GuildSubType): class Role(SlottedModel, GuildSubType):
""" """
A role object A role object
@ -95,7 +98,7 @@ class Role(GuildSubType):
return '<@{}>'.format(self.id) return '<@{}>'.format(self.id)
class GuildMember(GuildSubType): class GuildMember(SlottedModel, GuildSubType):
""" """
A GuildMember object A GuildMember object
@ -222,7 +225,7 @@ class Guild(SlottedModel, Permissible):
All of the guild's channels. All of the guild's channels.
roles : dict(snowflake, :class:`Role`) roles : dict(snowflake, :class:`Role`)
All of the guild's roles. All of the guild's roles.
emojis : dict(snowflake, :class:`Emoji`) emojis : dict(snowflake, :class:`GuildEmoji`)
All of the guild's emojis. All of the guild's emojis.
voice_states : dict(str, :class:`disco.types.voice.VoiceState`) voice_states : dict(str, :class:`disco.types.voice.VoiceState`)
All of the guild's voice states. All of the guild's voice states.
@ -243,7 +246,7 @@ class Guild(SlottedModel, Permissible):
members = Field(dictof(GuildMember, key='id')) members = Field(dictof(GuildMember, key='id'))
channels = Field(dictof(Channel, key='id')) channels = Field(dictof(Channel, key='id'))
roles = Field(dictof(Role, key='id')) roles = Field(dictof(Role, key='id'))
emojis = Field(dictof(Emoji, key='id')) emojis = Field(dictof(GuildEmoji, key='id'))
voice_states = Field(dictof(VoiceState, key='session_id')) voice_states = Field(dictof(VoiceState, key='session_id'))
member_count = Field(int) member_count = Field(int)
presences = Field(listof(Presence)) presences = Field(listof(Presence))

37
disco/types/message.py

@ -19,10 +19,24 @@ MessageType = Enum(
) )
class MessageReactionEmoji(SlottedModel): class Emoji(SlottedModel):
id = Field(snowflake) id = Field(snowflake)
name = Field(text) name = Field(text)
def __eq__(self, other):
if isinstance(other, Emoji):
return self.id == other.id and self.name == other.name
raise NotImplementedError
def to_string(self):
if self.id:
return '{}:{}'.format(self.name, self.id)
return self.name
class MessageReactionEmoji(Emoji):
pass
class MessageReaction(SlottedModel): class MessageReaction(SlottedModel):
emoji = Field(MessageReactionEmoji) emoji = Field(MessageReactionEmoji)
@ -261,6 +275,27 @@ class Message(SlottedModel):
""" """
return self.client.api.channels_messages_delete(self.channel_id, self.id) return self.client.api.channels_messages_delete(self.channel_id, self.id)
def create_reaction(self, emoji):
if isinstance(emoji, Emoji):
emoji = emoji.to_string()
self.client.api.channels_messages_reactions_create(
self.channel_id,
self.id,
emoji)
def delete_reaction(self, emoji, user=None):
if isinstance(emoji, Emoji):
emoji = emoji.to_string()
if user:
user = to_snowflake(user)
self.client.api.channels_messages_reactions_delete(
self.channel_id,
self.id,
emoji,
user)
def is_mentioned(self, entity): def is_mentioned(self, entity):
""" """
Returns Returns

31
disco/util/logging.py

@ -3,15 +3,24 @@ from __future__ import absolute_import
import logging import logging
LEVEL_OVERRIDES = {
'requests': logging.WARNING
}
def setup_logging(**kwargs):
logging.basicConfig(**kwargs)
for logger, level in LEVEL_OVERRIDES.items():
logging.getLogger(logger).setLevel(level)
class LoggingClass(object): class LoggingClass(object):
def __init__(self): __slots__ = ['_log']
self.log = logging.getLogger(self.__class__.__name__)
@property
def log_on_error(self, msg, f): def log(self):
def _f(*args, **kwargs): try:
try: return self._log
return f(*args, **kwargs) except AttributeError:
except: self._log = logging.getLogger(self.__class__.__name__)
self.log.exception(msg) return self._log
raise
return _f

Loading…
Cancel
Save