add demo of twisted flow, update docs
python -m wormhole.twisted.demo send-text TEXT -> CODE python -m wormhole.twisted.demo receive-text CODE -> TEXT
This commit is contained in:
parent
25472423c6
commit
6ee09f5316
72
docs/api.md
72
docs/api.md
|
@ -50,39 +50,45 @@ theirdata = r.get_data(mydata)
|
||||||
print("Their data: %s" % theirdata.decode("ascii"))
|
print("Their data: %s" % theirdata.decode("ascii"))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Twisted (TODO)
|
## Twisted
|
||||||
|
|
||||||
The Twisted-friendly flow, which is not yet implemented, may look like this:
|
The Twisted-friendly flow looks like this:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from wormhole.transcribe import TwistedInitiator
|
from wormhole.public_relay import RENDEZVOUS_RELAY
|
||||||
data = b"initiator's data"
|
from wormhole.twisted.transcribe import SymmetricWormhole
|
||||||
ti = TwistedInitiator("appid", data, reactor)
|
outbound_message = b"outbound data"
|
||||||
ti.startService()
|
w1 = SymmetricWormhole("appid", RENDEZVOUS_RELAY)
|
||||||
d1 = ti.when_get_code()
|
d = w1.get_code()
|
||||||
d1.addCallback(lambda code: print("Invitation Code: %s" % code))
|
def _got_code(code):
|
||||||
d2 = ti.when_get_data()
|
print "Invitation Code:", code
|
||||||
d2.addCallback(lambda theirdata:
|
return w1.get_data(outbound_message)
|
||||||
print("Their data: %s" % theirdata.decode("ascii")))
|
d.addCallback(_got_code)
|
||||||
d2.addCallback(labmda _: reactor.stop())
|
def _got_data(inbound_message):
|
||||||
|
print "Inbound message:", inbound_message
|
||||||
|
d.addCallback(_got_data)
|
||||||
|
d.addBoth(lambda _: reactor.stop())
|
||||||
reactor.run()
|
reactor.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On the other side, you call `set_code()` instead of waiting for `get_code()`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twisted.internet import reactor
|
w2 = SymmetricWormhole("appid", RENDEZVOUS_RELAY)
|
||||||
from wormhole.transcribe import TwistedReceiver
|
w2.set_code(code)
|
||||||
data = b"receiver's data"
|
d = w2.get_data(my_message)
|
||||||
code = sys.argv[1]
|
|
||||||
tr = TwistedReceiver("appid", code, data, reactor)
|
|
||||||
tr.startService()
|
|
||||||
d = tr.when_get_data()
|
|
||||||
d.addCallback(lambda theirdata:
|
|
||||||
print("Their data: %s" % theirdata.decode("ascii")))
|
|
||||||
d.addCallback(lambda _: reactor.stop())
|
|
||||||
reactor.run()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can call `d=w.get_verifier()` before `get_data()`: this will perform the
|
||||||
|
first half of the PAKE negotiation, then fire the Deferred with a verifier
|
||||||
|
object (bytes) which can be converted into a printable representation and
|
||||||
|
manually compared. When the users are convinced that `get_verifier()` from
|
||||||
|
both sides are the same, call `d=get_data()` to continue the transfer. If you
|
||||||
|
call `get_data()` first, it will perform the complete transfer without
|
||||||
|
pausing.
|
||||||
|
|
||||||
|
|
||||||
## Application Identifier
|
## Application Identifier
|
||||||
|
|
||||||
Applications using this library must provide an "application identifier", a
|
Applications using this library must provide an "application identifier", a
|
||||||
|
@ -135,17 +141,27 @@ sync will be abandoned, and all callbacks will errback with a TimeoutError.
|
||||||
|
|
||||||
Both have defaults suitable for face-to-face realtime setup environments.
|
Both have defaults suitable for face-to-face realtime setup environments.
|
||||||
|
|
||||||
## Serialization (TODO)
|
## Serialization
|
||||||
|
|
||||||
|
TODO: only the Twisted form supports serialization so far
|
||||||
|
|
||||||
You may not be able to hold the Initiator/Receiver object in memory for the
|
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
|
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
|
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
|
the state of the object by calling `data = w.serialize()`, which will return
|
||||||
a printable bytestring (the JSON-encoding of a small dictionary). To restore,
|
a printable bytestring (the JSON-encoding of a small dictionary). To restore,
|
||||||
call `Initiator.from_serialized(data)`.
|
use the `from_serialized(data)` classmethod (e.g. `w =
|
||||||
|
SymmetricWormhole.from_serialized(data)`).
|
||||||
|
|
||||||
Note that callbacks are not serialized: they must be restored after
|
There is exactly one point at which you can serialize the wormhole: *after*
|
||||||
deserialization.
|
establishing the invitation code, but before waiting for `get_verifier()` or
|
||||||
|
`get_data()`. If you are creating a new code, the correct time is during the
|
||||||
|
callback fired by `get_code()`. If you are accepting a pre-generated code,
|
||||||
|
the time is just after calling `set_code()`.
|
||||||
|
|
||||||
|
To properly checkpoint the process, you should store the first message
|
||||||
|
(returned by `start()`) next to the serialized wormhole instance, so you can
|
||||||
|
re-send it if necessary.
|
||||||
|
|
||||||
## Detailed Example
|
## Detailed Example
|
||||||
|
|
||||||
|
|
30
src/wormhole/twisted/demo.py
Normal file
30
src/wormhole/twisted/demo.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import sys
|
||||||
|
from twisted.internet import reactor
|
||||||
|
from .transcribe import SymmetricWormhole
|
||||||
|
from .. import public_relay
|
||||||
|
|
||||||
|
APPID = "lothar.com/wormhole/text-xfer"
|
||||||
|
|
||||||
|
w = SymmetricWormhole(APPID, public_relay.RENDEZVOUS_RELAY)
|
||||||
|
|
||||||
|
if sys.argv[1] == "send-text":
|
||||||
|
message = sys.argv[2]
|
||||||
|
d = w.get_code()
|
||||||
|
def _got_code(code):
|
||||||
|
print "code is:", code
|
||||||
|
return w.get_data(message)
|
||||||
|
d.addCallback(_got_code)
|
||||||
|
def _got_data(their_data):
|
||||||
|
print "ack:", their_data
|
||||||
|
d.addCallback(_got_data)
|
||||||
|
elif sys.argv[1] == "receive-text":
|
||||||
|
code = sys.argv[2]
|
||||||
|
w.set_code(code)
|
||||||
|
d = w.get_data("ok")
|
||||||
|
def _got_data(their_data):
|
||||||
|
print their_data
|
||||||
|
d.addCallback(_got_data)
|
||||||
|
else:
|
||||||
|
raise ValueError("bad command")
|
||||||
|
d.addCallback(lambda _: reactor.stop())
|
||||||
|
reactor.run()
|
Loading…
Reference in New Issue
Block a user