pubsub.lazy_guild: bugfixes and better role_* methods

this fixes role_create and role_delete, adds more debug logging
to understand what is going on, etc.

 - pubsub.lazy_guild: promote role_update -> new_role when updating to
    hoist=True
 - pubsub.lazy_guild: promote role_update -> role_delete when updating
    to hoist=False
 - pubsub.lazy_guild: better handling of unknown group items on
    role_delete
This commit is contained in:
Luna Mendes 2018-11-09 03:56:00 -03:00
parent 5fa5aac2f5
commit 1d7a71a6ad
1 changed files with 59 additions and 17 deletions

View File

@ -276,14 +276,10 @@ class GuildMemberList:
async def set_groups(self): async def set_groups(self):
"""Get the groups for the member list.""" """Get the groups for the member list."""
role_groups = await self.get_roles() role_groups = await self.get_roles()
role_ids = [g.gid for g in role_groups]
self.list.groups = role_ids + ['online', 'offline']
# inject default groups 'online' and 'offline' # inject default groups 'online' and 'offline'
# their position is always going to be the last ones. # their position is always going to be the last ones.
self.list.groups = role_ids + [ self.list.groups = role_groups + [
GroupInfo('online', 'online', MAX_ROLES + 1, 0), GroupInfo('online', 'online', MAX_ROLES + 1, 0),
GroupInfo('offline', 'offline', MAX_ROLES + 2, 0) GroupInfo('offline', 'offline', MAX_ROLES + 2, 0)
] ]
@ -385,7 +381,7 @@ class GuildMemberList:
for group, presences in self.list: for group, presences in self.list:
res.append({ res.append({
'group': { 'group': {
'id': group.gid, 'id': str(group.gid),
'count': len(presences), 'count': len(presences),
} }
}) })
@ -436,7 +432,7 @@ class GuildMemberList:
'groups': [ 'groups': [
{ {
'count': len(presences), 'count': len(presences),
'id': group.gid 'id': str(group.gid),
} for group, presences in self.list } for group, presences in self.list
], ],
@ -707,10 +703,15 @@ class GuildMemberList:
Only adds the new role to the list if the role Only adds the new role to the list if the role
has the necessary permissions to start with. has the necessary permissions to start with.
""" """
if not self.list:
return
group_id = int(role['id']) group_id = int(role['id'])
new_group = GroupInfo(group_id, role['name'], new_group = GroupInfo(
role['position'], role['permisions']) group_id, role['name'],
role['position'], Permissions(role['permissions'])
)
# check if new role has good perms # check if new role has good perms
await self._fetch_overwrites() await self._fetch_overwrites()
@ -719,6 +720,9 @@ class GuildMemberList:
log.info('ignoring incoming group {}', new_group) log.info('ignoring incoming group {}', new_group)
return return
log.debug('new_role: inserted rid={} (gid={}, cid={})',
group_id, self.guild_id, self.channel_id)
# maintain role sorting # maintain role sorting
self.list.groups.insert(role['position'], new_group) self.list.groups.insert(role['position'], new_group)
@ -745,8 +749,8 @@ class GuildMemberList:
- role is not found inside the group list. - role is not found inside the group list.
""" """
if not self.list: if not self.list:
log.warning('uninitialized list for rid={}', log.warning('uninitialized list for gid={} cid={} rid={}',
role_id) self.guild_id, self.channel_id, role_id)
return None return None
groups_idx = index_by_func( groups_idx = index_by_func(
@ -793,10 +797,22 @@ class GuildMemberList:
the group if it lost the permissions to the group if it lost the permissions to
read the channel. read the channel.
""" """
if not self.list:
return
role_id = int(role['id']) role_id = int(role['id'])
group_idx = self._get_role_as_group_idx(role_id) group_idx = self._get_role_as_group_idx(role_id)
if not group_idx and role['hoist']:
# this is a new group, so we'll treat it accordingly.
log.debug('role_update promote to new_role call rid={}',
role_id)
return await self.new_role(role)
if not group_idx: if not group_idx:
log.debug('role is not group {} (gid={}, cid={})',
role_id, self.guild_id, self.channel_id)
return return
group = self.list.groups[group_idx] group = self.list.groups[group_idx]
@ -812,12 +828,20 @@ class GuildMemberList:
# respective GUILD_MEMBER_LIST_UPDATE events # respective GUILD_MEMBER_LIST_UPDATE events
# down to the subscribers. # down to the subscribers.
if not self._can_read_chan(group): if not self._can_read_chan(group):
log.debug('role_update promote to role_delete '
'call rid={} (lost perms)',
role_id)
return await self.role_delete(role_id)
if not role['hoist']:
log.debug('role_update promote to role_delete '
'call rid={} (no hoist)',
role_id)
return await self.role_delete(role_id) return await self.role_delete(role_id)
async def role_delete(self, role_id: int): async def role_delete(self, role_id: int):
"""Called when a role is deleted, so we should """Called when a role is deleted, so we should
delete it off the list.""" delete it off the list."""
if not self.list: if not self.list:
return return
@ -830,7 +854,19 @@ class GuildMemberList:
self.items self.items
) )
sess_ids_resync = self.get_subs(role_item_index) # we only resync when we actually have an item to resync
# we don't have items to resync when we:
# - a role without users is losing hoist
# - the role isn't a group to begin with
# we convert the get_subs result to a list
# so we have all the states to resync with.
# using a filter object would cause problems
# as we only resync AFTER we delete the group
sess_ids_resync = (list(self.get_subs(role_item_index))
if role_item_index is not None
else [])
# remove the group info off the list # remove the group info off the list
groups_index = index_by_func( groups_index = index_by_func(
@ -859,11 +895,16 @@ class GuildMemberList:
try: try:
self.list.overwrites.pop(role_id) self.list.overwrites.pop(role_id)
except KeyError: except KeyError:
log.warning('list unstable: {} not in overwrites dict', role_id) # don't need to log as not having a overwrite
# is acceptable behavior.
pass
# after removing, we do a resync with the # after removing, we do a resync with the
# shards that had the group. # shards that had the group.
log.info('role_delete rid={} (gid={}, cid={})',
role_id, self.guild_id, self.channel_id)
for session_id in sess_ids_resync: for session_id in sess_ids_resync:
# find the list range that the group was on # find the list range that the group was on
# so we resync only the given range, instead # so we resync only the given range, instead
@ -938,17 +979,18 @@ class LazyGuildDispatcher(Dispatcher):
async def dispatch(self, guild_id, event: str, *args, **kwargs): async def dispatch(self, guild_id, event: str, *args, **kwargs):
"""Call a function specialized in handling the given event""" """Call a function specialized in handling the given event"""
try: try:
handler = getattr(self, f'_handle_{event}') handler = getattr(self, f'_handle_{event.lower()}')
await handler(guild_id, *args, **kwargs)
except AttributeError: except AttributeError:
log.warning('unknown event: {}', event) log.warning('unknown event: {}', event)
return return
await handler(guild_id, *args, **kwargs)
async def _call_all_lists(self, guild_id, method_str: str, *args): async def _call_all_lists(self, guild_id, method_str: str, *args):
lists = self.get_gml_guild(guild_id) lists = self.get_gml_guild(guild_id)
log.debug('calling method={} to all {} lists', log.debug('calling method={} to all {} lists',
method, len(lists)) method_str, len(lists))
for lazy_list in lists: for lazy_list in lists:
method = getattr(lazy_list, method_str) method = getattr(lazy_list, method_str)