mirror of https://gitlab.com/litecord/litecord.git
guild.members: add basic handling of nicks in lazy guilds
- pubsub.lazy_guilds: add a list lock to prevent inconsistencies - pubsub.lazy_guilds: add a lot of debug info related to list sorting
This commit is contained in:
parent
f34c3f6296
commit
864f6a5d9f
|
|
@ -101,6 +101,7 @@ async def modify_guild_member(guild_id, member_id):
|
||||||
await guild_owner_check(user_id, guild_id)
|
await guild_owner_check(user_id, guild_id)
|
||||||
|
|
||||||
j = validate(await request.get_json(), MEMBER_UPDATE)
|
j = validate(await request.get_json(), MEMBER_UPDATE)
|
||||||
|
nick_flag = False
|
||||||
|
|
||||||
if 'nick' in j:
|
if 'nick' in j:
|
||||||
# TODO: check MANAGE_NICKNAMES
|
# TODO: check MANAGE_NICKNAMES
|
||||||
|
|
@ -111,6 +112,8 @@ async def modify_guild_member(guild_id, member_id):
|
||||||
WHERE user_id = $2 AND guild_id = $3
|
WHERE user_id = $2 AND guild_id = $3
|
||||||
""", j['nick'], member_id, guild_id)
|
""", j['nick'], member_id, guild_id)
|
||||||
|
|
||||||
|
nick_flag = True
|
||||||
|
|
||||||
if 'mute' in j:
|
if 'mute' in j:
|
||||||
# TODO: check MUTE_MEMBERS
|
# TODO: check MUTE_MEMBERS
|
||||||
|
|
||||||
|
|
@ -141,14 +144,16 @@ async def modify_guild_member(guild_id, member_id):
|
||||||
member = await app.storage.get_member_data_one(guild_id, member_id)
|
member = await app.storage.get_member_data_one(guild_id, member_id)
|
||||||
member.pop('joined_at')
|
member.pop('joined_at')
|
||||||
|
|
||||||
lazy_guilds = app.dispatcher.backends['lazy_guild']
|
# call pres_update for role and nick changes.
|
||||||
lists = lazy_guilds.get_gml_guild(guild_id)
|
partial = {
|
||||||
|
'roles': member['roles']
|
||||||
|
}
|
||||||
|
|
||||||
for member_list in lists:
|
if nick_flag:
|
||||||
# just call pres_update but only for role changes.
|
partial['nick'] = j['nick']
|
||||||
await member_list.pres_update(member_id, {
|
|
||||||
'roles': member['roles'],
|
await app.dispatcher.dispatch(
|
||||||
})
|
'lazy_guild', guild_id, 'pres_update', user_id, partial)
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_UPDATE', {**{
|
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_UPDATE', {**{
|
||||||
'guild_id': str(guild_id)
|
'guild_id': str(guild_id)
|
||||||
|
|
@ -174,6 +179,12 @@ async def update_nickname(guild_id):
|
||||||
member = await app.storage.get_member_data_one(guild_id, user_id)
|
member = await app.storage.get_member_data_one(guild_id, user_id)
|
||||||
member.pop('joined_at')
|
member.pop('joined_at')
|
||||||
|
|
||||||
|
# call pres_update for nick changes, etc.
|
||||||
|
await app.dispatcher.dispatch(
|
||||||
|
'lazy_guild', guild_id, 'pres_update', user_id, {
|
||||||
|
'nick': j['nick']
|
||||||
|
})
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_UPDATE', {**{
|
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_UPDATE', {**{
|
||||||
'guild_id': str(guild_id)
|
'guild_id': str(guild_id)
|
||||||
}, **member})
|
}, **member})
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ class GatewayWebsocket:
|
||||||
if len(encoded) < 1024:
|
if len(encoded) < 1024:
|
||||||
log.debug('sending\n{}', pprint.pformat(payload))
|
log.debug('sending\n{}', pprint.pformat(payload))
|
||||||
else:
|
else:
|
||||||
log.debug('sending {}', pprint.pformat(payload))
|
# log.debug('sending {}', pprint.pformat(payload))
|
||||||
log.debug('sending op={} s={} t={} (too big)',
|
log.debug('sending op={} s={} t={} (too big)',
|
||||||
payload.get('op'),
|
payload.get('op'),
|
||||||
payload.get('s'),
|
payload.get('s'),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
Main code for Lazy Guild implementation in litecord.
|
Main code for Lazy Guild implementation in litecord.
|
||||||
"""
|
"""
|
||||||
import pprint
|
import pprint
|
||||||
|
import asyncio
|
||||||
from dataclasses import dataclass, asdict
|
from dataclasses import dataclass, asdict
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, List, Dict, Union
|
from typing import Any, List, Dict, Union
|
||||||
|
|
@ -164,6 +165,8 @@ class GuildMemberList:
|
||||||
# type is{session_id: set[list]}
|
# type is{session_id: set[list]}
|
||||||
self.state = defaultdict(set)
|
self.state = defaultdict(set)
|
||||||
|
|
||||||
|
self._list_lock = asyncio.Lock()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def loop(self):
|
def loop(self):
|
||||||
"""Get the main asyncio loop instance."""
|
"""Get the main asyncio loop instance."""
|
||||||
|
|
@ -342,9 +345,13 @@ class GuildMemberList:
|
||||||
|
|
||||||
# this should update the list in-place
|
# this should update the list in-place
|
||||||
group_members.sort(
|
group_members.sort(
|
||||||
key=lambda p: display_name(member_nicks, p))
|
key=lambda p: display_name(member_nicks, p),
|
||||||
|
reverse=True)
|
||||||
|
|
||||||
async def _init_member_list(self):
|
print('post sort')
|
||||||
|
pprint.pprint(group_members)
|
||||||
|
|
||||||
|
async def __init_member_list(self):
|
||||||
"""Generate the main member list with groups."""
|
"""Generate the main member list with groups."""
|
||||||
member_ids = await self.storage.get_member_ids(self.guild_id)
|
member_ids = await self.storage.get_member_ids(self.guild_id)
|
||||||
|
|
||||||
|
|
@ -367,6 +374,13 @@ class GuildMemberList:
|
||||||
# by the display name
|
# by the display name
|
||||||
await self._sort_groups()
|
await self._sort_groups()
|
||||||
|
|
||||||
|
async def _init_member_list(self):
|
||||||
|
try:
|
||||||
|
await self._list_lock.acquire()
|
||||||
|
await self.__init_member_list()
|
||||||
|
finally:
|
||||||
|
self._list_lock.release()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def items(self) -> list:
|
def items(self) -> list:
|
||||||
"""Main items list."""
|
"""Main items list."""
|
||||||
|
|
@ -597,22 +611,31 @@ class GuildMemberList:
|
||||||
for presence in presences:
|
for presence in presences:
|
||||||
name = display_name(member_nicks, presence)
|
name = display_name(member_nicks, presence)
|
||||||
|
|
||||||
print(name, current_name, name < current_name)
|
print(name, current_name, current_name < name)
|
||||||
|
|
||||||
# TODO: check if this works
|
# TODO: check if this works
|
||||||
if name < current_name:
|
if current_name < name:
|
||||||
break
|
break
|
||||||
|
|
||||||
best_index += 1
|
best_index += 1
|
||||||
|
|
||||||
# insert the presence at the index
|
# insert the presence at the index
|
||||||
presences.insert(best_index + 1, current_presence)
|
print('pre insert')
|
||||||
|
pprint.pprint(presences)
|
||||||
|
|
||||||
|
presences.insert(best_index - 1, current_presence)
|
||||||
|
log.debug('inserted cur pres @ pres idx {}', best_index - 1)
|
||||||
|
|
||||||
|
print('post insert')
|
||||||
|
pprint.pprint(presences)
|
||||||
|
|
||||||
new_item_index = self.get_item_index(user_id)
|
new_item_index = self.get_item_index(user_id)
|
||||||
|
|
||||||
log.debug('assigned new item index {} to uid {}',
|
log.debug('assigned new item index {} to uid {}',
|
||||||
new_item_index, user_id)
|
new_item_index, user_id)
|
||||||
|
|
||||||
|
print('items')
|
||||||
|
pprint.pprint(self.items)
|
||||||
|
|
||||||
session_ids_old = self.get_subs(old_item_index)
|
session_ids_old = self.get_subs(old_item_index)
|
||||||
session_ids_new = self.get_subs(new_item_index)
|
session_ids_new = self.get_subs(new_item_index)
|
||||||
|
|
||||||
|
|
@ -644,21 +667,32 @@ class GuildMemberList:
|
||||||
- from 'offline' to any
|
- from 'offline' to any
|
||||||
- from any to 'offline'
|
- from any to 'offline'
|
||||||
- from any to any
|
- from any to any
|
||||||
- from G to G (with G being any group)
|
- from G to G (with G being any group), while changing position
|
||||||
|
- from G to G (with G being any group), but not changing position
|
||||||
|
|
||||||
any: 'online' | role_id
|
any: 'online' | role_id
|
||||||
|
|
||||||
All first, second, and third updates are 'complex' updates,
|
All 1st, 2nd, 3rd, and 4th updates are 'complex' updates,
|
||||||
which means we'll have to change the group the user is on
|
which means we'll have to change the group the user is on
|
||||||
to account for them.
|
to account for them, or we'll change the position a user
|
||||||
|
is in inside a group (for the 4th update).
|
||||||
|
|
||||||
The fourth is a 'simple' change, since we're not changing
|
The fifth is a 'simple' change, since we're not changing
|
||||||
the group a user is on, and so there's less overhead
|
the group a user is on, and so there's less overhead
|
||||||
involved.
|
involved.
|
||||||
"""
|
"""
|
||||||
await self._init_check()
|
await self._init_check()
|
||||||
|
|
||||||
old_group, old_index, old_presence = None, None, None
|
old_group, old_index, old_presence = None, None, None
|
||||||
|
has_nick = 'nick' in partial_presence
|
||||||
|
|
||||||
|
# partial presences don't have 'nick'. we only use it
|
||||||
|
# as a flag that we're doing a mixed update (complex
|
||||||
|
# but without any inter-group changes)
|
||||||
|
try:
|
||||||
|
partial_presence.pop('nick')
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
for group, presences in self.list:
|
for group, presences in self.list:
|
||||||
p_idx = index_by_func(
|
p_idx = index_by_func(
|
||||||
|
|
@ -694,9 +728,9 @@ class GuildMemberList:
|
||||||
log.debug('pres update: gid={} cid={} old_g={} new_g={}',
|
log.debug('pres update: gid={} cid={} old_g={} new_g={}',
|
||||||
self.guild_id, self.channel_id, old_group, new_group)
|
self.guild_id, self.channel_id, old_group, new_group)
|
||||||
|
|
||||||
# if we're going to the same group,
|
# if we're going to the same group AND there are no
|
||||||
# treat this as a simple update
|
# nickname changes, treat this as a simple update
|
||||||
if old_group == new_group:
|
if old_group == new_group and not has_nick:
|
||||||
return await self._pres_update_simple(user_id)
|
return await self._pres_update_simple(user_id)
|
||||||
|
|
||||||
return await self._pres_update_complex(
|
return await self._pres_update_complex(
|
||||||
|
|
@ -1039,3 +1073,8 @@ class LazyGuildDispatcher(Dispatcher):
|
||||||
|
|
||||||
async def _handle_role_delete(self, guild_id, role_id: int):
|
async def _handle_role_delete(self, guild_id, role_id: int):
|
||||||
await self._call_all_lists(guild_id, 'role_delete', role_id)
|
await self._call_all_lists(guild_id, 'role_delete', role_id)
|
||||||
|
|
||||||
|
async def _handle_pres_update(self, guild_id, user_id: int,
|
||||||
|
partial: dict):
|
||||||
|
await self._call_all_lists(
|
||||||
|
guild_id, 'pres_update', user_id, partial)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue