mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-03 18:42:43 +00:00
Optimise VoiceState for memory.
Instead of storing one VoiceState per Member, only store them if necessary. This should bring down the number of instances significantly.
This commit is contained in:
parent
044b0824e6
commit
31229a53e9
@ -117,8 +117,7 @@ class GroupCall:
|
||||
if data['channel_id'] is None:
|
||||
self._voice_states.pop(user_id, None)
|
||||
else:
|
||||
data['voice_channel'] = self.channel
|
||||
self._voice_states[user_id] = VoiceState(**data)
|
||||
self._voice_states[user_id] = VoiceState(data=data, channel=self.channel)
|
||||
|
||||
@property
|
||||
def connected(self):
|
||||
|
@ -31,9 +31,6 @@ from . import utils
|
||||
from .enums import Status, ChannelType, try_enum
|
||||
from .colour import Colour
|
||||
|
||||
import copy
|
||||
import inspect
|
||||
|
||||
class VoiceState:
|
||||
"""Represents a Discord user's voice state.
|
||||
|
||||
@ -49,32 +46,25 @@ class VoiceState:
|
||||
Indicates if the user is currently deafened by their own accord.
|
||||
is_afk: bool
|
||||
Indicates if the user is currently in the AFK channel in the server.
|
||||
voice_channel: Optional[Union[:class:`Channel`, :class:`PrivateChannel`]]
|
||||
channel: Optional[Union[:class:`Channel`, :class:`PrivateChannel`]]
|
||||
The voice channel that the user is currently connected to. None if the user
|
||||
is not currently in a voice channel.
|
||||
"""
|
||||
|
||||
__slots__ = ( 'session_id', 'deaf', 'mute', 'self_mute',
|
||||
'self_deaf', 'is_afk', 'voice_channel' )
|
||||
'self_deaf', 'is_afk', 'channel' )
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.session_id = kwargs.get('session_id')
|
||||
self._update_voice_state(**kwargs)
|
||||
def __init__(self, *, data, channel=None):
|
||||
self.session_id = data.get('session_id')
|
||||
self._update(data, channel)
|
||||
|
||||
def _update_voice_state(self, **kwargs):
|
||||
self.self_mute = kwargs.get('self_mute', False)
|
||||
self.self_deaf = kwargs.get('self_deaf', False)
|
||||
self.is_afk = kwargs.get('suppress', False)
|
||||
self.mute = kwargs.get('mute', False)
|
||||
self.deaf = kwargs.get('deaf', False)
|
||||
self.voice_channel = kwargs.get('voice_channel')
|
||||
|
||||
def flatten_voice_states(cls):
|
||||
for attr in VoiceState.__slots__:
|
||||
def getter(self, x=attr):
|
||||
return getattr(self.voice, x)
|
||||
setattr(cls, attr, property(getter))
|
||||
return cls
|
||||
def _update(self, data, channel):
|
||||
self.self_mute = data.get('self_mute', False)
|
||||
self.self_deaf = data.get('self_deaf', False)
|
||||
self.is_afk = data.get('suppress', False)
|
||||
self.mute = data.get('mute', False)
|
||||
self.deaf = data.get('deaf', False)
|
||||
self.channel = channel
|
||||
|
||||
def flatten_user(cls):
|
||||
for attr, value in User.__dict__.items():
|
||||
@ -107,7 +97,6 @@ def flatten_user(cls):
|
||||
|
||||
return cls
|
||||
|
||||
@flatten_voice_states
|
||||
@flatten_user
|
||||
class Member:
|
||||
"""Represents a Discord member to a :class:`Server`.
|
||||
@ -130,9 +119,6 @@ class Member:
|
||||
|
||||
Attributes
|
||||
----------
|
||||
voice: :class:`VoiceState`
|
||||
The member's voice state. Properties are defined to mirror access of the attributes.
|
||||
e.g. ``Member.is_afk`` is equivalent to `Member.voice.is_afk``.
|
||||
roles
|
||||
A list of :class:`Role` that the member belongs to. Note that the first element of this
|
||||
list is always the default '@everyone' role.
|
||||
@ -150,12 +136,11 @@ class Member:
|
||||
The server specific nickname of the user.
|
||||
"""
|
||||
|
||||
__slots__ = ('roles', 'joined_at', 'status', 'game', 'server', 'nick', 'voice', '_user', '_state')
|
||||
__slots__ = ('roles', 'joined_at', 'status', 'game', 'server', 'nick', '_user', '_state')
|
||||
|
||||
def __init__(self, *, data, server, state):
|
||||
self._state = state
|
||||
self._user = state.try_insert_user(data['user'])
|
||||
self.voice = VoiceState(**data)
|
||||
self.joined_at = utils.parse_time(data.get('joined_at'))
|
||||
self.roles = data.get('roles', [])
|
||||
self.status = Status.offline
|
||||
@ -176,36 +161,6 @@ class Member:
|
||||
def __hash__(self):
|
||||
return hash(self._user.id)
|
||||
|
||||
def _update_voice_state(self, **kwargs):
|
||||
self.voice.self_mute = kwargs.get('self_mute', False)
|
||||
self.voice.self_deaf = kwargs.get('self_deaf', False)
|
||||
self.voice.is_afk = kwargs.get('suppress', False)
|
||||
self.voice.mute = kwargs.get('mute', False)
|
||||
self.voice.deaf = kwargs.get('deaf', False)
|
||||
old_channel = getattr(self, 'voice_channel', None)
|
||||
vc = kwargs.get('voice_channel')
|
||||
|
||||
if old_channel is None and vc is not None:
|
||||
# we joined a channel
|
||||
vc.voice_members.append(self)
|
||||
elif old_channel is not None:
|
||||
try:
|
||||
# we either left a channel or we switched channels
|
||||
old_channel.voice_members.remove(self)
|
||||
except ValueError:
|
||||
pass
|
||||
finally:
|
||||
# we switched channels
|
||||
if vc is not None:
|
||||
vc.voice_members.append(self)
|
||||
|
||||
self.voice.voice_channel = vc
|
||||
|
||||
def _copy(self):
|
||||
ret = copy.copy(self)
|
||||
ret.voice = copy.copy(self.voice)
|
||||
return ret
|
||||
|
||||
def _update(self, data, user):
|
||||
self._user.name = user['username']
|
||||
self._user.discriminator = user['discriminator']
|
||||
@ -323,3 +278,8 @@ class Member:
|
||||
return Permissions.all()
|
||||
|
||||
return base
|
||||
|
||||
@property
|
||||
def voice(self):
|
||||
"""Optional[:class:`VoiceState`]: Returns the member's current voice state."""
|
||||
return self.server._voice_state_for(self._user.id)
|
||||
|
@ -26,13 +26,15 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from . import utils
|
||||
from .role import Role
|
||||
from .member import Member
|
||||
from .member import Member, VoiceState
|
||||
from .emoji import Emoji
|
||||
from .game import Game
|
||||
from .channel import Channel
|
||||
from .enums import ServerRegion, Status, try_enum, VerificationLevel
|
||||
from .mixins import Hashable
|
||||
|
||||
import copy
|
||||
|
||||
class Server(Hashable):
|
||||
"""Represents a Discord server.
|
||||
|
||||
@ -112,12 +114,13 @@ class Server(Hashable):
|
||||
'name', 'id', 'owner', 'unavailable', 'name', 'region',
|
||||
'_default_role', '_default_channel', 'roles', '_member_count',
|
||||
'large', 'owner_id', 'mfa_level', 'emojis', 'features',
|
||||
'verification_level', 'splash' )
|
||||
'verification_level', 'splash', '_voice_states' )
|
||||
|
||||
def __init__(self, *, data, state):
|
||||
self._channels = {}
|
||||
self.owner = None
|
||||
self._members = {}
|
||||
self._voice_states = {}
|
||||
self._state = state
|
||||
self._from_data(data)
|
||||
|
||||
@ -135,6 +138,9 @@ class Server(Hashable):
|
||||
def _remove_channel(self, channel):
|
||||
self._channels.pop(channel.id, None)
|
||||
|
||||
def _voice_state_for(self, user_id):
|
||||
return self._voice_states.get(user_id)
|
||||
|
||||
@property
|
||||
def members(self):
|
||||
return self._members.values()
|
||||
@ -153,15 +159,42 @@ class Server(Hashable):
|
||||
return self.name
|
||||
|
||||
def _update_voice_state(self, data):
|
||||
user_id = data.get('user_id')
|
||||
user_id = data['user_id']
|
||||
channel = self.get_channel(data['channel_id'])
|
||||
try:
|
||||
# check if we should remove the voice state from cache
|
||||
if channel is None:
|
||||
after = self._voice_states.pop(user_id)
|
||||
else:
|
||||
after = self._voice_states[user_id]
|
||||
|
||||
before = copy.copy(after)
|
||||
after._update(data, channel)
|
||||
except KeyError:
|
||||
# if we're here then we're getting added into the cache
|
||||
after = VoiceState(data=data, channel=channel)
|
||||
before = VoiceState(data=data, channel=None)
|
||||
self._voice_states[user_id] = after
|
||||
|
||||
member = self.get_member(user_id)
|
||||
before = None
|
||||
if member is not None:
|
||||
before = member._copy()
|
||||
ch_id = data.get('channel_id')
|
||||
channel = self.get_channel(ch_id)
|
||||
member._update_voice_state(voice_channel=channel, **data)
|
||||
return before, member
|
||||
old = before.channel
|
||||
# update the references pointed to by the voice channels
|
||||
if old is None and channel is not None:
|
||||
# we joined a channel
|
||||
channel.voice_members.append(member)
|
||||
elif old is not None:
|
||||
try:
|
||||
# we either left a channel or switched channels
|
||||
old.voice_members.remove(member)
|
||||
except ValueError:
|
||||
pass
|
||||
finally:
|
||||
# we switched channels
|
||||
if channel is not None:
|
||||
channel.voice_members.append(self)
|
||||
|
||||
return member, before, after
|
||||
|
||||
def _add_role(self, role):
|
||||
# roles get added to the bottom (position 1, pos 0 is @everyone)
|
||||
|
@ -340,7 +340,7 @@ class ConnectionState:
|
||||
member = self._make_member(server, data)
|
||||
server._add_member(member)
|
||||
|
||||
old_member = member._copy()
|
||||
old_member = copy.copy(member)
|
||||
member._presence_update(data=data, user=user)
|
||||
self.dispatch('member_update', old_member, member)
|
||||
|
||||
@ -431,12 +431,14 @@ class ConnectionState:
|
||||
server._member_count -= 1
|
||||
|
||||
# remove them from the voice channel member list
|
||||
vc = member.voice_channel
|
||||
if vc is not None:
|
||||
try:
|
||||
vc.voice_members.remove(member)
|
||||
except:
|
||||
pass
|
||||
vc = server._voice_state_for(user_id)
|
||||
if vc:
|
||||
voice_channel = vc.channel
|
||||
if voice_channel is not None:
|
||||
try:
|
||||
voice_channel.voice_members.remove(member)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.dispatch('member_remove', member)
|
||||
|
||||
@ -446,7 +448,7 @@ class ConnectionState:
|
||||
user_id = user['id']
|
||||
member = server.get_member(user_id)
|
||||
if member is not None:
|
||||
old_member = member._copy()
|
||||
old_member = copy.copy(member)
|
||||
member._update(data, user)
|
||||
self.dispatch('member_update', old_member, member)
|
||||
|
||||
@ -620,15 +622,14 @@ class ConnectionState:
|
||||
def parse_voice_state_update(self, data):
|
||||
server = self._get_server(data.get('guild_id'))
|
||||
if server is not None:
|
||||
channel = server.get_channel(data.get('channel_id'))
|
||||
if data.get('user_id') == self.user.id:
|
||||
voice = self._get_voice_client(server.id)
|
||||
if voice is not None:
|
||||
voice.channel = channel
|
||||
voice.channel = server.get_channel(data.get('channel_id'))
|
||||
|
||||
before, after = server._update_voice_state(data)
|
||||
member, before, after = server._update_voice_state(data)
|
||||
if after is not None:
|
||||
self.dispatch('voice_state_update', before, after)
|
||||
self.dispatch('voice_state_update', member, before, after)
|
||||
else:
|
||||
# in here we're either at private or group calls
|
||||
call = self._calls.get(data.get('channel_id'), None)
|
||||
|
Loading…
x
Reference in New Issue
Block a user