Allow client to communicate with either local server or dev.lbry.id

This commit is contained in:
Daniel Krol 2022-06-16 11:46:29 -04:00
parent fcec1ad950
commit 027e0eadf6
3 changed files with 50 additions and 41 deletions

View file

@ -6,10 +6,12 @@ A couple example flows so it's clear how it works. We're assuming that we're sta
Set up a client for each wallet, but with the same sync account (which won't exist on the server yet). This will simulate clients on two different computers.
For this example we will be working with a locally running server so that we don't care about the data. If you want to communicate with `dev.lbry.id`, simply omit the `local=True`.
```
>>> from test_client import Client
>>> c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1')
>>> c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2')
>>> c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1', local=True)
>>> c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2', local=True)
```
Register the account on the server with one of the clients.
@ -23,9 +25,9 @@ Now that the account exists, grab an auth token with both clients.
```
>>> c1.get_auth_token()
Got auth token: 3d98076fda58400f3dbd5ea6511184507d5f8637bd5549e5cb0cc9cdbb7102e5
Got auth token: 2e1c00c0f2f205defc177bd21e64dd01c669e234cf23bbc19f73e720ac1ef12d
>>> c2.get_auth_token()
Got auth token: 1385a51bf3ba86a3e1f412908c3b2165cc399e06692a2dc602f5e17fe2c7993c
Got auth token: 07ab32cfac3961d30570537d4082abdf08123de6e5a28670dbf680be45e442d5
```
## Syncing
@ -41,7 +43,7 @@ No wallet found on the server for this account. Starting a new one.
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6ew8QGI/89sz70Oud6NljymaLSUCyNSBYwpTCBZu9gMbwXYuDKqB4YnZeYRJdHhXz+9NQ9qSkRUIPHQ4m6f38R38KvXCE5raRnnozrnmDOt/eGFUl9XYMrFcYqgqYSCxb1kTcWS1cWkkOO6TtrjeBKuc+qriKZr9ggk1pnLmnKQc=')
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6CjZHlCv4ZyHiPKA7PoIOOkQ6Fh9fYUYPe9xwiZRYdLKHDgtEQCIcwkNldP1TN8TwTht4Qj5QEnApwQkd2Y20nVjdCUTKLzu4gmdP8QBz2EEGR+XmZgosX937E8bmmqgC55ttgt8fh0o62cTonF4h1LLI7DoWw1SvEcqIIAEn/dc=')
'Success'
```
@ -52,7 +54,7 @@ Now, call `init_wallet_state` with the other client. This time, `init_wallet_sta
```
>>> c2.init_wallet_state()
Got latest walletState:
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6ew8QGI/89sz70Oud6NljymaLSUCyNSBYwpTCBZu9gMbwXYuDKqB4YnZeYRJdHhXz+9NQ9qSkRUIPHQ4m6f38R38KvXCE5raRnnozrnmDOt/eGFUl9XYMrFcYqgqYSCxb1kTcWS1cWkkOO6TtrjeBKuc+qriKZr9ggk1pnLmnKQc=')
WalletState(sequence=1, encrypted_wallet='czo4MTkyOjE2OjE6CjZHlCv4ZyHiPKA7PoIOOkQ6Fh9fYUYPe9xwiZRYdLKHDgtEQCIcwkNldP1TN8TwTht4Qj5QEnApwQkd2Y20nVjdCUTKLzu4gmdP8QBz2EEGR+XmZgosX937E8bmmqgC55ttgt8fh0o62cTonF4h1LLI7DoWw1SvEcqIIAEn/dc=')
```
## Updating
@ -63,11 +65,11 @@ Push a new version, GET it with the other client. Even though we haven't edited
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6DAT6j6JSp0by78XpOOMtGroxFUX5vh6X+oXhIVlHVhvmVgp+09vWt7IP/IGofP4Ua7Dggr9iyxF4A3F9tSNgxKrev08eMP+8W2LAwk3jTAtZPoh5vtz/20tJFWOw+Y+s00NRNXcDeT8GjZvgTfawy+k7WKQMt6ryW6c8liORDfA=')
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6LsWo7O3EQVw+buxGPuqJBBEn3oBM3/sAII2NjpbKi7tEvWxbWmKb+nNyr3fuvQ6YZZda0i0Rb7Veuq7ym+hYAn2pTt/8WrYR8K1HFnxs3y1m91HQIsXrl6NwxU5t+mZ6uInQUfEGEV6JLHfbt1NJ2pYlYvYTelusKZXq/kja8i4=')
'Success'
>>> c1.get_remote_wallet()
Got latest walletState:
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6DAT6j6JSp0by78XpOOMtGroxFUX5vh6X+oXhIVlHVhvmVgp+09vWt7IP/IGofP4Ua7Dggr9iyxF4A3F9tSNgxKrev08eMP+8W2LAwk3jTAtZPoh5vtz/20tJFWOw+Y+s00NRNXcDeT8GjZvgTfawy+k7WKQMt6ryW6c8liORDfA=')
WalletState(sequence=2, encrypted_wallet='czo4MTkyOjE2OjE6LsWo7O3EQVw+buxGPuqJBBEn3oBM3/sAII2NjpbKi7tEvWxbWmKb+nNyr3fuvQ6YZZda0i0Rb7Veuq7ym+hYAn2pTt/8WrYR8K1HFnxs3y1m91HQIsXrl6NwxU5t+mZ6uInQUfEGEV6JLHfbt1NJ2pYlYvYTelusKZXq/kja8i4=')
'Success'
```
@ -93,11 +95,11 @@ The wallet is synced between the clients. The client with the changed preference
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6SQ/9PBDeOs8sOG+QDnOBmgbOKJDUx3TJD1p9r/bIuD2R5lamKmn1UKz/fQynLJexPJj3QCJP5u5OKTZDMBhY6HF5qBV2ndnWmPLjB40KlGj7jjZJaETEMktyJjjKdLbsV8nKLpnB2KpyYZejJVppBS+DRswAFByTE6c5E+8FJ3TTPXhzTvE9L3RqvetQEUxn')
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6l5SVvs2yNDoC5j1316n0xQ5H6K1UEso/JpdpShfLW2bCY3lg9vOcwayO1v085RyItxEwtrtSnD3fnan3kr86GmSI8U6x5DxASHVdgceLBrclVkuCpFXllz6YNtWo5thjbf63PWSg4k6LHI8w50BT2tu9FUufCi67n7sTWnGb/0AjAFYU1sUTJ9aoeiZYrrur')
'Success'
>>> c2.get_remote_wallet()
Got latest walletState:
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6SQ/9PBDeOs8sOG+QDnOBmgbOKJDUx3TJD1p9r/bIuD2R5lamKmn1UKz/fQynLJexPJj3QCJP5u5OKTZDMBhY6HF5qBV2ndnWmPLjB40KlGj7jjZJaETEMktyJjjKdLbsV8nKLpnB2KpyYZejJVppBS+DRswAFByTE6c5E+8FJ3TTPXhzTvE9L3RqvetQEUxn')
WalletState(sequence=3, encrypted_wallet='czo4MTkyOjE2OjE6l5SVvs2yNDoC5j1316n0xQ5H6K1UEso/JpdpShfLW2bCY3lg9vOcwayO1v085RyItxEwtrtSnD3fnan3kr86GmSI8U6x5DxASHVdgceLBrclVkuCpFXllz6YNtWo5thjbf63PWSg4k6LHI8w50BT2tu9FUufCi67n7sTWnGb/0AjAFYU1sUTJ9aoeiZYrrur')
'Success'
>>> c2.get_preferences()
{'animal': 'cow', 'car': ''}
@ -124,7 +126,7 @@ One client POSTs its change first.
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62uWympFofMnLmZSGGPTC5qctGKlWkan/DmOFLVZHktzqY9OndxhY3VCr5QBMXOGyn/Y321zNtL6YNfA+gs3Ov6qhzcneERHJM3ByySjMPwEds4NVDctKW4HAXggZIA1xhga1XlNggrBXlu09Sqro9zEbJdrBwJQI6BeuZHpH2eaJBDI73ljTWgtqoIeLg1WA')
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE66nridrsrXcL/DlcudUs7RaAIZ3jRYQJhaacRH3vPNx0TZqkJbDcjMiHbiHY6U2AVhoAsLPIf/zcU+uDTw4IRcOL9Gozupc8tCrIcgm/kwXjnQI9RNzIfDsFxalBKj0u7Xf0c+5f/ntr4Hs9Q/Y7qthseNbUBZKU12KxNlmDcE7knLOui6NQdsUvFpuI/Rzgr')
'Success'
```
@ -135,7 +137,7 @@ Eventually, the client will be responsible (or at least more responsible) for me
```
>>> c2.get_remote_wallet()
Got latest walletState:
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE62uWympFofMnLmZSGGPTC5qctGKlWkan/DmOFLVZHktzqY9OndxhY3VCr5QBMXOGyn/Y321zNtL6YNfA+gs3Ov6qhzcneERHJM3ByySjMPwEds4NVDctKW4HAXggZIA1xhga1XlNggrBXlu09Sqro9zEbJdrBwJQI6BeuZHpH2eaJBDI73ljTWgtqoIeLg1WA')
WalletState(sequence=4, encrypted_wallet='czo4MTkyOjE2OjE66nridrsrXcL/DlcudUs7RaAIZ3jRYQJhaacRH3vPNx0TZqkJbDcjMiHbiHY6U2AVhoAsLPIf/zcU+uDTw4IRcOL9Gozupc8tCrIcgm/kwXjnQI9RNzIfDsFxalBKj0u7Xf0c+5f/ntr4Hs9Q/Y7qthseNbUBZKU12KxNlmDcE7knLOui6NQdsUvFpuI/Rzgr')
'Success'
>>> c2.get_preferences()
{'animal': 'horse', 'car': 'Audi'}
@ -147,11 +149,11 @@ Finally, the client with the merged wallet pushes it to the server, and the othe
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6ngb8TU1FyKgmzyHLQ8c30yOg/kVFNSDbtquXHKs16vEIQta3zrJLnGiY0WoiXx8Ul4uvYLK1riNaoo+OfZYtJjtpYLWf1oGdn0PDq0ZCHhK6GcX2Zbz/YQEdPcOvDeENjxZ4Pq2qoZYSDcPvwOgbvO2FSOK27OhCWHCA/9LbzAu6Suq6RS3i2p2TpmUHtz2H')
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE68NAahtUE4gg2M6Fam/E3brb4sv1TzcXJLvGRh4CY4416haOF1lxmKSdrvIPpOBvpNPS0B5qCbmpaKQ8Pm/WRCLj1yYUDVKgSZx0ru7AJBHiBLtpKA99Ia7XlWl129p6WtjJkbOoW8Ya+PEii72g4nrtM+j40Xe9UbVI463tlKYaRvmKr/BcoFGMJSB10Whh8')
'Success'
>>> c1.get_remote_wallet()
Got latest walletState:
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE6ngb8TU1FyKgmzyHLQ8c30yOg/kVFNSDbtquXHKs16vEIQta3zrJLnGiY0WoiXx8Ul4uvYLK1riNaoo+OfZYtJjtpYLWf1oGdn0PDq0ZCHhK6GcX2Zbz/YQEdPcOvDeENjxZ4Pq2qoZYSDcPvwOgbvO2FSOK27OhCWHCA/9LbzAu6Suq6RS3i2p2TpmUHtz2H')
WalletState(sequence=5, encrypted_wallet='czo4MTkyOjE2OjE68NAahtUE4gg2M6Fam/E3brb4sv1TzcXJLvGRh4CY4416haOF1lxmKSdrvIPpOBvpNPS0B5qCbmpaKQ8Pm/WRCLj1yYUDVKgSZx0ru7AJBHiBLtpKA99Ia7XlWl129p6WtjJkbOoW8Ya+PEii72g4nrtM+j40Xe9UbVI463tlKYaRvmKr/BcoFGMJSB10Whh8')
'Success'
>>> c1.get_preferences()
{'animal': 'horse', 'car': 'Audi'}
@ -182,12 +184,12 @@ We try to POST both of them to the server, but the second one fails because of t
>>> c2.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6MnLcl2+VTv8B9MIKJjpwptjF8Ws6NfhFkFBnsTDy8arv7akMSV/jojkvz2bJzOjX+iAKiY0+FKgD2akONsUnQqF95pnbr+TPnpbFxS4TLFUWxbpJMm7+r3FZiOauMZ6ewBfBq3vzI2UA2o3RrSxzucKZ6ZcgZqJsKCnk+rCj/ADmrUJb01kwB6WDATcMlG5A')
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6sh95Bt0OfcDY3QwUWaPgPWD1WPYCkN2yg1+XLD/5puONhNyjzVAnhINqVvPy52pxfkVgkIScLacMQFq4W19d+SC5LConu+fPchBzYj14Wvc3/IEQiQIxbmkv6N9USvYsjAzjGqK7szistRJY4MHC4/wRbWRprfIE7BFcDaisFSe18mRs8D2KlhEzjNJu+X8+')
'Success'
>>> c1.update_remote_wallet()
Wallet state out of date. Getting updated wallet state. Try posting again after this.
Got new walletState:
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6MnLcl2+VTv8B9MIKJjpwptjF8Ws6NfhFkFBnsTDy8arv7akMSV/jojkvz2bJzOjX+iAKiY0+FKgD2akONsUnQqF95pnbr+TPnpbFxS4TLFUWxbpJMm7+r3FZiOauMZ6ewBfBq3vzI2UA2o3RrSxzucKZ6ZcgZqJsKCnk+rCj/ADmrUJb01kwB6WDATcMlG5A')
WalletState(sequence=6, encrypted_wallet='czo4MTkyOjE2OjE6sh95Bt0OfcDY3QwUWaPgPWD1WPYCkN2yg1+XLD/5puONhNyjzVAnhINqVvPy52pxfkVgkIScLacMQFq4W19d+SC5LConu+fPchBzYj14Wvc3/IEQiQIxbmkv6N9USvYsjAzjGqK7szistRJY4MHC4/wRbWRprfIE7BFcDaisFSe18mRs8D2KlhEzjNJu+X8+')
'Success'
>>> c1.get_preferences()
{'animal': 'beaver', 'car': 'Toyota'}
@ -199,6 +201,6 @@ Now that the merge is complete, the client can make a second POST request contai
>>> c1.update_remote_wallet()
Successfully updated wallet state on server
Got new walletState:
WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE6uexO9yl0JVsKFo6WeJGOsJ/sm1RJPc+NwLxniaE744lVEihK2HyNxDVbcAFEMxn/vKXgFKtzLV/D7eAzeGrSIyQR5v3YeZrTWPcRzK79rJgHzjcZpjKpytcDMZp2lB5cRHkNg7u8qAa2DnbebMXU0CKblTL++IIteU+CzyuTdW1Uoj4cEOsy6G8HwrZc5drf')
WalletState(sequence=7, encrypted_wallet='czo4MTkyOjE2OjE68J19IGGfoiRDm15Nb1sTj5yP9Mc3jpAeYarh206kLXKMKLKCIahmhLDMqBCXgwDe098uaIqB6IwKDfXbCVJHhWfqzu/5GoWPK1QZjhCu0rGxteFv4Tio0IYGg8CUYCvOhpQA319SXEf4sF9cyC32VwlL6qkJ2TzWTu9bTGUfZRGV3q9Rt9oL4OQHxuNIPEiE')
'Success'
```

View file

@ -3,12 +3,16 @@
# NOTE - delete the database before running this, or else you'll get an error for registering. also we want the wallet to start empty
# NOTE - in the SDK, create wallets called "test_wallet_1" and "test_wallet_2"
import time
from test_client import LBRYSDK
# reset all of the preferences so we can run our example
for wallet in ['test_wallet_1', 'test_wallet_2']:
for pref_key in ['car', 'animal']:
LBRYSDK.set_preference(wallet, pref_key, '')
# Make sure the next preference changes have a later timestamp!
time.sleep(3)
def code_block(code):
print ("```")
for line in code.strip().split('\n'):
@ -29,12 +33,14 @@ A couple example flows so it's clear how it works. We're assuming that we're sta
print("""## Initial setup and account recovery
Set up a client for each wallet, but with the same sync account (which won't exist on the server yet). This will simulate clients on two different computers.
For this example we will be working with a locally running server so that we don't care about the data. If you want to communicate with `dev.lbry.id`, simply omit the `local=True`.
""")
code_block("""
from test_client import Client
c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1')
c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2')
c1 = Client("joe2@example.com", "123abc2", 'test_wallet_1', local=True)
c2 = Client("joe2@example.com", "123abc2", 'test_wallet_2', local=True)
""")
print("""
@ -155,7 +161,6 @@ c1.get_preferences()
""")
# Make sure the next preference changes have a later timestamp!
import time
time.sleep(3)
print("""

View file

@ -58,32 +58,34 @@ class LBRYSDK():
return response.json()['result']
class WalletSync():
def __init__(self, local):
if local:
BASE_URL = 'http://localhost:8090'
AUTH_URL = BASE_URL + '/auth/full'
REGISTER_URL = BASE_URL + '/signup'
WALLET_URL = BASE_URL + '/wallet'
else:
BASE_URL = 'https://dev.lbry.id:8091'
self.AUTH_URL = BASE_URL + '/auth/full'
self.REGISTER_URL = BASE_URL + '/signup'
self.WALLET_URL = BASE_URL + '/wallet'
@classmethod
def register(cls, email, password):
def register(self, email, password):
body = json.dumps({
'email': email,
'password': password,
})
response = requests.post(cls.REGISTER_URL, body)
response = requests.post(self.REGISTER_URL, body)
if response.status_code != 201:
print ('Error', response.status_code)
print (response.content)
return False
return True
@classmethod
def get_auth_token(cls, email, password, device_id):
def get_auth_token(self, email, password, device_id):
body = json.dumps({
'email': email,
'password': password,
'deviceId': device_id,
})
response = requests.post(cls.AUTH_URL, body)
response = requests.post(self.AUTH_URL, body)
if response.status_code != 200:
print ('Error', response.status_code)
print (response.content)
@ -91,12 +93,11 @@ class WalletSync():
return response.json()['token']
@classmethod
def get_wallet(cls, token):
def get_wallet(self, token):
params = {
'token': token,
}
response = requests.get(cls.WALLET_URL, params=params)
response = requests.get(self.WALLET_URL, params=params)
# TODO check response version on client side now
if response.status_code == 404:
@ -116,8 +117,7 @@ class WalletSync():
hmac = response.json()['hmac']
return wallet_state, hmac
@classmethod
def update_wallet(cls, wallet_state, hmac, token):
def update_wallet(self, wallet_state, hmac, token):
body = json.dumps({
'version': CURRENT_VERSION,
'token': token,
@ -126,7 +126,7 @@ class WalletSync():
"hmac": hmac,
})
response = requests.post(cls.WALLET_URL, body)
response = requests.post(self.WALLET_URL, body)
# TODO check that response.json().version == CURRENT_VERSION
@ -188,7 +188,7 @@ class Client():
return True
def __init__(self, email, root_password, wallet_id='default_wallet'):
def __init__(self, email, root_password, wallet_id='default_wallet', local=False):
# Represents normal client behavior (though a real client will of course save device id)
self.device_id = str(uuid.uuid4())
@ -200,6 +200,8 @@ class Client():
self.root_password = root_password
self.wallet_id = wallet_id
self.wallet_sync_api = WalletSync(local=local)
# TODO - This does not deal with the question of tying accounts to wallets.
# Does a new wallet state mean a we're creating a new account? What happens
# if we create a new wallet state tied to an existing account? Do we merge it
@ -243,7 +245,7 @@ class Client():
)
def register(self):
success = WalletSync.register(
success = self.wallet_sync_api.register(
self.email,
derive_login_password(self.root_password),
)
@ -251,7 +253,7 @@ class Client():
print ("Registered")
def get_auth_token(self):
token = WalletSync.get_auth_token(
token = self.wallet_sync_api.get_auth_token(
self.email,
derive_login_password(self.root_password),
self.device_id,
@ -270,7 +272,7 @@ class Client():
# Returns: status
def get_remote_wallet(self):
new_wallet_state, hmac = WalletSync.get_wallet(self.auth_token)
new_wallet_state, hmac = self.wallet_sync_api.get_wallet(self.auth_token)
if not new_wallet_state:
# Wallet not found, but this is not an error
@ -315,7 +317,7 @@ class Client():
hmac = create_hmac(submitted_wallet_state, hmac_key)
# Submit our wallet, get the latest wallet back as a response
new_wallet_state, new_hmac, conflict = WalletSync.update_wallet(submitted_wallet_state, hmac, self.auth_token)
new_wallet_state, new_hmac, conflict = self.wallet_sync_api.update_wallet(submitted_wallet_state, hmac, self.auth_token)
# TODO - there's some code in common here with the get_remote_wallet function. factor it out.