Skip to content

Commit 6783478

Browse files
committed
Add message editing events
Reference: - revoltchat/rfcs#13 - revoltchat/backend#395
1 parent e5528cd commit 6783478

File tree

3 files changed

+103
-19
lines changed

3 files changed

+103
-19
lines changed

pyvolt/adapter.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@
3939
F = typing.TypeVar('F')
4040

4141

42-
class WebSocketConnectionRetry(Exception):
43-
"""Signal to retry connecting to WebSocket."""
42+
class WebSocketConnectionFailure(Exception):
43+
"""Signal that WebSocket endpoint did not return "101 Switching Protocols" status code."""
4444

45-
__slots__ = ()
45+
__slots__ = ('status',)
46+
47+
def __init__(self, *, status: int) -> None:
48+
self.status: int = status
4649

4750

4851
@typing.runtime_checkable
@@ -237,22 +240,22 @@ async def websocket(
237240

238241
@abstractmethod
239242
def is_close_frame(self, frame: F, /) -> bool:
240-
""":class:`bool`: Returns whether the provided message is a CLOSE/CLOSED/CLOSING frame."""
243+
""":class:`bool`: Returns whether the provided frame is a CLOSE/CLOSED/CLOSING frame."""
241244
...
242245

243246
@abstractmethod
244247
def is_error_frame(self, frame: F, /) -> bool:
245-
""":class:`bool`: Returns whether the provided message is a ERROR pseudo-frame."""
248+
""":class:`bool`: Returns whether the provided frame is a ERROR pseudo-frame."""
246249
...
247250

248251
@abstractmethod
249252
def is_binary_frame(self, frame: F, /) -> bool:
250-
""":class:`bool`: Returns whether the provided message is a BINARY frame."""
253+
""":class:`bool`: Returns whether the provided frame is a BINARY frame."""
251254
...
252255

253256
@abstractmethod
254257
def is_text_frame(self, frame: F, /) -> bool:
255-
""":class:`bool`: Returns whether the provided message is a TEXT frame."""
258+
""":class:`bool`: Returns whether the provided frame is a TEXT frame."""
256259
...
257260

258261
@abstractmethod
@@ -380,7 +383,12 @@ async def websocket(
380383
The response.
381384
"""
382385
session = await self.get_session()
383-
connection = await session.ws_connect(url, headers=headers, **kwargs)
386+
387+
try:
388+
connection = await session.ws_connect(url, headers=headers, **kwargs)
389+
except aiohttp.WSServerHandshakeError as exc:
390+
raise WebSocketConnectionFailure(status=exc.status) from exc
391+
384392
return connection
385393

386394
def is_close_frame(self, frame: aiohttp.WSMessage, /) -> bool:
@@ -392,15 +400,15 @@ def is_close_frame(self, frame: aiohttp.WSMessage, /) -> bool:
392400
)
393401

394402
def is_error_frame(self, frame: aiohttp.WSMessage, /) -> bool:
395-
""":class:`bool`: Returns whether the provided message is a ERROR pseudo-frame."""
403+
""":class:`bool`: Returns whether the provided frame is a ERROR pseudo-frame."""
396404
return frame.type is aiohttp.WSMsgType.ERROR
397405

398406
def is_binary_frame(self, frame: aiohttp.WSMessage, /) -> bool:
399-
""":class:`bool`: Returns whether the provided message is a BINARY frame."""
407+
""":class:`bool`: Returns whether the provided frame is a BINARY frame."""
400408
return frame.type is aiohttp.WSMsgType.BINARY
401409

402410
def is_text_frame(self, frame: aiohttp.WSMessage, /) -> bool:
403-
""":class:`bool`: Returns whether the provided message is a TEXT frame."""
411+
""":class:`bool`: Returns whether the provided frame is a TEXT frame."""
404412
return frame.type is aiohttp.WSMsgType.TEXT
405413

406414
def payload_from_frame(self, frame: aiohttp.WSMessage, /) -> typing.Any:
@@ -409,7 +417,7 @@ def payload_from_frame(self, frame: aiohttp.WSMessage, /) -> typing.Any:
409417

410418

411419
__all__ = (
412-
'WebSocketConnectionRetry',
420+
'WebSocketConnectionFailure',
413421
'HTTPResponse',
414422
'AIOHTTPResponseWrapper',
415423
'HTTPWebSocket',

pyvolt/raw/gateway.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,20 @@ class ClientChannelStopTypingEvent(typing.TypedDict):
293293
user: str
294294

295295

296+
class ClientMessageStartEditingEvent(typing.TypedDict):
297+
type: typing.Literal['MessageStartEditing']
298+
id: str
299+
channel: str
300+
user: str
301+
302+
303+
class ClientMessageStopEditingEvent(typing.TypedDict):
304+
type: typing.Literal['MessageStopEditing']
305+
id: str
306+
channel: str
307+
user: str
308+
309+
296310
class ClientChannelAckEvent(typing.TypedDict):
297311
type: typing.Literal['ChannelAck']
298312
id: str
@@ -400,6 +414,8 @@ class ClientUserVoiceStateUpdateEvent(typing.TypedDict):
400414
ClientChannelGroupLeaveEvent,
401415
ClientChannelStartTypingEvent,
402416
ClientChannelStopTypingEvent,
417+
ClientMessageStartEditingEvent,
418+
ClientMessageStopEditingEvent,
403419
ClientChannelAckEvent,
404420
ClientWebhookCreateEvent,
405421
ClientWebhookUpdateEvent,
@@ -427,6 +443,18 @@ class ServerEndTypingEvent(typing.TypedDict):
427443
channel: str
428444

429445

446+
class ServerBeginEditingEvent(typing.TypedDict):
447+
type: typing.Literal['BeginEditing']
448+
channel: str
449+
message: str
450+
451+
452+
class ServerStopEditingEvent(typing.TypedDict):
453+
type: typing.Literal['StopEditing']
454+
channel: str
455+
message: str
456+
457+
430458
class ServerSubscribeEvent(typing.TypedDict):
431459
type: typing.Literal['Subscribe']
432460
server_id: str
@@ -442,6 +470,8 @@ class ServerPingEvent(typing.TypedDict):
442470
ServerBeginTypingEvent,
443471
ServerEndTypingEvent,
444472
ServerSubscribeEvent,
473+
ServerBeginEditingEvent,
474+
ServerStopEditingEvent,
445475
ServerPingEvent,
446476
]
447477

pyvolt/shard.py

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@
3030
import logging
3131
import typing
3232

33-
import aiohttp
3433
from multidict import CIMultiDict
3534

3635
from . import __version__, utils
37-
from .adapter import HTTPWebSocket, HTTPAdapter, AIOHTTPAdapter
36+
from .adapter import WebSocketConnectionFailure, HTTPWebSocket, HTTPAdapter, AIOHTTPAdapter
3837
from .core import ULIDOr, resolve_id
3938
from .enums import ShardFormat
4039
from .errors import PyvoltException, ShardClosedError, AuthenticationError, ConnectError
@@ -44,6 +43,7 @@
4443

4544
from . import raw
4645
from .channel import TextableChannel
46+
from .message import BaseMessage
4747
from .server import BaseServer
4848
from .state import State
4949

@@ -251,6 +251,36 @@ async def subscribe_to(self, server: ULIDOr[BaseServer], /) -> None:
251251
"""
252252
...
253253

254+
@abstractmethod
255+
async def begin_editing(self, channel: ULIDOr[TextableChannel], message: ULIDOr[BaseMessage]) -> None:
256+
"""|coro|
257+
258+
Begins editing a message.
259+
260+
Parameters
261+
----------
262+
channel: ULIDOr[:class:`.TextableChannel`]
263+
The channel the message was sent in.
264+
message: ULIDOr[:class:`.BaseMessage`]
265+
The message to begin editing.
266+
"""
267+
...
268+
269+
@abstractmethod
270+
async def stop_editing(self, channel: ULIDOr[TextableChannel], message: ULIDOr[BaseMessage]) -> None:
271+
"""|coro|
272+
273+
Stops editing a message.
274+
275+
Parameters
276+
----------
277+
channel: ULIDOr[:class:`.TextableChannel`]
278+
The channel the message was sent in.
279+
message: ULIDOr[:class:`.BaseMessage`]
280+
The message to stop editing.
281+
"""
282+
...
283+
254284
@abstractmethod
255285
async def connect(self) -> None:
256286
"""Starts the WebSocket lifecycle."""
@@ -479,12 +509,28 @@ async def subscribe_to(self, server: ULIDOr[BaseServer], /) -> None:
479509
payload: raw.ServerSubscribeEvent = {'type': 'Subscribe', 'server_id': resolve_id(server)}
480510
await self.send(payload)
481511

512+
async def begin_editing(self, channel: ULIDOr[TextableChannel], message: ULIDOr[BaseMessage]) -> None:
513+
payload: raw.ServerBeginEditingEvent = {
514+
'type': 'BeginEditing',
515+
'channel': resolve_id(channel),
516+
'message': resolve_id(message),
517+
}
518+
await self.send(payload)
519+
520+
async def stop_editing(self, channel: ULIDOr[TextableChannel], message: ULIDOr[BaseMessage]) -> None:
521+
payload: raw.ServerStopEditingEvent = {
522+
'type': 'StopEditing',
523+
'channel': resolve_id(channel),
524+
'message': resolve_id(message),
525+
}
526+
await self.send(payload)
527+
482528
async def _send_json(self, d: raw.ServerEvent, /) -> None:
483-
_L.debug('sending %s', d)
529+
_L.debug('Sending %s', d)
484530
await self.socket.send_str(utils.to_json(d))
485531

486532
async def _send_msgpack(self, d: raw.ServerEvent, /) -> None:
487-
_L.debug('sending %s', d)
533+
_L.debug('Sending %s', d)
488534

489535
# Will never none according to stubs: https://github.com/sbdchd/msgpack-types/blob/a9ab1c861933fa11aff706b21c303ee52a2ee359/msgpack-stubs/__init__.pyi#L40-L49
490536
payload: bytes = msgpack.packb(d) # type: ignore
@@ -595,9 +641,9 @@ async def _socket_connect(self) -> HTTPWebSocket[typing.Any]:
595641
if exc.errno == 11001:
596642
await asyncio.sleep(1)
597643
i += 1
598-
except aiohttp.WSServerHandshakeError as exc:
599-
_L.debug('Server replied with %i', exc.code)
600-
if exc.code in (502, 525):
644+
except WebSocketConnectionFailure as exc:
645+
_L.debug('Server replied with %i', exc.status)
646+
if exc.status in (502, 525):
601647
await asyncio.sleep(1.5)
602648
continue
603649
raise exc from None

0 commit comments

Comments
 (0)