add the rest of the events

This commit is contained in:
Zomatree
2021-11-08 13:59:16 +00:00
parent 611939ed6f
commit 1310f3a31a
7 changed files with 208 additions and 13 deletions
+7
View File
@@ -165,3 +165,10 @@ class Client:
self.listeners.setdefault(event, []).append((check, future))
return await asyncio.wait_for(future, timeout)
@property
def user(self) -> User:
user = self.websocket.user
assert user
return user
+12
View File
@@ -54,3 +54,15 @@ class Member(User):
def avatar(self) -> Optional[Asset]:
"""Optional[:class:`Asset`] The avatar the member is displaying, this includes guild avatars and masqueraded avatar"""
return self.masquerade_avatar or self.guild_avatar or self.original_avatar
def _update(self, *, nickname: Optional[str] = None, avatar: Optional[File] = None, roles: Optional[list[str]] = None):
if nickname:
self.nickname = nickname
if avatar:
self.guild_avatar = Asset(avatar, self.state)
if roles:
member_roles = [self.server.get_role(role_id) for role_id in roles]
self.roles = sorted(member_roles, key=lambda role: role.rank, reverse=True)
+14 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional
from .permissions import ServerPermissions
@@ -56,3 +56,16 @@ class Role:
The new permissions for the role
"""
await self.state.http.set_role_permissions(self.server.id, self.id, *permissions.value)
def _update(self, *, name: Optional[str] = None, colour: Optional[str] = None, hoist: Optional[bool] = None, rank: Optional[int] = None):
if name:
self.name = name
if colour:
self.colour = colour
if hoist:
self.hoist = hoist
if rank:
self.rank = rank
+1 -1
View File
@@ -111,7 +111,7 @@ class Server:
self._members: dict[str, Member] = {}
self._roles: dict[str, Role] = {role_id: Role(role, role_id, state, self) for role_id, role in data.get("roles", {}).items()}
channels = cast(list[Channel], list(filter(bool, [state.get_channel(channel_id) for channel_id in data["channels"]])))
channels = [state.get_channel(channel_id) for channel_id in data["channels"]]
self._channels: dict[str, Channel] = {channel.id: channel for channel in channels}
def _update(self, *, owner: Optional[str] = None, name: Optional[str] = None, description: Optional[str] = None, icon: Optional[FilePayload] = None, banner: Optional[FilePayload] = None, default_permissions: Optional[PermissionPayload] = None, nsfw: Optional[bool] = None, system_messages: Optional[SystemMessagesConfig] = None, categories: Optional[list[CategoryPayload]] = None):
+45 -4
View File
@@ -7,10 +7,9 @@ from .channel import (Channel, DMChannel, Group, SavedMessages, TextChannel,
from .message import Message
if TYPE_CHECKING:
from .member import Member
from .member import Member, MemberID
from .server import Server
from .user import User
from .user import User, Status
__all__ = (
"BasePayload",
@@ -26,7 +25,15 @@ __all__ = (
"ChannelDeleteEventPayload",
"ChannelStartTypingEventPayload",
"ChannelDeleteTypingEventPayload",
"ServerUpdateEventPayload"
"ServerUpdateEventPayload",
"ServerDeleteEventPayload",
"ServerMemberUpdateEventPayload",
"ServerMemberJoinEventPayload",
"ServerMemberLeaveEventPayload",
"ServerRoleUpdateEventPayload",
"ServerRoleDeleteEventPayload",
"UserUpdateEventPayload",
"UserRelationshipEventPayload"
)
class BasePayload(TypedDict):
@@ -94,3 +101,37 @@ class ServerUpdateEventPayload(BasePayload):
id: str
data: dict
clear: Literal["Icon", "Banner", "Description"]
class ServerDeleteEventPayload(BasePayload):
id: str
class ServerMemberUpdateEventPayload(BasePayload):
id: MemberID
data: dict
clear: Literal["Nickname", "Avatar"]
class ServerMemberJoinEventPayload(BasePayload):
id: str
user: str
ServerMemberLeaveEventPayload = ServerMemberJoinEventPayload
class ServerRoleUpdateEventPayload(BasePayload):
id: str
role_id: str
data: dict
clear: Literal["Color"]
class ServerRoleDeleteEventPayload(BasePayload):
id: str
role_id: str
class UserUpdateEventPayload(BasePayload):
id: str
data: dict
clear: Literal["ProfileContent", "ProfileBackground", "StatusText", "Avatar"]
class UserRelationshipEventPayload(BasePayload):
id: str
user: str
status: Status
+26 -3
View File
@@ -7,8 +7,7 @@ from .enums import PresenceType, RelationshipType
if TYPE_CHECKING:
from .state import State
from .types import User as UserPayload
from .types import UserRelation
from .types import User as UserPayload, Status as StatusPayload, File
__all__ = ("User",)
@@ -23,6 +22,11 @@ class Status(NamedTuple):
text: Optional[str]
presence: Optional[PresenceType]
class UserProfile(NamedTuple):
"""A namedtuple representing a users profile"""
content: Optional[str]
background: Optional[Asset]
class User:
"""Represents a user
@@ -47,7 +51,7 @@ class User:
status: Optional[:class:`Status`]
The users status
"""
__flattern_attributes__ = ("id", "bot", "owner_id", "badges", "online", "flags", "relations", "relationship", "status", "masquerade_avatar", "masquerade_name", "original_name", "original_avatar")
__flattern_attributes__ = ("id", "bot", "owner_id", "badges", "online", "flags", "relations", "relationship", "status", "masquerade_avatar", "masquerade_name", "original_name", "original_avatar", "profile")
__slots__ = (*__flattern_attributes__, "state")
def __init__(self, data: UserPayload, state: State):
@@ -88,6 +92,8 @@ class User:
else:
self.status = None
self.profile: Optional[UserProfile] = None
self.masquerade_avatar: Optional[PartialAsset] = None
self.masquerade_name: Optional[str] = None
@@ -109,3 +115,20 @@ class User:
def avatar(self) -> Union[Asset, PartialAsset, None]:
"""Optional[:class:`Asset`] The avatar the member is displaying, this includes there orginal avatar and masqueraded avatar"""
return self.masquerade_avatar or self.original_avatar
def _update(self, *, status: Optional[StatusPayload] = None, profile_content: Optional[str] = None, profile_background: Optional[File] = None, avatar: Optional[File] = None, online: Optional[bool] = None):
if status:
presence = status.get("presence")
self.status = Status(status.get("text"), PresenceType(presence) if presence else None)
if profile_background:
self.profile = UserProfile(self.profile.content if self.profile else None, Asset(profile_background, self.state))
if profile_content:
self.profile = UserProfile(profile_content, self.profile.background if self.profile else None)
if avatar:
self.original_avatar = Asset(avatar, self.state)
if online:
self.online = online
+103 -4
View File
@@ -5,9 +5,12 @@ import logging
from copy import copy
from typing import TYPE_CHECKING, Callable, cast
from .enums import RelationshipType
from .user import Status
from .types import (ChannelCreateEventPayload, ChannelDeleteEventPayload,
ChannelDeleteTypingEventPayload,
ChannelStartTypingEventPayload, ChannelUpdateEventPayload, ServerUpdateEventPayload)
ChannelStartTypingEventPayload, ChannelUpdateEventPayload, ServerUpdateEventPayload, UserRelationshipEventPayload, ServerRoleDeleteEventPayload, UserUpdateEventPayload, ServerDeleteEventPayload, ServerMemberUpdateEventPayload, ServerMemberJoinEventPayload, ServerMemberLeaveEventPayload, ServerRoleUpdateEventPayload)
from .types import Message as MessagePayload
from .types import MessageDeleteEventPayload, MessageUpdateEventPayload
@@ -36,7 +39,7 @@ __all__ = ("WebsocketHandler",)
logger = logging.getLogger("revolt")
class WebsocketHandler:
__slots__ = ("session", "token", "ws_url", "dispatch", "state", "websocket", "loop")
__slots__ = ("session", "token", "ws_url", "dispatch", "state", "websocket", "loop", "user", "ready")
def __init__(self, session: aiohttp.ClientSession, token: str, ws_url: str, dispatch: Callable[..., None], state: State):
self.session = session
@@ -46,6 +49,8 @@ class WebsocketHandler:
self.state = state
self.websocket: aiohttp.ClientWebSocketResponse
self.loop = asyncio.get_running_loop()
self.user = None
self.ready = asyncio.Event()
async def send_payload(self, payload: BasePayload):
if use_msgpack:
@@ -71,6 +76,9 @@ class WebsocketHandler:
event_type = payload["type"].lower()
logger.debug("Recieved event %s %s", event_type, payload)
try:
if event_type != "ready":
await self.ready.wait()
func = getattr(self, f"handle_{event_type}")
except:
logger.debug("Unknown event '%s'", event_type)
@@ -82,8 +90,11 @@ class WebsocketHandler:
logger.info("Successfully authenticated")
async def handle_ready(self, payload: ReadyEventPayload):
for user in payload["users"]:
self.state.add_user(user)
for user_payload in payload["users"]:
user = self.state.add_user(user_payload)
if user.relationship == RelationshipType.user:
self.user = user
for channel in payload["channels"]:
self.state.add_channel(channel)
@@ -97,6 +108,7 @@ class WebsocketHandler:
await self.state.fetch_all_server_members()
self.ready.set()
self.dispatch("ready")
async def handle_message(self, payload: MessageEventPayload):
@@ -189,6 +201,93 @@ class WebsocketHandler:
self.dispatch("server_update", old_server, server)
async def handle_serverdelete(self, payload: ServerDeleteEventPayload):
server = self.state.servers.pop(payload["id"])
for channel in server.channels:
del self.state.channels[channel.id]
self.dispatch("server_delete", server)
async def handle_servermemberupdate(self, payload: ServerMemberUpdateEventPayload):
member = self.state.get_member(payload["id"]["server"], payload["id"]["user"])
old_member = copy(member)
if clear := payload.get("clear"):
if clear == "Nickname":
member.nickname = None
elif clear == "Avatar":
member.guild_avatar = None
member._update(**payload["data"])
self.dispatch("member_update", old_member, member)
async def handle_servermemberjoin(self, payload: ServerMemberJoinEventPayload):
member = self.state.add_member(payload["id"], {"_id": {"server": payload["id"], "user": payload["user"]}})
self.dispatch("member_join", member)
async def handle_memberleave(self, payload: ServerMemberLeaveEventPayload):
server = self.state.get_server(payload["id"])
member = server._members.pop(payload["user"])
self.dispatch("member_leave", member)
async def handle_serveroleupdate(self, payload: ServerRoleUpdateEventPayload):
server = self.state.get_server(payload["id"])
role = server.get_role(payload["role_id"])
old_role = copy(role)
if clear := payload.get("clear"):
if clear == "Colour":
role.colour = None
role._update(**payload["data"])
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"])
self.dispatch("role_delete", role)
async def handle_userupdate(self, payload: UserUpdateEventPayload):
user = self.state.get_user(payload["id"])
old_user = copy(user)
if clear := payload.get("clear"):
if clear == "ProfileContent":
...
elif clear == "ProfileBackground":
...
elif clear == "StatusText":
# user.status will never be none because they are trying to remove the text
if user.status.presence is None: # type: ignore
user.status = None
else:
user.status = Status(None, user.status.presence) # type: ignore
elif clear == "Avatar":
user.original_avatar = None
# the keys have . in them so i need to replace with _
data = payload["data"]
data["profile_content"] = data.get("profile.content", None)
data["profile_background"] = data.get("profile.background", None)
user._update(**data)
self.dispatch("user_update", old_user, user)
async def handle_userrelationship(self, payload: UserRelationshipEventPayload):
user = self.state.get_user(payload["user"])
old_relationship = user.relationship
user.relationship = RelationshipType(payload["status"])
self.dispatch("user_relationship_update", user, old_relationship, user.relationship)
async def start(self):
if use_msgpack:
url = f"{self.ws_url}?format=msgpack"