bacommon.cloud

Functionality related to cloud functionality.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Functionality related to cloud functionality."""
  4
  5from __future__ import annotations
  6
  7from enum import Enum
  8from dataclasses import dataclass, field
  9from typing import TYPE_CHECKING, Annotated, override
 10
 11from efro.message import Message, Response
 12from efro.dataclassio import ioprepped, IOAttrs
 13from bacommon.securedata import SecureDataChecker
 14from bacommon.transfer import DirectoryManifest
 15from bacommon.login import LoginType
 16
 17if TYPE_CHECKING:
 18    pass
 19
 20
 21class WebLocation(Enum):
 22    """Set of places we can be directed on ballistica.net."""
 23
 24    ACCOUNT_EDITOR = 'e'
 25    ACCOUNT_DELETE_SECTION = 'd'
 26
 27
 28@ioprepped
 29@dataclass
 30class LoginProxyRequestMessage(Message):
 31    """Request send to the cloud to ask for a login-proxy."""
 32
 33    @override
 34    @classmethod
 35    def get_response_types(cls) -> list[type[Response] | None]:
 36        return [LoginProxyRequestResponse]
 37
 38
 39@ioprepped
 40@dataclass
 41class LoginProxyRequestResponse(Response):
 42    """Response to a request for a login proxy."""
 43
 44    # URL to direct the user to for sign in.
 45    url: Annotated[str, IOAttrs('u')]
 46
 47    # URL to use for overlay-web-browser sign ins.
 48    url_overlay: Annotated[str, IOAttrs('uo')]
 49
 50    # Proxy-Login id for querying results.
 51    proxyid: Annotated[str, IOAttrs('p')]
 52
 53    # Proxy-Login key for querying results.
 54    proxykey: Annotated[str, IOAttrs('k')]
 55
 56
 57@ioprepped
 58@dataclass
 59class LoginProxyStateQueryMessage(Message):
 60    """Soo.. how is that login proxy going?"""
 61
 62    proxyid: Annotated[str, IOAttrs('p')]
 63    proxykey: Annotated[str, IOAttrs('k')]
 64
 65    @override
 66    @classmethod
 67    def get_response_types(cls) -> list[type[Response] | None]:
 68        return [LoginProxyStateQueryResponse]
 69
 70
 71@ioprepped
 72@dataclass
 73class LoginProxyStateQueryResponse(Response):
 74    """Here's the info on that login-proxy you asked about, boss."""
 75
 76    class State(Enum):
 77        """States a login-proxy can be in."""
 78
 79        WAITING = 'waiting'
 80        SUCCESS = 'success'
 81        FAIL = 'fail'
 82
 83    state: Annotated[State, IOAttrs('s')]
 84
 85    # On success, these will be filled out.
 86    credentials: Annotated[str | None, IOAttrs('tk')]
 87
 88
 89@ioprepped
 90@dataclass
 91class LoginProxyCompleteMessage(Message):
 92    """Just so you know, we're done with this proxy."""
 93
 94    proxyid: Annotated[str, IOAttrs('p')]
 95
 96
 97@ioprepped
 98@dataclass
 99class PingMessage(Message):
100    """Standard ping."""
101
102    @override
103    @classmethod
104    def get_response_types(cls) -> list[type[Response] | None]:
105        return [PingResponse]
106
107
108@ioprepped
109@dataclass
110class PingResponse(Response):
111    """pong."""
112
113
114@ioprepped
115@dataclass
116class TestMessage(Message):
117    """Can I get some of that workspace action?"""
118
119    testfoo: Annotated[int, IOAttrs('f')]
120
121    @override
122    @classmethod
123    def get_response_types(cls) -> list[type[Response] | None]:
124        return [TestResponse]
125
126
127@ioprepped
128@dataclass
129class TestResponse(Response):
130    """Here's that workspace you asked for, boss."""
131
132    testfoo: Annotated[int, IOAttrs('f')]
133
134
135@ioprepped
136@dataclass
137class SendInfoMessage(Message):
138    """User is using the send-info function"""
139
140    description: Annotated[str, IOAttrs('c')]
141
142    @override
143    @classmethod
144    def get_response_types(cls) -> list[type[Response] | None]:
145        return [SendInfoResponse]
146
147
148@ioprepped
149@dataclass
150class SendInfoResponse(Response):
151    """Response to sending into the server."""
152
153    handled: Annotated[bool, IOAttrs('v')]
154    message: Annotated[str | None, IOAttrs('m', store_default=False)] = None
155    legacy_code: Annotated[str | None, IOAttrs('l', store_default=False)] = None
156
157
158@ioprepped
159@dataclass
160class WorkspaceFetchState:
161    """Common state data for a workspace fetch."""
162
163    manifest: Annotated[DirectoryManifest, IOAttrs('m')]
164    iteration: Annotated[int, IOAttrs('i')] = 0
165    total_deletes: Annotated[int, IOAttrs('tdels')] = 0
166    total_downloads: Annotated[int, IOAttrs('tdlds')] = 0
167    total_up_to_date: Annotated[int | None, IOAttrs('tunmd')] = None
168
169
170@ioprepped
171@dataclass
172class WorkspaceFetchMessage(Message):
173    """Can I get some of that workspace action?"""
174
175    workspaceid: Annotated[str, IOAttrs('w')]
176    state: Annotated[WorkspaceFetchState, IOAttrs('s')]
177
178    @override
179    @classmethod
180    def get_response_types(cls) -> list[type[Response] | None]:
181        return [WorkspaceFetchResponse]
182
183
184@ioprepped
185@dataclass
186class WorkspaceFetchResponse(Response):
187    """Here's that workspace you asked for, boss."""
188
189    state: Annotated[WorkspaceFetchState, IOAttrs('s')]
190    deletes: Annotated[list[str], IOAttrs('dlt', store_default=False)] = field(
191        default_factory=list
192    )
193    downloads_inline: Annotated[
194        dict[str, bytes], IOAttrs('dinl', store_default=False)
195    ] = field(default_factory=dict)
196
197    done: Annotated[bool, IOAttrs('d')] = False
198
199
200@ioprepped
201@dataclass
202class MerchAvailabilityMessage(Message):
203    """Can we show merch link?"""
204
205    @override
206    @classmethod
207    def get_response_types(cls) -> list[type[Response] | None]:
208        return [MerchAvailabilityResponse]
209
210
211@ioprepped
212@dataclass
213class MerchAvailabilityResponse(Response):
214    """About that merch..."""
215
216    url: Annotated[str | None, IOAttrs('u')]
217
218
219@ioprepped
220@dataclass
221class SignInMessage(Message):
222    """Can I sign in please?"""
223
224    login_type: Annotated[LoginType, IOAttrs('l')]
225    sign_in_token: Annotated[str, IOAttrs('t')]
226
227    # For debugging. Can remove soft_default once build 20988+ is ubiquitous.
228    description: Annotated[str, IOAttrs('d', soft_default='-')]
229    apptime: Annotated[float, IOAttrs('at', soft_default=-1.0)]
230
231    @override
232    @classmethod
233    def get_response_types(cls) -> list[type[Response] | None]:
234        return [SignInResponse]
235
236
237@ioprepped
238@dataclass
239class SignInResponse(Response):
240    """Here's that sign-in result you asked for, boss."""
241
242    credentials: Annotated[str | None, IOAttrs('c')]
243
244
245@ioprepped
246@dataclass
247class ManageAccountMessage(Message):
248    """Message asking for a manage-account url."""
249
250    weblocation: Annotated[WebLocation, IOAttrs('l')] = (
251        WebLocation.ACCOUNT_EDITOR
252    )
253
254    @override
255    @classmethod
256    def get_response_types(cls) -> list[type[Response] | None]:
257        return [ManageAccountResponse]
258
259
260@ioprepped
261@dataclass
262class ManageAccountResponse(Response):
263    """Here's that sign-in result you asked for, boss."""
264
265    url: Annotated[str | None, IOAttrs('u')]
266
267
268@ioprepped
269@dataclass
270class StoreQueryMessage(Message):
271    """Message asking about purchasable stuff and store related state."""
272
273    @override
274    @classmethod
275    def get_response_types(cls) -> list[type[Response] | None]:
276        return [StoreQueryResponse]
277
278
279@ioprepped
280@dataclass
281class StoreQueryResponse(Response):
282    """Here's that store info you asked for, boss."""
283
284    class Result(Enum):
285        """Our overall result."""
286
287        SUCCESS = 's'
288        ERROR = 'e'
289
290    @dataclass
291    class Purchase:
292        """Info about a purchasable thing."""
293
294        purchaseid: Annotated[str, IOAttrs('id')]
295
296    # Overall result; all data is undefined if not SUCCESS.
297    result: Annotated[Result, IOAttrs('r')]
298
299    tokens: Annotated[int, IOAttrs('t')]
300    gold_pass: Annotated[bool, IOAttrs('g')]
301
302    available_purchases: Annotated[list[Purchase], IOAttrs('p')]
303    token_info_url: Annotated[str, IOAttrs('tiu')]
304
305
306@ioprepped
307@dataclass
308class SecureDataCheckMessage(Message):
309    """Was this data signed by the master-server?."""
310
311    data: Annotated[bytes, IOAttrs('d')]
312    signature: Annotated[bytes, IOAttrs('s')]
313
314    @override
315    @classmethod
316    def get_response_types(cls) -> list[type[Response] | None]:
317        return [SecureDataCheckResponse]
318
319
320@ioprepped
321@dataclass
322class SecureDataCheckResponse(Response):
323    """Here's the result of that data check, boss."""
324
325    # Whether the data signature was valid.
326    result: Annotated[bool, IOAttrs('v')]
327
328
329@ioprepped
330@dataclass
331class SecureDataCheckerRequest(Message):
332    """Can I get a checker over here?."""
333
334    @override
335    @classmethod
336    def get_response_types(cls) -> list[type[Response] | None]:
337        return [SecureDataCheckerResponse]
338
339
340@ioprepped
341@dataclass
342class SecureDataCheckerResponse(Response):
343    """Here's that checker ya asked for, boss."""
344
345    checker: Annotated[SecureDataChecker, IOAttrs('c')]
class WebLocation(enum.Enum):
22class WebLocation(Enum):
23    """Set of places we can be directed on ballistica.net."""
24
25    ACCOUNT_EDITOR = 'e'
26    ACCOUNT_DELETE_SECTION = 'd'

Set of places we can be directed on ballistica.net.

ACCOUNT_EDITOR = <WebLocation.ACCOUNT_EDITOR: 'e'>
ACCOUNT_DELETE_SECTION = <WebLocation.ACCOUNT_DELETE_SECTION: 'd'>
@ioprepped
@dataclass
class LoginProxyRequestMessage(efro.message._message.Message):
29@ioprepped
30@dataclass
31class LoginProxyRequestMessage(Message):
32    """Request send to the cloud to ask for a login-proxy."""
33
34    @override
35    @classmethod
36    def get_response_types(cls) -> list[type[Response] | None]:
37        return [LoginProxyRequestResponse]

Request send to the cloud to ask for a login-proxy.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
34    @override
35    @classmethod
36    def get_response_types(cls) -> list[type[Response] | None]:
37        return [LoginProxyRequestResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class LoginProxyRequestResponse(efro.message._message.Response):
40@ioprepped
41@dataclass
42class LoginProxyRequestResponse(Response):
43    """Response to a request for a login proxy."""
44
45    # URL to direct the user to for sign in.
46    url: Annotated[str, IOAttrs('u')]
47
48    # URL to use for overlay-web-browser sign ins.
49    url_overlay: Annotated[str, IOAttrs('uo')]
50
51    # Proxy-Login id for querying results.
52    proxyid: Annotated[str, IOAttrs('p')]
53
54    # Proxy-Login key for querying results.
55    proxykey: Annotated[str, IOAttrs('k')]

Response to a request for a login proxy.

LoginProxyRequestResponse( url: Annotated[str, <efro.dataclassio.IOAttrs object>], url_overlay: Annotated[str, <efro.dataclassio.IOAttrs object>], proxyid: Annotated[str, <efro.dataclassio.IOAttrs object>], proxykey: Annotated[str, <efro.dataclassio.IOAttrs object>])
url: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107536d50>]
url_overlay: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075371a0>]
proxyid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075372f0>]
proxykey: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107537410>]
@ioprepped
@dataclass
class LoginProxyStateQueryMessage(efro.message._message.Message):
58@ioprepped
59@dataclass
60class LoginProxyStateQueryMessage(Message):
61    """Soo.. how is that login proxy going?"""
62
63    proxyid: Annotated[str, IOAttrs('p')]
64    proxykey: Annotated[str, IOAttrs('k')]
65
66    @override
67    @classmethod
68    def get_response_types(cls) -> list[type[Response] | None]:
69        return [LoginProxyStateQueryResponse]

Soo.. how is that login proxy going?

LoginProxyStateQueryMessage( proxyid: Annotated[str, <efro.dataclassio.IOAttrs object>], proxykey: Annotated[str, <efro.dataclassio.IOAttrs object>])
proxyid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107489070>]
proxykey: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107488ef0>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
66    @override
67    @classmethod
68    def get_response_types(cls) -> list[type[Response] | None]:
69        return [LoginProxyStateQueryResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class LoginProxyStateQueryResponse(efro.message._message.Response):
72@ioprepped
73@dataclass
74class LoginProxyStateQueryResponse(Response):
75    """Here's the info on that login-proxy you asked about, boss."""
76
77    class State(Enum):
78        """States a login-proxy can be in."""
79
80        WAITING = 'waiting'
81        SUCCESS = 'success'
82        FAIL = 'fail'
83
84    state: Annotated[State, IOAttrs('s')]
85
86    # On success, these will be filled out.
87    credentials: Annotated[str | None, IOAttrs('tk')]

Here's the info on that login-proxy you asked about, boss.

LoginProxyStateQueryResponse( state: Annotated[LoginProxyStateQueryResponse.State, <efro.dataclassio.IOAttrs object>], credentials: Annotated[str | None, <efro.dataclassio.IOAttrs object>])
state: Annotated[LoginProxyStateQueryResponse.State, <efro.dataclassio.IOAttrs object at 0x1075356a0>]
credentials: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x105ea4da0>]
class LoginProxyStateQueryResponse.State(enum.Enum):
77    class State(Enum):
78        """States a login-proxy can be in."""
79
80        WAITING = 'waiting'
81        SUCCESS = 'success'
82        FAIL = 'fail'

States a login-proxy can be in.

WAITING = <State.WAITING: 'waiting'>
SUCCESS = <State.SUCCESS: 'success'>
FAIL = <State.FAIL: 'fail'>
@ioprepped
@dataclass
class LoginProxyCompleteMessage(efro.message._message.Message):
90@ioprepped
91@dataclass
92class LoginProxyCompleteMessage(Message):
93    """Just so you know, we're done with this proxy."""
94
95    proxyid: Annotated[str, IOAttrs('p')]

Just so you know, we're done with this proxy.

LoginProxyCompleteMessage(proxyid: Annotated[str, <efro.dataclassio.IOAttrs object>])
proxyid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x10748b5f0>]
@ioprepped
@dataclass
class PingMessage(efro.message._message.Message):
 98@ioprepped
 99@dataclass
100class PingMessage(Message):
101    """Standard ping."""
102
103    @override
104    @classmethod
105    def get_response_types(cls) -> list[type[Response] | None]:
106        return [PingResponse]

Standard ping.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
103    @override
104    @classmethod
105    def get_response_types(cls) -> list[type[Response] | None]:
106        return [PingResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class PingResponse(efro.message._message.Response):
109@ioprepped
110@dataclass
111class PingResponse(Response):
112    """pong."""

pong.

@ioprepped
@dataclass
class TestMessage(efro.message._message.Message):
115@ioprepped
116@dataclass
117class TestMessage(Message):
118    """Can I get some of that workspace action?"""
119
120    testfoo: Annotated[int, IOAttrs('f')]
121
122    @override
123    @classmethod
124    def get_response_types(cls) -> list[type[Response] | None]:
125        return [TestResponse]

Can I get some of that workspace action?

TestMessage(testfoo: Annotated[int, <efro.dataclassio.IOAttrs object>])
testfoo: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075f0050>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
122    @override
123    @classmethod
124    def get_response_types(cls) -> list[type[Response] | None]:
125        return [TestResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class TestResponse(efro.message._message.Response):
128@ioprepped
129@dataclass
130class TestResponse(Response):
131    """Here's that workspace you asked for, boss."""
132
133    testfoo: Annotated[int, IOAttrs('f')]

Here's that workspace you asked for, boss.

TestResponse(testfoo: Annotated[int, <efro.dataclassio.IOAttrs object>])
testfoo: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075f2690>]
@ioprepped
@dataclass
class SendInfoMessage(efro.message._message.Message):
136@ioprepped
137@dataclass
138class SendInfoMessage(Message):
139    """User is using the send-info function"""
140
141    description: Annotated[str, IOAttrs('c')]
142
143    @override
144    @classmethod
145    def get_response_types(cls) -> list[type[Response] | None]:
146        return [SendInfoResponse]

User is using the send-info function

SendInfoMessage(description: Annotated[str, <efro.dataclassio.IOAttrs object>])
description: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075f31d0>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
143    @override
144    @classmethod
145    def get_response_types(cls) -> list[type[Response] | None]:
146        return [SendInfoResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class SendInfoResponse(efro.message._message.Response):
149@ioprepped
150@dataclass
151class SendInfoResponse(Response):
152    """Response to sending into the server."""
153
154    handled: Annotated[bool, IOAttrs('v')]
155    message: Annotated[str | None, IOAttrs('m', store_default=False)] = None
156    legacy_code: Annotated[str | None, IOAttrs('l', store_default=False)] = None

Response to sending into the server.

SendInfoResponse( handled: Annotated[bool, <efro.dataclassio.IOAttrs object>], message: Annotated[str | None, <efro.dataclassio.IOAttrs object>] = None, legacy_code: Annotated[str | None, <efro.dataclassio.IOAttrs object>] = None)
handled: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x1075f21b0>]
message: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1075f22a0>] = None
legacy_code: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1075f2420>] = None
@ioprepped
@dataclass
class WorkspaceFetchState:
159@ioprepped
160@dataclass
161class WorkspaceFetchState:
162    """Common state data for a workspace fetch."""
163
164    manifest: Annotated[DirectoryManifest, IOAttrs('m')]
165    iteration: Annotated[int, IOAttrs('i')] = 0
166    total_deletes: Annotated[int, IOAttrs('tdels')] = 0
167    total_downloads: Annotated[int, IOAttrs('tdlds')] = 0
168    total_up_to_date: Annotated[int | None, IOAttrs('tunmd')] = None

Common state data for a workspace fetch.

WorkspaceFetchState( manifest: Annotated[bacommon.transfer.DirectoryManifest, <efro.dataclassio.IOAttrs object>], iteration: Annotated[int, <efro.dataclassio.IOAttrs object>] = 0, total_deletes: Annotated[int, <efro.dataclassio.IOAttrs object>] = 0, total_downloads: Annotated[int, <efro.dataclassio.IOAttrs object>] = 0, total_up_to_date: Annotated[int | None, <efro.dataclassio.IOAttrs object>] = None)
manifest: Annotated[bacommon.transfer.DirectoryManifest, <efro.dataclassio.IOAttrs object at 0x1075f34d0>]
iteration: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075f36b0>] = 0
total_deletes: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075f3800>] = 0
total_downloads: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075f3920>] = 0
total_up_to_date: Annotated[int | None, <efro.dataclassio.IOAttrs object at 0x1075f39b0>] = None
@ioprepped
@dataclass
class WorkspaceFetchMessage(efro.message._message.Message):
171@ioprepped
172@dataclass
173class WorkspaceFetchMessage(Message):
174    """Can I get some of that workspace action?"""
175
176    workspaceid: Annotated[str, IOAttrs('w')]
177    state: Annotated[WorkspaceFetchState, IOAttrs('s')]
178
179    @override
180    @classmethod
181    def get_response_types(cls) -> list[type[Response] | None]:
182        return [WorkspaceFetchResponse]

Can I get some of that workspace action?

WorkspaceFetchMessage( workspaceid: Annotated[str, <efro.dataclassio.IOAttrs object>], state: Annotated[WorkspaceFetchState, <efro.dataclassio.IOAttrs object>])
workspaceid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075d2330>]
state: Annotated[WorkspaceFetchState, <efro.dataclassio.IOAttrs object at 0x1075d0350>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
179    @override
180    @classmethod
181    def get_response_types(cls) -> list[type[Response] | None]:
182        return [WorkspaceFetchResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class WorkspaceFetchResponse(efro.message._message.Response):
185@ioprepped
186@dataclass
187class WorkspaceFetchResponse(Response):
188    """Here's that workspace you asked for, boss."""
189
190    state: Annotated[WorkspaceFetchState, IOAttrs('s')]
191    deletes: Annotated[list[str], IOAttrs('dlt', store_default=False)] = field(
192        default_factory=list
193    )
194    downloads_inline: Annotated[
195        dict[str, bytes], IOAttrs('dinl', store_default=False)
196    ] = field(default_factory=dict)
197
198    done: Annotated[bool, IOAttrs('d')] = False

Here's that workspace you asked for, boss.

WorkspaceFetchResponse( state: Annotated[WorkspaceFetchState, <efro.dataclassio.IOAttrs object>], deletes: Annotated[list[str], <efro.dataclassio.IOAttrs object>] = <factory>, downloads_inline: Annotated[dict[str, bytes], <efro.dataclassio.IOAttrs object>] = <factory>, done: Annotated[bool, <efro.dataclassio.IOAttrs object>] = False)
state: Annotated[WorkspaceFetchState, <efro.dataclassio.IOAttrs object at 0x1075d3080>]
deletes: Annotated[list[str], <efro.dataclassio.IOAttrs object at 0x1075d1820>]
downloads_inline: Annotated[dict[str, bytes], <efro.dataclassio.IOAttrs object at 0x1075d1970>]
done: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x1075d1b20>] = False
@ioprepped
@dataclass
class MerchAvailabilityMessage(efro.message._message.Message):
201@ioprepped
202@dataclass
203class MerchAvailabilityMessage(Message):
204    """Can we show merch link?"""
205
206    @override
207    @classmethod
208    def get_response_types(cls) -> list[type[Response] | None]:
209        return [MerchAvailabilityResponse]

Can we show merch link?

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
206    @override
207    @classmethod
208    def get_response_types(cls) -> list[type[Response] | None]:
209        return [MerchAvailabilityResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class MerchAvailabilityResponse(efro.message._message.Response):
212@ioprepped
213@dataclass
214class MerchAvailabilityResponse(Response):
215    """About that merch..."""
216
217    url: Annotated[str | None, IOAttrs('u')]

About that merch...

MerchAvailabilityResponse(url: Annotated[str | None, <efro.dataclassio.IOAttrs object>])
url: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1075d35f0>]
@ioprepped
@dataclass
class SignInMessage(efro.message._message.Message):
220@ioprepped
221@dataclass
222class SignInMessage(Message):
223    """Can I sign in please?"""
224
225    login_type: Annotated[LoginType, IOAttrs('l')]
226    sign_in_token: Annotated[str, IOAttrs('t')]
227
228    # For debugging. Can remove soft_default once build 20988+ is ubiquitous.
229    description: Annotated[str, IOAttrs('d', soft_default='-')]
230    apptime: Annotated[float, IOAttrs('at', soft_default=-1.0)]
231
232    @override
233    @classmethod
234    def get_response_types(cls) -> list[type[Response] | None]:
235        return [SignInResponse]

Can I sign in please?

SignInMessage( login_type: Annotated[bacommon.login.LoginType, <efro.dataclassio.IOAttrs object>], sign_in_token: Annotated[str, <efro.dataclassio.IOAttrs object>], description: Annotated[str, <efro.dataclassio.IOAttrs object>], apptime: Annotated[float, <efro.dataclassio.IOAttrs object>])
login_type: Annotated[bacommon.login.LoginType, <efro.dataclassio.IOAttrs object at 0x1076134d0>]
sign_in_token: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107610200>]
description: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1076103b0>]
apptime: Annotated[float, <efro.dataclassio.IOAttrs object at 0x107610440>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
232    @override
233    @classmethod
234    def get_response_types(cls) -> list[type[Response] | None]:
235        return [SignInResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class SignInResponse(efro.message._message.Response):
238@ioprepped
239@dataclass
240class SignInResponse(Response):
241    """Here's that sign-in result you asked for, boss."""
242
243    credentials: Annotated[str | None, IOAttrs('c')]

Here's that sign-in result you asked for, boss.

SignInResponse( credentials: Annotated[str | None, <efro.dataclassio.IOAttrs object>])
credentials: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x107612f90>]
@ioprepped
@dataclass
class ManageAccountMessage(efro.message._message.Message):
246@ioprepped
247@dataclass
248class ManageAccountMessage(Message):
249    """Message asking for a manage-account url."""
250
251    weblocation: Annotated[WebLocation, IOAttrs('l')] = (
252        WebLocation.ACCOUNT_EDITOR
253    )
254
255    @override
256    @classmethod
257    def get_response_types(cls) -> list[type[Response] | None]:
258        return [ManageAccountResponse]

Message asking for a manage-account url.

ManageAccountMessage( weblocation: Annotated[WebLocation, <efro.dataclassio.IOAttrs object>] = <WebLocation.ACCOUNT_EDITOR: 'e'>)
weblocation: Annotated[WebLocation, <efro.dataclassio.IOAttrs object at 0x107612000>] = <WebLocation.ACCOUNT_EDITOR: 'e'>
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
255    @override
256    @classmethod
257    def get_response_types(cls) -> list[type[Response] | None]:
258        return [ManageAccountResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class ManageAccountResponse(efro.message._message.Response):
261@ioprepped
262@dataclass
263class ManageAccountResponse(Response):
264    """Here's that sign-in result you asked for, boss."""
265
266    url: Annotated[str | None, IOAttrs('u')]

Here's that sign-in result you asked for, boss.

ManageAccountResponse(url: Annotated[str | None, <efro.dataclassio.IOAttrs object>])
url: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x107612900>]
@ioprepped
@dataclass
class StoreQueryMessage(efro.message._message.Message):
269@ioprepped
270@dataclass
271class StoreQueryMessage(Message):
272    """Message asking about purchasable stuff and store related state."""
273
274    @override
275    @classmethod
276    def get_response_types(cls) -> list[type[Response] | None]:
277        return [StoreQueryResponse]

Message asking about purchasable stuff and store related state.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
274    @override
275    @classmethod
276    def get_response_types(cls) -> list[type[Response] | None]:
277        return [StoreQueryResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class StoreQueryResponse(efro.message._message.Response):
280@ioprepped
281@dataclass
282class StoreQueryResponse(Response):
283    """Here's that store info you asked for, boss."""
284
285    class Result(Enum):
286        """Our overall result."""
287
288        SUCCESS = 's'
289        ERROR = 'e'
290
291    @dataclass
292    class Purchase:
293        """Info about a purchasable thing."""
294
295        purchaseid: Annotated[str, IOAttrs('id')]
296
297    # Overall result; all data is undefined if not SUCCESS.
298    result: Annotated[Result, IOAttrs('r')]
299
300    tokens: Annotated[int, IOAttrs('t')]
301    gold_pass: Annotated[bool, IOAttrs('g')]
302
303    available_purchases: Annotated[list[Purchase], IOAttrs('p')]
304    token_info_url: Annotated[str, IOAttrs('tiu')]

Here's that store info you asked for, boss.

StoreQueryResponse( result: Annotated[StoreQueryResponse.Result, <efro.dataclassio.IOAttrs object>], tokens: Annotated[int, <efro.dataclassio.IOAttrs object>], gold_pass: Annotated[bool, <efro.dataclassio.IOAttrs object>], available_purchases: Annotated[list[StoreQueryResponse.Purchase], <efro.dataclassio.IOAttrs object>], token_info_url: Annotated[str, <efro.dataclassio.IOAttrs object>])
result: Annotated[StoreQueryResponse.Result, <efro.dataclassio.IOAttrs object at 0x1075fda60>]
tokens: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1075fc320>]
gold_pass: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x1075fc470>]
available_purchases: Annotated[list[StoreQueryResponse.Purchase], <efro.dataclassio.IOAttrs object at 0x1075fc4d0>]
token_info_url: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075fc680>]
class StoreQueryResponse.Result(enum.Enum):
285    class Result(Enum):
286        """Our overall result."""
287
288        SUCCESS = 's'
289        ERROR = 'e'

Our overall result.

SUCCESS = <Result.SUCCESS: 's'>
ERROR = <Result.ERROR: 'e'>
@dataclass
class StoreQueryResponse.Purchase:
291    @dataclass
292    class Purchase:
293        """Info about a purchasable thing."""
294
295        purchaseid: Annotated[str, IOAttrs('id')]

Info about a purchasable thing.

StoreQueryResponse.Purchase(purchaseid: Annotated[str, <efro.dataclassio.IOAttrs object>])
purchaseid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1075fe300>]
@ioprepped
@dataclass
class SecureDataCheckMessage(efro.message._message.Message):
307@ioprepped
308@dataclass
309class SecureDataCheckMessage(Message):
310    """Was this data signed by the master-server?."""
311
312    data: Annotated[bytes, IOAttrs('d')]
313    signature: Annotated[bytes, IOAttrs('s')]
314
315    @override
316    @classmethod
317    def get_response_types(cls) -> list[type[Response] | None]:
318        return [SecureDataCheckResponse]

Was this data signed by the master-server?.

SecureDataCheckMessage( data: Annotated[bytes, <efro.dataclassio.IOAttrs object>], signature: Annotated[bytes, <efro.dataclassio.IOAttrs object>])
data: Annotated[bytes, <efro.dataclassio.IOAttrs object at 0x1075fee40>]
signature: Annotated[bytes, <efro.dataclassio.IOAttrs object at 0x1075ff1d0>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
315    @override
316    @classmethod
317    def get_response_types(cls) -> list[type[Response] | None]:
318        return [SecureDataCheckResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class SecureDataCheckResponse(efro.message._message.Response):
321@ioprepped
322@dataclass
323class SecureDataCheckResponse(Response):
324    """Here's the result of that data check, boss."""
325
326    # Whether the data signature was valid.
327    result: Annotated[bool, IOAttrs('v')]

Here's the result of that data check, boss.

SecureDataCheckResponse(result: Annotated[bool, <efro.dataclassio.IOAttrs object>])
result: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x10768d730>]
@ioprepped
@dataclass
class SecureDataCheckerRequest(efro.message._message.Message):
330@ioprepped
331@dataclass
332class SecureDataCheckerRequest(Message):
333    """Can I get a checker over here?."""
334
335    @override
336    @classmethod
337    def get_response_types(cls) -> list[type[Response] | None]:
338        return [SecureDataCheckerResponse]

Can I get a checker over here?.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
335    @override
336    @classmethod
337    def get_response_types(cls) -> list[type[Response] | None]:
338        return [SecureDataCheckerResponse]

Return all Response types this Message can return when sent.

The default implementation specifies a None return type.

@ioprepped
@dataclass
class SecureDataCheckerResponse(efro.message._message.Response):
341@ioprepped
342@dataclass
343class SecureDataCheckerResponse(Response):
344    """Here's that checker ya asked for, boss."""
345
346    checker: Annotated[SecureDataChecker, IOAttrs('c')]

Here's that checker ya asked for, boss.

SecureDataCheckerResponse( checker: Annotated[bacommon.securedata.SecureDataChecker, <efro.dataclassio.IOAttrs object>])
checker: Annotated[bacommon.securedata.SecureDataChecker, <efro.dataclassio.IOAttrs object at 0x10768f500>]