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

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

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
33    @override
34    @classmethod
35    def get_response_types(cls) -> list[type[Response] | None]:
36        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):
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')]

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 0x1070caa80>]
url_overlay: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1070c9be0>]
proxyid: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1070c9cd0>]
proxykey: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1070c9eb0>]
@ioprepped
@dataclass
class LoginProxyStateQueryMessage(efro.message._message.Message):
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]

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 0x1070ca840>]
proxykey: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1070cb080>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
65    @override
66    @classmethod
67    def get_response_types(cls) -> list[type[Response] | None]:
68        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):
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')]

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 0x1070cbf20>]
credentials: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1070ab170>]
class LoginProxyStateQueryResponse.State(enum.Enum):
76    class State(Enum):
77        """States a login-proxy can be in."""
78
79        WAITING = 'waiting'
80        SUCCESS = 'success'
81        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):
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')]

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 0x1070ab590>]
@ioprepped
@dataclass
class PingMessage(efro.message._message.Message):
 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]

Standard ping.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
102    @override
103    @classmethod
104    def get_response_types(cls) -> list[type[Response] | None]:
105        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):
108@ioprepped
109@dataclass
110class PingResponse(Response):
111    """pong."""

pong.

@ioprepped
@dataclass
class TestMessage(efro.message._message.Message):
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]

Can I get some of that workspace action?

TestMessage(testfoo: Annotated[int, <efro.dataclassio.IOAttrs object>])
testfoo: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1070aba40>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
121    @override
122    @classmethod
123    def get_response_types(cls) -> list[type[Response] | None]:
124        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):
127@ioprepped
128@dataclass
129class TestResponse(Response):
130    """Here's that workspace you asked for, boss."""
131
132    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 0x1070e6330>]
@ioprepped
@dataclass
class SendInfoMessage(efro.message._message.Message):
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]

User is using the send-info function

SendInfoMessage(description: Annotated[str, <efro.dataclassio.IOAttrs object>])
description: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1070e6b40>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
142    @override
143    @classmethod
144    def get_response_types(cls) -> list[type[Response] | None]:
145        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):
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

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 0x1070e5e80>]
message: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1070e5f70>] = None
legacy_code: Annotated[str | None, <efro.dataclassio.IOAttrs object at 0x1070e6120>] = None
@ioprepped
@dataclass
class WorkspaceFetchState:
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

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 0x1070e7080>]
iteration: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1070e7260>] = 0
total_deletes: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1070e7380>] = 0
total_downloads: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1070e74d0>] = 0
total_up_to_date: Annotated[int | None, <efro.dataclassio.IOAttrs object at 0x1070e7560>] = None
@ioprepped
@dataclass
class WorkspaceFetchMessage(efro.message._message.Message):
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]

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 0x1070c1eb0>]
state: Annotated[WorkspaceFetchState, <efro.dataclassio.IOAttrs object at 0x1070c1190>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
178    @override
179    @classmethod
180    def get_response_types(cls) -> list[type[Response] | None]:
181        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):
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

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 0x1070c2c00>]
deletes: Annotated[list[str], <efro.dataclassio.IOAttrs object at 0x1070c1520>]
downloads_inline: Annotated[dict[str, bytes], <efro.dataclassio.IOAttrs object at 0x1070c1670>]
done: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x1070c1820>] = False
@ioprepped
@dataclass
class MerchAvailabilityMessage(efro.message._message.Message):
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]

Can we show merch link?

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
205    @override
206    @classmethod
207    def get_response_types(cls) -> list[type[Response] | None]:
208        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):
211@ioprepped
212@dataclass
213class MerchAvailabilityResponse(Response):
214    """About that merch..."""
215
216    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 0x1070c31d0>]
@ioprepped
@dataclass
class SignInMessage(efro.message._message.Message):
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]

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 0x1070c3e60>]
sign_in_token: Annotated[str, <efro.dataclassio.IOAttrs object at 0x107138170>]
description: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1071381d0>]
apptime: Annotated[float, <efro.dataclassio.IOAttrs object at 0x107138260>]
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
231    @override
232    @classmethod
233    def get_response_types(cls) -> list[type[Response] | None]:
234        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):
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')]

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 0x10713aba0>]
@ioprepped
@dataclass
class ManageAccountMessage(efro.message._message.Message):
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]

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 0x10713bd40>] = <WebLocation.ACCOUNT_EDITOR: 'e'>
@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
254    @override
255    @classmethod
256    def get_response_types(cls) -> list[type[Response] | None]:
257        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):
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')]

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 0x10713a5a0>]
@ioprepped
@dataclass
class StoreQueryMessage(efro.message._message.Message):
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]

Message asking about purchasable stuff and store related state.

@override
@classmethod
def get_response_types(cls) -> list[type[efro.message.Response] | None]:
273    @override
274    @classmethod
275    def get_response_types(cls) -> list[type[Response] | None]:
276        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):
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')]

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 0x107164050>]
tokens: Annotated[int, <efro.dataclassio.IOAttrs object at 0x1071642c0>]
gold_pass: Annotated[bool, <efro.dataclassio.IOAttrs object at 0x1071643e0>]
available_purchases: Annotated[list[StoreQueryResponse.Purchase], <efro.dataclassio.IOAttrs object at 0x107164440>]
token_info_url: Annotated[str, <efro.dataclassio.IOAttrs object at 0x1071645f0>]
class StoreQueryResponse.Result(enum.Enum):
284    class Result(Enum):
285        """Our overall result."""
286
287        SUCCESS = 's'
288        ERROR = 'e'

Our overall result.

SUCCESS = <Result.SUCCESS: 's'>
ERROR = <Result.ERROR: 'e'>
@dataclass
class StoreQueryResponse.Purchase:
290    @dataclass
291    class Purchase:
292        """Info about a purchasable thing."""
293
294        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 0x1071661b0>]