2022-06-07 19:25:14 +02:00
# Generate the README since I want real behavior interspersed with comments
# Come to think of it, this is accidentally a pretty okay integration test for client and server
# NOTE - delete the database before running this, or else you'll get an error for registering. also we want the wallet to start empty
def code_block ( code ) :
print ( " ``` " )
for line in code . strip ( ) . split ( ' \n ' ) :
print ( " >>> " + line )
if ' = ' in line or " import " in line :
exec ( ' global c1, c2 \n ' + line )
else :
result = eval ( line )
if result is not None :
print ( repr ( result ) )
print ( " ``` " )
print ( """ # Test Client
A couple example flows so it ' s clear how it works.
""" )
print ( """ ## Initial setup and account recovery
Set up two clients with the same account ( which won ' t exist on the server yet).
""" )
code_block ( """
from test_client import Client
c1 = Client ( )
c2 = Client ( )
c1 . set_account ( " joe2@example.com " , " 123abc2 " )
c2 . set_account ( " joe2@example.com " , " 123abc2 " )
""" )
print ( """
Register the account on the server with one of the clients .
""" )
code_block ( """
c1 . register ( )
""" )
print ( """
Now that the account exists , grab an auth token with both clients .
""" )
code_block ( """
2022-06-08 00:24:01 +02:00
c1 . get_auth_token ( )
c2 . get_auth_token ( )
2022-06-07 19:25:14 +02:00
""" )
print ( """
## Syncing
2022-06-09 23:04:49 +02:00
Create a new wallet + metadata ( we ' ll wrap it in a struct we ' ll call ` WalletState ` in this client ) and POST them to the server . The metadata ( as of now ) in the walletstate is only ` sequence ` . This increments for every POSTed wallet . This is bookkeeping to prevent certain syncing errors .
2022-06-07 19:25:14 +02:00
2022-06-09 23:04:49 +02:00
Note that after POSTing , it says it " got " a new wallet . This is because the POST endpoint also returns the latest version . The purpose of this will be explained in " Conflicts " below .
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
c1 . new_wallet_state ( )
2022-06-11 03:07:55 +02:00
c1 . update_wallet ( )
2022-06-07 19:25:14 +02:00
""" )
print ( """
2022-06-09 23:04:49 +02:00
With the other client , GET it from the server . Note that both clients have the same data now .
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
2022-06-09 23:04:49 +02:00
c2 . get_wallet ( )
2022-06-07 19:25:14 +02:00
""" )
print ( """
## Updating
2022-06-09 23:04:49 +02:00
Push a new version , GET it with the other client . Even though we haven ' t edited the encrypted wallet yet, we can still increment the sequence number.
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
2022-06-11 03:07:55 +02:00
c2 . update_wallet ( )
2022-06-09 23:04:49 +02:00
c1 . get_wallet ( )
2022-06-07 19:25:14 +02:00
""" )
print ( """
## Wallet Changes
For demo purposes , this test client represents each change to the wallet by appending segments separated by ` : ` so that we can more easily follow the history . ( The real app will not actually edit the wallet in the form of an append log . )
""" )
code_block ( """
c1 . cur_encrypted_wallet ( )
c1 . change_encrypted_wallet ( )
c1 . cur_encrypted_wallet ( )
""" )
print ( """
The wallet is synced between the clients .
""" )
code_block ( """
2022-06-11 03:07:55 +02:00
c1 . update_wallet ( )
2022-06-09 23:04:49 +02:00
c2 . get_wallet ( )
2022-06-07 19:25:14 +02:00
c2 . cur_encrypted_wallet ( )
""" )
print ( """
## Merging Changes
Both clients create changes . They now have diverging wallets .
""" )
2022-06-09 23:04:49 +02:00
merge_base = c2 . cur_encrypted_wallet ( )
2022-06-07 19:25:14 +02:00
code_block ( """
c1 . change_encrypted_wallet ( )
c2 . change_encrypted_wallet ( )
c1 . cur_encrypted_wallet ( )
c2 . cur_encrypted_wallet ( )
""" )
print ( """
2022-06-09 23:04:49 +02:00
One client POSTs its change first .
""" )
2022-06-07 19:25:14 +02:00
2022-06-09 23:04:49 +02:00
code_block ( """
2022-06-11 03:07:55 +02:00
c1 . update_wallet ( )
2022-06-07 19:25:14 +02:00
""" )
2022-06-09 23:04:49 +02:00
print ( """
The other client pulls that change , and _merges_ those changes on top of the changes it had saved locally .
The _merge base_ that a given client uses is the last version that it successfully got from or POSTed to the server . You can see the merge base here : ` " %s " ` , the first part of the wallet which both clients had in common before the merge .
""" % merge_base)
2022-06-07 19:25:14 +02:00
code_block ( """
2022-06-09 23:04:49 +02:00
c2 . get_wallet ( )
2022-06-07 19:25:14 +02:00
c2 . cur_encrypted_wallet ( )
""" )
print ( """
2022-06-09 23:04:49 +02:00
Finally , the client with the merged wallet pushes it to the server , and the other client GETs the update .
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
2022-06-11 03:07:55 +02:00
c2 . update_wallet ( )
2022-06-09 23:04:49 +02:00
c1 . get_wallet ( )
2022-06-07 19:25:14 +02:00
c1 . cur_encrypted_wallet ( )
""" )
print ( """
## Conflicts
2022-06-09 23:04:49 +02:00
A client cannot POST if it is not up to date . It needs to merge in any new changes on the server before POSTing its own changes . For convenience , if a conflicting POST request is made , the server responds with the latest version of the wallet state ( just like a GET request ) . This way the client doesn ' t need to make a second request to perform the merge.
2022-06-07 19:25:14 +02:00
2022-06-09 23:04:49 +02:00
( If a non - conflicting POST request is made , it responds with the same wallet state that the client just POSTed , as it is now the server ' s current wallet state)
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
c2 . change_encrypted_wallet ( )
2022-06-11 03:07:55 +02:00
c2 . update_wallet ( )
2022-06-07 19:25:14 +02:00
c1 . change_encrypted_wallet ( )
2022-06-11 03:07:55 +02:00
c1 . update_wallet ( )
2022-06-07 19:25:14 +02:00
""" )
print ( """
2022-06-09 23:04:49 +02:00
Now the merge is complete , and the client can make a second POST request containing the merged wallet .
2022-06-07 19:25:14 +02:00
""" )
code_block ( """
2022-06-11 03:07:55 +02:00
c1 . update_wallet ( )
2022-06-07 19:25:14 +02:00
""" )