add user session reclaiming

In its current state the implementation should allow a user to resume
their session if the websocket connection is reset, for whatever reason.
This could be expanded to allow session sharing (multiple agents logging
in to the same client), or manual session resume via some sort of
password (encode uid & key to some pass-phrase kinda thing, or QR code).
This commit is contained in:
ducklet 2021-01-31 00:19:35 +01:00
parent 476f3d7a49
commit 4908b1fc6e
10 changed files with 376 additions and 77 deletions

108
stubs/websockets.pyi Normal file
View file

@ -0,0 +1,108 @@
import asyncio
import http
from typing import *
# typing (but mypy doesn't know it ...)
class TracebackType: ...
# websockets/typing.py
Data = Union[str, bytes]
Origin = NewType("Origin", str)
Origin.__doc__ = """Value of a Origin header"""
Subprotocol = NewType("Subprotocol", str)
Subprotocol.__doc__ = """Subprotocol value in a Sec-WebSocket-Protocol header"""
# websockets/legacy/protocol.py
class WebSocketCommonProtocol(asyncio.Protocol):
@property
def host(self) -> Optional[str]: ...
@property
def port(self) -> Optional[int]: ...
@property
def secure(self) -> Optional[bool]: ...
@property
def open(self) -> bool: ...
@property
def closed(self) -> bool: ...
async def wait_closed(self) -> None: ...
async def __aiter__(self) -> AsyncIterator[Data]: ...
async def recv(self) -> Data: ...
async def send(
self, message: Union[Data, Iterable[Data], AsyncIterable[Data]]
) -> None: ...
async def close(self, code: int = 1000, reason: str = "") -> None: ...
async def ping(self, data: Optional[Data] = None) -> Awaitable[None]: ...
# websockets/extensions/base.py
class ServerExtensionFactory: ...
# websockets/datastructures.py
class Headers(MutableMapping[str, str]):
def __iter__(self) -> Iterator[str]: ...
def __len__(self) -> int: ...
def __getitem__(self, key: str) -> str: ...
def __setitem__(self, key: str, value: str) -> None: ...
def __delitem__(self, key: str) -> None: ...
HeadersLike = Union[Headers, Mapping[str, str], Iterable[Tuple[str, str]]]
# websockets/legacy/server.py
HeadersLikeOrCallable = Union[HeadersLike, Callable[[str, Headers], HeadersLike]]
HTTPResponse = Tuple[http.HTTPStatus, HeadersLike, bytes]
class WebSocketServerProtocol(WebSocketCommonProtocol):
async def process_request(
self, path: str, request_headers: Headers
) -> Optional[HTTPResponse]: ...
class WebSocketServer:
def wrap(self, server: asyncio.AbstractServer) -> None: ...
def close(self) -> None: ...
class Serve:
def __init__(
self,
ws_handler: Callable[[WebSocketServerProtocol, str], Awaitable[Any]],
host: Optional[Union[str, Sequence[str]]] = None,
port: Optional[int] = None,
*,
path: Optional[str] = None,
create_protocol: Optional[Callable[[Any], WebSocketServerProtocol]] = None,
ping_interval: Optional[float] = 20,
ping_timeout: Optional[float] = 20,
close_timeout: Optional[float] = None,
max_size: Optional[int] = 2 ** 20,
max_queue: Optional[int] = 2 ** 5,
read_limit: int = 2 ** 16,
write_limit: int = 2 ** 16,
loop: Optional[asyncio.AbstractEventLoop] = None,
legacy_recv: bool = False,
klass: Optional[Type[WebSocketServerProtocol]] = None,
timeout: Optional[float] = None,
compression: Optional[str] = "deflate",
origins: Optional[Sequence[Optional[Origin]]] = None,
extensions: Optional[Sequence[ServerExtensionFactory]] = None,
subprotocols: Optional[Sequence[Subprotocol]] = None,
extra_headers: Optional[HeadersLikeOrCallable] = None,
process_request: Optional[
Callable[[str, Headers], Awaitable[Optional[HTTPResponse]]]
] = None,
select_subprotocol: Optional[
Callable[[Sequence[Subprotocol], Sequence[Subprotocol]], Subprotocol]
] = None,
unix: bool = False,
**kwargs: Any,
) -> None: ...
async def __aenter__(self) -> WebSocketServer: ...
async def __aexit__(
self,
exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType],
) -> None: ...
def __await__(self) -> Generator[Any, None, WebSocketServer]: ...
__iter__ = __await__
serve = Serve
WebSocketServerProtocol