mirror of
https://github.com/stoatchat/python-client-sdk.git
synced 2026-07-21 01:55:23 -04:00
handle server join event
This commit is contained in:
+5
-1
@@ -35,10 +35,13 @@ class Member(User):
|
||||
|
||||
def __init__(self, data: MemberPayload, server: Server, state: State):
|
||||
user = state.get_user(data["_id"]["user"])
|
||||
|
||||
# due to not having a user payload and only a user object we have to manually add all the attributes instead of calling User.__init__
|
||||
|
||||
flattern_user(self, user)
|
||||
user._members.append(self)
|
||||
|
||||
self._state = state
|
||||
self.nickname = data.get("nickname")
|
||||
|
||||
if avatar := data.get("avatar"):
|
||||
self.guild_avatar = Asset(avatar, state)
|
||||
@@ -49,6 +52,7 @@ class Member(User):
|
||||
self.roles = sorted(roles, key=lambda role: role.rank, reverse=True)
|
||||
|
||||
self.server = server
|
||||
self.nickname = data.get("nickname")
|
||||
|
||||
@property
|
||||
def avatar(self) -> Optional[Asset]:
|
||||
|
||||
+9
-8
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
||||
from .types import Masquerade as MasqueradePayload
|
||||
from .types import Message as MessagePayload
|
||||
from .types import MessageReplyPayload
|
||||
|
||||
from .server import Server
|
||||
|
||||
__all__ = (
|
||||
"Message",
|
||||
@@ -36,8 +36,6 @@ class Message:
|
||||
The embeds of the message
|
||||
channel: :class:`Messageable`
|
||||
The channel the message was sent in
|
||||
server: :class:`Server`
|
||||
The server the message was sent in
|
||||
author: Union[:class:`Member`, :class:`User`]
|
||||
The author of the message, will be :class:`User` in DMs
|
||||
edited_at: Optional[:class:`datetime.datetime`]
|
||||
@@ -49,7 +47,7 @@ class Message:
|
||||
reply_ids: list[:class:`str`]
|
||||
The message's ids this message has replies to
|
||||
"""
|
||||
__slots__ = ("state", "id", "content", "attachments", "embeds", "channel", "server", "author", "edited_at", "mentions", "replies", "reply_ids")
|
||||
__slots__ = ("state", "id", "content", "attachments", "embeds", "channel", "author", "edited_at", "mentions", "replies", "reply_ids")
|
||||
|
||||
def __init__(self, data: MessagePayload, state: State):
|
||||
self.state = state
|
||||
@@ -63,10 +61,8 @@ class Message:
|
||||
assert isinstance(channel, Messageable)
|
||||
self.channel = channel
|
||||
|
||||
self.server = self.channel and self.channel.server
|
||||
|
||||
if self.server:
|
||||
author = state.get_member(self.server.id, data["author"])
|
||||
if server_id := self.channel.server_id:
|
||||
author = state.get_member(server_id, data["author"])
|
||||
else:
|
||||
author = state.get_user(data["author"])
|
||||
|
||||
@@ -135,6 +131,11 @@ class Message:
|
||||
"""
|
||||
return self.channel.send(*args, **kwargs, replies=[MessageReply(self, mention)])
|
||||
|
||||
@property
|
||||
def server(self) -> Server:
|
||||
""":class:`Server` The server this voice channel belongs too"""
|
||||
return self.channel.server
|
||||
|
||||
class MessageReply(NamedTuple):
|
||||
"""A namedtuple which represents a reply to a message.
|
||||
|
||||
|
||||
+10
-7
@@ -93,12 +93,15 @@ class State:
|
||||
|
||||
raise LookupError
|
||||
|
||||
async def fetch_server_members(self, server_id: str):
|
||||
data = await self.http.fetch_members(server_id)
|
||||
|
||||
for user in data["users"]:
|
||||
self.add_user(user)
|
||||
|
||||
for member in data["members"]:
|
||||
self.add_member(server_id, member)
|
||||
|
||||
async def fetch_all_server_members(self):
|
||||
for server_id in self.servers:
|
||||
data = await self.http.fetch_members(server_id)
|
||||
|
||||
for user in data["users"]:
|
||||
self.add_user(user)
|
||||
|
||||
for member in data["members"]:
|
||||
self.add_member(server_id, member)
|
||||
await self.fetch_server_members(server_id)
|
||||
|
||||
@@ -38,7 +38,8 @@ __all__ = (
|
||||
"ServerRoleUpdateEventPayload",
|
||||
"ServerRoleDeleteEventPayload",
|
||||
"UserUpdateEventPayload",
|
||||
"UserRelationshipEventPayload"
|
||||
"UserRelationshipEventPayload",
|
||||
"ServerCreateEventPayload"
|
||||
)
|
||||
|
||||
class BasePayload(TypedDict):
|
||||
@@ -130,6 +131,11 @@ class ServerUpdateEventPayload(BasePayload):
|
||||
class ServerDeleteEventPayload(BasePayload):
|
||||
id: str
|
||||
|
||||
class ServerCreateEventPayload(BasePayload):
|
||||
id: str
|
||||
server: Server
|
||||
channels: list[Channel]
|
||||
|
||||
class ServerMemberUpdateEventPayloadData(TypedDict, total=False):
|
||||
nickname: str
|
||||
avatar: File
|
||||
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, NamedTuple, Optional, Union
|
||||
from typing import TYPE_CHECKING, Literal, NamedTuple, Optional, Union
|
||||
|
||||
from .asset import Asset, PartialAsset
|
||||
from .channel import DMChannel
|
||||
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
||||
from .types import File
|
||||
from .types import Status as StatusPayload
|
||||
from .types import User as UserPayload
|
||||
|
||||
from .member import Member
|
||||
|
||||
__all__ = ("User", "Status", "Relation", "UserProfile")
|
||||
|
||||
@@ -59,10 +59,11 @@ class User(Messageable):
|
||||
The dm channel between the client and the user, this will only be set if the client has dm'ed the user or :meth:`User.open_dm` was run
|
||||
"""
|
||||
__flattern_attributes__ = ("id", "bot", "owner_id", "badges", "online", "flags", "relations", "relationship", "status", "masquerade_avatar", "masquerade_name", "original_name", "original_avatar", "profile", "dm_channel")
|
||||
__slots__ = (*__flattern_attributes__, "state")
|
||||
__slots__ = (*__flattern_attributes__, "state", "_members")
|
||||
|
||||
def __init__(self, data: UserPayload, state: State):
|
||||
self.state = state
|
||||
self._members: list[Member] = [] # we store all member versions of this user to avoid having to check every guild when needing to update.
|
||||
self.id = data["_id"]
|
||||
self.original_name = data["username"]
|
||||
self.dm_channel = None
|
||||
@@ -153,6 +154,11 @@ class User(Messageable):
|
||||
if online:
|
||||
self.online = online
|
||||
|
||||
# update user infomation for all members
|
||||
|
||||
for member in self._members:
|
||||
User._update(member, status=status, profile_content=profile_content, profile_background=profile_background, avatar=avatar, online=online)
|
||||
|
||||
async def default_avatar(self) -> bytes:
|
||||
"""Returns the default avatar for this user
|
||||
|
||||
|
||||
+63
-1
@@ -15,6 +15,7 @@ from .types import Message as MessagePayload
|
||||
from .types import (MessageDeleteEventPayload, MessageUpdateEventPayload,
|
||||
ServerDeleteEventPayload, ServerMemberJoinEventPayload,
|
||||
ServerMemberLeaveEventPayload,
|
||||
ServerCreateEventPayload,
|
||||
ServerMemberUpdateEventPayload,
|
||||
ServerRoleDeleteEventPayload, ServerRoleUpdateEventPayload,
|
||||
ServerUpdateEventPayload, UserRelationshipEventPayload,
|
||||
@@ -46,7 +47,7 @@ __all__ = ("WebsocketHandler",)
|
||||
logger = logging.getLogger("revolt")
|
||||
|
||||
class WebsocketHandler:
|
||||
__slots__ = ("session", "token", "ws_url", "dispatch", "state", "websocket", "loop", "user", "ready")
|
||||
__slots__ = ("session", "token", "ws_url", "dispatch", "state", "websocket", "loop", "user", "ready", "server_events")
|
||||
|
||||
def __init__(self, session: aiohttp.ClientSession, token: str, ws_url: str, dispatch: Callable[..., None], state: State):
|
||||
self.session = session
|
||||
@@ -58,6 +59,11 @@ class WebsocketHandler:
|
||||
self.loop = asyncio.get_running_loop()
|
||||
self.user = None
|
||||
self.ready = asyncio.Event()
|
||||
self.server_events: dict[str, asyncio.Event] = {}
|
||||
|
||||
async def _wait_for_server_ready(self, server_id: str):
|
||||
if event := self.server_events.get(server_id):
|
||||
await event.wait()
|
||||
|
||||
async def send_payload(self, payload: BasePayload):
|
||||
if use_msgpack:
|
||||
@@ -120,6 +126,10 @@ class WebsocketHandler:
|
||||
|
||||
async def handle_message(self, payload: MessageEventPayload):
|
||||
message = self.state.add_message(cast(MessagePayload, payload))
|
||||
|
||||
if server := message.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("message", message)
|
||||
|
||||
async def handle_messageupdate(self, payload: MessageUpdateEventPayload):
|
||||
@@ -140,6 +150,9 @@ class WebsocketHandler:
|
||||
|
||||
message._update(**kwargs)
|
||||
|
||||
if server := message.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("message_update", message)
|
||||
|
||||
async def handle_messagedelete(self, payload: MessageDeleteEventPayload):
|
||||
@@ -151,11 +164,18 @@ class WebsocketHandler:
|
||||
return
|
||||
|
||||
self.state.messages.remove(message)
|
||||
|
||||
if server := message.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("message_delete", message)
|
||||
|
||||
async def handle_channelcreate(self, payload: ChannelCreateEventPayload):
|
||||
channel = self.state.add_channel(payload)
|
||||
|
||||
if server := channel.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("channel_create", channel)
|
||||
|
||||
async def handle_channelupdate(self, payload: ChannelUpdateEventPayload):
|
||||
@@ -174,23 +194,35 @@ class WebsocketHandler:
|
||||
if isinstance(channel, (TextChannel, VoiceChannel, GroupDMChannel)):
|
||||
channel.description = None
|
||||
|
||||
if server := channel.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("channel_update", old_channel, channel)
|
||||
|
||||
async def handle_channeldelete(self, payload: ChannelDeleteEventPayload):
|
||||
channel = self.state.channels.pop(payload["id"])
|
||||
|
||||
if server := channel.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("channel_delete", channel)
|
||||
|
||||
async def handle_channelstarttyping(self, payload: ChannelStartTypingEventPayload):
|
||||
channel = self.state.get_channel(payload["id"])
|
||||
user = self.state.get_user(payload["user"])
|
||||
|
||||
if server := channel.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("typing_start", channel, user)
|
||||
|
||||
async def handle_channelstoptyping(self, payload: ChannelDeleteTypingEventPayload):
|
||||
channel = self.state.get_channel(payload["id"])
|
||||
user = self.state.get_user(payload["user"])
|
||||
|
||||
if server := channel.server:
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("typing_stop", channel, user)
|
||||
|
||||
async def handle_serverupdate(self, payload: ServerUpdateEventPayload):
|
||||
@@ -210,6 +242,8 @@ class WebsocketHandler:
|
||||
elif clear == "Description":
|
||||
server.description = None
|
||||
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("server_update", old_server, server)
|
||||
|
||||
async def handle_serverdelete(self, payload: ServerDeleteEventPayload):
|
||||
@@ -218,9 +252,26 @@ class WebsocketHandler:
|
||||
for channel in server.channels:
|
||||
del self.state.channels[channel.id]
|
||||
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("server_delete", server)
|
||||
|
||||
async def handle_servercreate(self, payload: ServerCreateEventPayload):
|
||||
for channel in payload["channels"]:
|
||||
self.state.add_channel(channel)
|
||||
|
||||
server = self.state.add_server(payload["server"])
|
||||
|
||||
# lock all server events until we fetch all the members, otherwise the cache will be incomplete
|
||||
self.server_events[server.id] = asyncio.Event()
|
||||
await self.state.fetch_server_members(server.id)
|
||||
self.server_events.pop(server.id).set()
|
||||
|
||||
self.dispatch("server_create", server)
|
||||
|
||||
async def handle_servermemberupdate(self, payload: ServerMemberUpdateEventPayload):
|
||||
await self._wait_for_server_ready(payload["id"]["server"])
|
||||
|
||||
member = self.state.get_member(payload["id"]["server"], payload["id"]["user"])
|
||||
old_member = copy(member)
|
||||
|
||||
@@ -239,9 +290,16 @@ class WebsocketHandler:
|
||||
self.dispatch("member_join", member)
|
||||
|
||||
async def handle_memberleave(self, payload: ServerMemberLeaveEventPayload):
|
||||
await self._wait_for_server_ready(payload["id"])
|
||||
|
||||
server = self.state.get_server(payload["id"])
|
||||
member = server._members.pop(payload["user"])
|
||||
|
||||
# remove the member from the user
|
||||
|
||||
user = self.state.get_user(payload["user"])
|
||||
user._members.remove(member)
|
||||
|
||||
self.dispatch("member_leave", member)
|
||||
|
||||
async def handle_serveroleupdate(self, payload: ServerRoleUpdateEventPayload):
|
||||
@@ -255,12 +313,16 @@ class WebsocketHandler:
|
||||
|
||||
role._update(**payload["data"])
|
||||
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("role_update", old_role, role)
|
||||
|
||||
async def handle_serverroledelete(self, payload: ServerRoleDeleteEventPayload):
|
||||
server = self.state.get_server(payload["id"])
|
||||
role = server._roles.pop(payload["role_id"])
|
||||
|
||||
await self._wait_for_server_ready(server.id)
|
||||
|
||||
self.dispatch("role_delete", role)
|
||||
|
||||
async def handle_userupdate(self, payload: UserUpdateEventPayload):
|
||||
|
||||
Reference in New Issue
Block a user