Skip to content

Commit 1c73561

Browse files
authored
Merge pull request #10 from clockworklabs/staging
Release v0.7.0-beta
2 parents 350e6e5 + 0947296 commit 1c73561

File tree

8 files changed

+104
-19
lines changed

8 files changed

+104
-19
lines changed

examples/quickstart/client/main.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ def on_subscription_applied():
7474
print_messages_in_order()
7575

7676

77-
def on_send_message_reducer(sender, status, message, msg):
78-
if sender == local_identity:
77+
def on_send_message_reducer(sender_id, sender_address, status, message, msg):
78+
if sender_id == local_identity:
7979
if status == "failed":
8080
print(f"Failed to send message: {message}")
8181

8282

83-
def on_set_name_reducer(sender, status, message, name):
84-
if sender == local_identity:
83+
def on_set_name_reducer(sender_id, sender_address, status, message, name):
84+
if sender_id == local_identity:
8585
if status == "failed":
8686
print(f"Failed to set name: {message}")
8787

examples/quickstart/client/module_bindings/message.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from __future__ import annotations
55
from typing import List, Iterator, Callable
66

7-
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient, Identity
7+
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient, Identity, Address
88
from spacetimedb_sdk.spacetimedb_client import ReducerEvent
99

1010
class Message:

examples/quickstart/client/module_bindings/send_message_reducer.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient
77
from spacetimedb_sdk.spacetimedb_client import Identity
8+
from spacetimedb_sdk.spacetimedb_client import Address
89

910

11+
reducer_name = "send_message"
12+
1013
def send_message(text: str):
1114
text = text
1215
SpacetimeDBClient.instance._reducer_call("send_message", text)
1316

14-
def register_on_send_message(callback: Callable[[Identity, str, str, str], None]):
17+
def register_on_send_message(callback: Callable[[Identity, Address, str, str, str], None]):
1518
SpacetimeDBClient.instance._register_reducer("send_message", callback)
1619

1720
def _decode_args(data):

examples/quickstart/client/module_bindings/set_name_reducer.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient
77
from spacetimedb_sdk.spacetimedb_client import Identity
8+
from spacetimedb_sdk.spacetimedb_client import Address
89

910

11+
reducer_name = "set_name"
12+
1013
def set_name(name: str):
1114
name = name
1215
SpacetimeDBClient.instance._reducer_call("set_name", name)
1316

14-
def register_on_set_name(callback: Callable[[Identity, str, str, str], None]):
17+
def register_on_set_name(callback: Callable[[Identity, Address, str, str, str], None]):
1518
SpacetimeDBClient.instance._register_reducer("set_name", callback)
1619

1720
def _decode_args(data):

examples/quickstart/client/module_bindings/user.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from __future__ import annotations
55
from typing import List, Iterator, Callable
66

7-
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient, Identity
7+
from spacetimedb_sdk.spacetimedb_client import SpacetimeDBClient, Identity, Address
88
from spacetimedb_sdk.spacetimedb_client import ReducerEvent
99

1010
class User:

src/spacetimedb_sdk/spacetime_websocket_client.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
class WebSocketClient:
8-
def __init__(self, protocol, on_connect=None, on_close=None, on_error=None, on_message=None):
8+
def __init__(self, protocol, on_connect=None, on_close=None, on_error=None, on_message=None, client_address=None):
99
self._on_connect = on_connect
1010
self._on_close = on_close
1111
self._on_error = on_error
@@ -17,11 +17,15 @@ def __init__(self, protocol, on_connect=None, on_close=None, on_error=None, on_m
1717
self.host = None
1818
self.name_or_address = None
1919
self.is_connected = False
20+
self.client_address = client_address
2021

2122
def connect(self, auth, host, name_or_address, ssl_enabled):
2223
protocol = "wss" if ssl_enabled else "ws"
2324
url = f"{protocol}://{host}/database/subscribe/{name_or_address}"
2425

26+
if self.client_address is not None:
27+
url += f"?client_address={self.client_address}"
28+
2529
self.host = host
2630
self.name_or_address = name_or_address
2731

src/spacetimedb_sdk/spacetimedb_async_client.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,9 @@ def on_disconnect(close_msg):
212212
else:
213213
self.event_queue.put_nowait(("error", SpacetimeDBException(close_msg)))
214214

215-
def on_identity_received(auth_token, identity):
215+
def on_identity_received(auth_token, identity, address):
216216
self.identity = identity
217+
self.address = address
217218
self.client.subscribe(subscription_queries)
218219
self.event_queue.put_nowait(("connected", (auth_token, identity)))
219220

src/spacetimedb_sdk/spacetimedb_client.py

+83-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import json
55
import queue
6+
import random
67

78
from spacetimedb_sdk.spacetime_websocket_client import WebSocketClient
89
from spacetimedb_sdk.client_cache import ClientCache
@@ -56,6 +57,69 @@ def __eq__(self, other):
5657
def __hash__(self):
5758
return hash(self.data)
5859

60+
class Address:
61+
"""
62+
Represents a user address. This is a wrapper around the Uint8Array that is recieved from SpacetimeDB.
63+
64+
Attributes:
65+
data (bytes): The address data.
66+
"""
67+
68+
def __init__(self, data):
69+
self.data = bytes(data) # Ensure data is always bytes
70+
71+
@staticmethod
72+
def from_string(string):
73+
"""
74+
Returns an Address object with the data attribute set to the byte representation of the input string.
75+
Returns None if the string is all zeros.
76+
77+
Args:
78+
string (str): The input string.
79+
80+
Returns:
81+
Address: The Address object.
82+
"""
83+
address_bytes = bytes.fromhex(string)
84+
if all(byte == 0 for byte in address_bytes):
85+
return None
86+
else:
87+
return Address(address_bytes)
88+
89+
@staticmethod
90+
def from_bytes(data):
91+
"""
92+
Returns an Address object with the data attribute set to the input bytes.
93+
94+
Args:
95+
data (bytes): The input bytes.
96+
97+
Returns:
98+
Address: The Address object.
99+
"""
100+
if all(byte == 0 for byte in address_bytes):
101+
return None
102+
else:
103+
return Address(data)
104+
105+
@staticmethod
106+
def random():
107+
"""
108+
Returns a random Address.
109+
"""
110+
return Address(bytes(random.getrandbits(8) for _ in range(16)))
111+
112+
# override to_string
113+
def __str__(self):
114+
return self.data.hex()
115+
116+
# override = operator
117+
def __eq__(self, other):
118+
return isinstance(other, Address) and self.data == other.data
119+
120+
def __hash__(self):
121+
return hash(self.data)
122+
59123

60124
class DbEvent:
61125
"""
@@ -93,11 +157,12 @@ class _IdentityReceivedMessage(_ClientApiMessage):
93157
This class is intended for internal use only and should not be used externally.
94158
"""
95159

96-
def __init__(self, auth_token, identity):
160+
def __init__(self, auth_token, identity, address):
97161
super().__init__("IdentityReceived")
98162

99163
self.auth_token = auth_token
100164
self.identity = identity
165+
self.address = address
101166

102167

103168
class _SubscriptionUpdateMessage(_ClientApiMessage):
@@ -114,15 +179,17 @@ class ReducerEvent:
114179
This class contains the information about a reducer event to be passed to row update callbacks.
115180
"""
116181

117-
def __init__(self, caller_identity, reducer_name, status, message, args):
182+
def __init__(self, caller_identity, caller_address, reducer_name, status, message, args):
118183
self.caller_identity = caller_identity
184+
self.caller_address = caller_address
119185
self.reducer_name = reducer_name
120186
self.status = status
121187
self.message = message
122188
self.args = args
123189

124190

125191
class TransactionUpdateMessage(_ClientApiMessage):
192+
# This docstring appears incorrect
126193
"""
127194
Represents a transaction update message. Used in on_event callbacks.
128195
@@ -140,14 +207,15 @@ class TransactionUpdateMessage(_ClientApiMessage):
140207
def __init__(
141208
self,
142209
caller_identity: Identity,
210+
caller_address: Address,
143211
status: str,
144212
message: str,
145213
reducer_name: str,
146214
args: Dict,
147215
):
148216
super().__init__("TransactionUpdate")
149217
self.reducer_event = ReducerEvent(
150-
caller_identity, reducer_name, status, message, args
218+
caller_identity, caller_address, reducer_name, status, message, args
151219
)
152220

153221

@@ -169,7 +237,7 @@ def init(
169237
autogen_package: ModuleType,
170238
on_connect: Callable[[], None] = None,
171239
on_disconnect: Callable[[str], None] = None,
172-
on_identity: Callable[[str, Identity], None] = None,
240+
on_identity: Callable[[str, Identity, Address], None] = None,
173241
on_error: Callable[[str], None] = None,
174242
):
175243
"""
@@ -182,7 +250,7 @@ def init(
182250
autogen_package (ModuleType): Python package where SpacetimeDB module generated files are located.
183251
on_connect (Callable[[], None], optional): Optional callback called when a connection is made to the SpacetimeDB module.
184252
on_disconnect (Callable[[str], None], optional): Optional callback called when the Python client is disconnected from the SpacetimeDB module. The argument is the close message.
185-
on_identity (Callable[[str, bytes], None], optional): Called when the user identity is recieved from SpacetimeDB. First argument is the auth token used to login in future sessions.
253+
on_identity (Callable[[str, Identity, Address], None], optional): Called when the user identity is recieved from SpacetimeDB. First argument is the auth token used to login in future sessions.
186254
on_error (Callable[[str], None], optional): Optional callback called when the Python client connection encounters an error. The argument is the error message.
187255
188256
Example:
@@ -210,6 +278,7 @@ def __init__(self, autogen_package):
210278
self._on_event = []
211279

212280
self.identity = None
281+
self.address = Address.random()
213282

214283
self.client_cache = ClientCache(autogen_package)
215284
self.message_queue = queue.Queue()
@@ -238,6 +307,7 @@ def connect(
238307
on_error=on_error,
239308
on_close=on_disconnect,
240309
on_message=self._on_message,
310+
client_address=self.address,
241311
)
242312
# print("CONNECTING " + host + " " + address_or_name)
243313
self.wsc.connect(
@@ -420,7 +490,8 @@ def _on_message(self, data):
420490
# is this safe to do in the message thread?
421491
token = message["IdentityToken"]["token"]
422492
identity = Identity.from_string(message["IdentityToken"]["identity"])
423-
self.message_queue.put(_IdentityReceivedMessage(token, identity))
493+
address = Address.from_string(message["IdentityToken"]["address"])
494+
self.message_queue.put(_IdentityReceivedMessage(token, identity, address))
424495
elif "SubscriptionUpdate" in message or "TransactionUpdate" in message:
425496
clientapi_message = None
426497
table_updates = None
@@ -432,6 +503,7 @@ def _on_message(self, data):
432503
# DAB Todo: We need reducer codegen to parse the args
433504
clientapi_message = TransactionUpdateMessage(
434505
Identity.from_string(spacetime_message["event"]["caller_identity"]),
506+
Address.from_string(spacetime_message["event"]["caller_address"]),
435507
spacetime_message["event"]["status"],
436508
spacetime_message["event"]["message"],
437509
spacetime_message["event"]["function_call"]["reducer"],
@@ -473,8 +545,9 @@ def _do_update(self):
473545

474546
if next_message.transaction_type == "IdentityReceived":
475547
self.identity = next_message.identity
548+
self.address = next_message.address
476549
if self._on_identity:
477-
self._on_identity(next_message.auth_token, self.identity)
550+
self._on_identity(next_message.auth_token, self.identity, self.address)
478551
else:
479552
# print(f"next_message: {next_message.transaction_type}")
480553
# apply all the event state before calling callbacks
@@ -596,14 +669,15 @@ def _do_update(self):
596669
decode_func = self.client_cache.reducer_cache[
597670
reducer_event.reducer_name
598671
]
599-
if reducer_event.status == "committed":
600-
args = decode_func(reducer_event.args)
672+
673+
args = decode_func(reducer_event.args)
601674

602675
for reducer_callback in self._reducer_callbacks[
603676
reducer_event.reducer_name
604677
]:
605678
reducer_callback(
606679
reducer_event.caller_identity,
680+
reducer_event.caller_address,
607681
reducer_event.status,
608682
reducer_event.message,
609683
*args,

0 commit comments

Comments
 (0)