start on sample clients
This commit is contained in:
		
							parent
							
								
									1b6668ff0a
								
							
						
					
					
						commit
						84852f26f5
					
				
							
								
								
									
										45
									
								
								docs/api.md
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								docs/api.md
									
									
									
									
									
								
							|  | @ -88,3 +88,48 @@ thousands of concurrent sessions. | |||
| The library uses a baked-in rendezvous server hostname. This must be the same | ||||
| for both clients. To use a different hostname provide it as the `rendezvous=` | ||||
| argument to the `Initiator`/`Receiver` constructor. | ||||
| 
 | ||||
| ## Polling and Shutdown | ||||
| 
 | ||||
| The reactor-based (Twisted-style) forms of these objects need to establish | ||||
| TCP connections, re-establish them if they are lost, and sometimes (for | ||||
| transports that don't support long-running connections) poll for new | ||||
| messages. They may also time out eventually. Longer delays mean less network | ||||
| traffic, but higher latency. | ||||
| 
 | ||||
| These timers should be matched to the expectations, and expected behavior, of | ||||
| your users. In a file-transfer application, where the users are sitting next | ||||
| to each other, it is appropriate to poll very frequently (perhaps every | ||||
| 500ms) for a few minutes, then give up. In an email-like messaging program | ||||
| where the introduction is establishing a long-term relationship, and the | ||||
| program can store any outgoing messages until the connection is established, | ||||
| it is probably better to poll once a minute for the first few minutes, then | ||||
| back off to once an hour, and not give up for several days. | ||||
| 
 | ||||
| The `schedule=` constructor argument establishes the polling schedule. It | ||||
| should contain a sorted list of (when, interval) tuples (both floats). At | ||||
| `when` seconds after the first `start()` call, the polling interval will be | ||||
| set to `interval`. | ||||
| 
 | ||||
| The `timeout=` argument provides a hard timeout. After this many seconds, the | ||||
| sync will be abandoned, and all callbacks will errback with a TimeoutError. | ||||
| 
 | ||||
| Both have defaults suitable for face-to-face realtime setup environments. | ||||
| 
 | ||||
| ## Serialization | ||||
| 
 | ||||
| You may not be able to hold the Initiator/Receiver object in memory for the | ||||
| whole sync process: maybe you allow it to wait for several days, but the | ||||
| program will be restarted during that time. To support this, you can persist | ||||
| the state of the object by calling `data = i.serialize()`, which will return | ||||
| a printable bytestring (the JSON-encoding of a small dictionary). To restore, | ||||
| call `Initiator.from_serialized(data)`. | ||||
| 
 | ||||
| Note that callbacks are not serialized: they must be restored after | ||||
| deserialization. | ||||
| 
 | ||||
| ## Detailed Example | ||||
| 
 | ||||
| ```python | ||||
| 
 | ||||
| ``` | ||||
|  |  | |||
							
								
								
									
										23
									
								
								src/wormhole/receive_file.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/wormhole/receive_file.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| 
 | ||||
| import sys, json | ||||
| from binascii import unhexlify | ||||
| from nacl.secret import SecretBox | ||||
| from nacl import utils | ||||
| from . import api | ||||
| 
 | ||||
| APPID = "lothar.com/wormhole/file-xfer" | ||||
| RELAY = "example.com" | ||||
| 
 | ||||
| # we're receiving | ||||
| code = sys.argv[1] | ||||
| blob = b"" | ||||
| r = api.Receiver(APPID, blob, code) | ||||
| them_bytes = r.finish() | ||||
| them_d = json.loads(them_bytes.decode("utf-8")) | ||||
| print("them: %r" % (them_d,)) | ||||
| xfer_key = unhexlify(them_d["xfer_key"].encode("ascii")) | ||||
| filename = them_d["filename"] # unicode | ||||
| filesize = them_d["filesize"] | ||||
| relay = them_d["relay"].encode("ascii") | ||||
| 
 | ||||
| # now receive the rest of the owl | ||||
							
								
								
									
										14
									
								
								src/wormhole/receive_text.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/wormhole/receive_text.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| 
 | ||||
| import sys, json | ||||
| from . import api | ||||
| 
 | ||||
| APPID = "lothar.com/wormhole/text-xfer" | ||||
| RELAY = "example.com" | ||||
| 
 | ||||
| # we're receiving | ||||
| code = sys.argv[1] | ||||
| blob = b"" | ||||
| r = api.Receiver(APPID, blob, code) | ||||
| them_bytes = r.finish() | ||||
| them_d = json.loads(them_bytes.decode("utf-8")) | ||||
| print(them_d["message"]) | ||||
							
								
								
									
										31
									
								
								src/wormhole/send_file.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/wormhole/send_file.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| 
 | ||||
| import os, sys, json | ||||
| from binascii import hexlify | ||||
| from nacl.secret import SecretBox | ||||
| from nacl import utils | ||||
| from . import api | ||||
| 
 | ||||
| APPID = "lothar.com/wormhole/file-xfer" | ||||
| RELAY = "example.com" | ||||
| 
 | ||||
| # we're sending | ||||
| filename = sys.argv[1] | ||||
| assert os.path.isfile(filename) | ||||
| xfer_key = utils.random(SecretBox.KEY_SIZE) | ||||
| blob = json.dumps({"xfer_key": hexlify(xfer_key), | ||||
|                    "filename": os.path.basename(filename), | ||||
|                    "filesize": os.stat(filename).st_size, | ||||
|                    "relay": RELAY, | ||||
|                    }).encode("utf-8") | ||||
| i = api.Initiator(APPID, blob) | ||||
| code = i.start() | ||||
| print("Wormhole code is '%s'" % code) | ||||
| print("On the other computer, please run:") | ||||
| print() | ||||
| print(" wormhole-receive-file %s" % code) | ||||
| print() | ||||
| them_bytes = i.finish() | ||||
| them_d = json.loads(them_bytes.decode("utf-8")) | ||||
| print("them: %r" % (them_d,)) | ||||
| 
 | ||||
| # now draw the rest of the owl | ||||
							
								
								
									
										24
									
								
								src/wormhole/send_text.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/wormhole/send_text.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| 
 | ||||
| import sys, json | ||||
| from nacl.secret import SecretBox | ||||
| from nacl import utils | ||||
| from . import api | ||||
| 
 | ||||
| APPID = "lothar.com/wormhole/text-xfer" | ||||
| RELAY = "example.com" | ||||
| 
 | ||||
| # we're sending | ||||
| message = sys.argv[1] | ||||
| xfer_key = utils.random(SecretBox.KEY_SIZE) | ||||
| blob = json.dumps({"message": message, | ||||
|                    }).encode("utf-8") | ||||
| i = api.Initiator(APPID, blob) | ||||
| code = i.start() | ||||
| print("Wormhole code is '%s'" % code) | ||||
| print("On the other computer, please run:") | ||||
| print() | ||||
| print(" wormhole-receive-text %s" % code) | ||||
| print() | ||||
| them_bytes = i.finish() | ||||
| them_d = json.loads(them_bytes.decode("utf-8")) | ||||
| print("them: %r" % (them_d,)) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user