Source code for bacommon.cloud

# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to cloud functionality."""

from __future__ import annotations

from enum import Enum
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Annotated, override

from efro.message import Message, Response
from efro.dataclassio import ioprepped, IOAttrs
from bacommon.securedata import SecureDataChecker
from bacommon.transfer import DirectoryManifest
from bacommon.login import LoginType

if TYPE_CHECKING:
    pass


[docs] class WebLocation(Enum): """Set of places we can be directed on ballistica.net.""" ACCOUNT_EDITOR = 'e' ACCOUNT_DELETE_SECTION = 'd'
[docs] @ioprepped @dataclass class LoginProxyRequestMessage(Message): """Request send to the cloud to ask for a login-proxy."""
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [LoginProxyRequestResponse]
[docs] @ioprepped @dataclass class LoginProxyRequestResponse(Response): """Response to a request for a login proxy.""" # URL to direct the user to for sign in. url: str # URL to use for overlay-web-browser sign ins. url_overlay: str # Proxy-Login id for querying results. proxyid: str # Proxy-Login key for querying results. proxykey: str
[docs] @ioprepped @dataclass class LoginProxyStateQueryMessage(Message): """Soo.. how is that login proxy going?""" proxyid: str proxykey: str
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [LoginProxyStateQueryResponse]
[docs] @ioprepped @dataclass class LoginProxyStateQueryResponse(Response): """Here's the info on that login-proxy you asked about, boss."""
[docs] class State(Enum): """States a login-proxy can be in.""" WAITING = 'waiting' SUCCESS = 'success' FAIL = 'fail'
state: State # On success, these will be filled out. credentials: str | None
[docs] @ioprepped @dataclass class LoginProxyCompleteMessage(Message): """Just so you know, we're done with this proxy.""" proxyid: str
[docs] @ioprepped @dataclass class PingMessage(Message): """Standard ping."""
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [PingResponse]
[docs] @ioprepped @dataclass class PingResponse(Response): """pong."""
[docs] @ioprepped @dataclass class TestMessage(Message): """Can I get some of that workspace action?""" testfoo: int
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [TestResponse]
[docs] @ioprepped @dataclass class TestResponse(Response): """Here's that workspace you asked for, boss.""" testfoo: int
[docs] @ioprepped @dataclass class SendInfoMessage(Message): """User is using the send-info function""" description: str
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [SendInfoResponse]
[docs] @ioprepped @dataclass class SendInfoResponse(Response): """Response to sending into the server.""" handled: bool message: str | None = None legacy_code: str | None = None
[docs] @ioprepped @dataclass class WorkspaceFetchState: """Common state data for a workspace fetch.""" manifest: DirectoryManifest iteration: int = 0 total_deletes: int = 0 total_downloads: int = 0 total_up_to_date: int | None = None
[docs] @ioprepped @dataclass class WorkspaceFetchMessage(Message): """Can I get some of that workspace action?""" workspaceid: str state: WorkspaceFetchState
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [WorkspaceFetchResponse]
[docs] @ioprepped @dataclass class WorkspaceFetchResponse(Response): """Here's that workspace you asked for, boss.""" state: WorkspaceFetchState deletes: list[str] = field( default_factory=list ) downloads_inline: dict[str, bytes] = field(default_factory=dict) done: bool = False
[docs] @ioprepped @dataclass class MerchAvailabilityMessage(Message): """Can we show merch link?"""
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [MerchAvailabilityResponse]
[docs] @ioprepped @dataclass class MerchAvailabilityResponse(Response): """About that merch...""" url: str | None
[docs] @ioprepped @dataclass class SignInMessage(Message): """Can I sign in please?""" login_type: LoginType sign_in_token: str # For debugging. Can remove soft_default once build 20988+ is ubiquitous. description: str apptime: float
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [SignInResponse]
[docs] @ioprepped @dataclass class SignInResponse(Response): """Here's that sign-in result you asked for, boss.""" credentials: str | None
[docs] @ioprepped @dataclass class ManageAccountMessage(Message): """Message asking for a manage-account url.""" weblocation: WebLocation = ( WebLocation.ACCOUNT_EDITOR )
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [ManageAccountResponse]
[docs] @ioprepped @dataclass class ManageAccountResponse(Response): """Here's that sign-in result you asked for, boss.""" url: str | None
[docs] @ioprepped @dataclass class StoreQueryMessage(Message): """Message asking about purchasable stuff and store related state."""
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [StoreQueryResponse]
[docs] @ioprepped @dataclass class StoreQueryResponse(Response): """Here's that store info you asked for, boss."""
[docs] class Result(Enum): """Our overall result.""" SUCCESS = 's' ERROR = 'e'
[docs] @dataclass class Purchase: """Info about a purchasable thing.""" purchaseid: str
# Overall result; all data is undefined if not SUCCESS. result: Result tokens: int gold_pass: bool available_purchases: list[Purchase] token_info_url: str
[docs] @ioprepped @dataclass class SecureDataCheckMessage(Message): """Was this data signed by the master-server?.""" data: bytes signature: bytes
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [SecureDataCheckResponse]
[docs] @ioprepped @dataclass class SecureDataCheckResponse(Response): """Here's the result of that data check, boss.""" # Whether the data signature was valid. result: bool
[docs] @ioprepped @dataclass class SecureDataCheckerRequest(Message): """Can I get a checker over here?."""
[docs] @override @classmethod def get_response_types(cls) -> list[type[Response] | None]: return [SecureDataCheckerResponse]
[docs] @ioprepped @dataclass class SecureDataCheckerResponse(Response): """Here's that checker ya asked for, boss.""" checker: SecureDataChecker
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum