provide wormhole() as a function, rather than a class constructor

You must always provide a reactor= argument. In the future, omitting the
reactor= argument is how you ask for a blocking Wormhole.
This commit is contained in:
Brian Warner 2016-05-12 16:36:48 -07:00
parent d87aba40e4
commit 104ef44d53
5 changed files with 37 additions and 26 deletions

View File

@ -77,7 +77,7 @@ before being closed.
To make it easier to call `close()`, the blocking Wormhole objects can be
used as a context manager. Just put your code in the body of a `with
Wormhole(ARGS) as w:` statement, and `close()` will automatically be called
wormhole(ARGS) as w:` statement, and `close()` will automatically be called
when the block exits (either successfully or due to an exception).
## Examples
@ -85,10 +85,10 @@ when the block exits (either successfully or due to an exception).
The synchronous+blocking flow looks like this:
```python
from wormhole.blocking.transcribe import Wormhole
from wormhole.blocking.transcribe import wormhole
from wormhole.public_relay import RENDEZVOUS_RELAY
mydata = b"initiator's data"
with Wormhole(u"appid", RENDEZVOUS_RELAY) as i:
with wormhole(u"appid", RENDEZVOUS_RELAY) as i:
code = i.get_code()
print("Invitation Code: %s" % code)
i.send(mydata)
@ -98,11 +98,11 @@ with Wormhole(u"appid", RENDEZVOUS_RELAY) as i:
```python
import sys
from wormhole.blocking.transcribe import Wormhole
from wormhole.blocking.transcribe import wormhole
from wormhole.public_relay import RENDEZVOUS_RELAY
mydata = b"receiver's data"
code = sys.argv[1]
with Wormhole(u"appid", RENDEZVOUS_RELAY) as r:
with wormhole(u"appid", RENDEZVOUS_RELAY) as r:
r.set_code(code)
r.send(mydata)
theirdata = r.get()
@ -116,9 +116,9 @@ The Twisted-friendly flow looks like this:
```python
from twisted.internet import reactor
from wormhole.public_relay import RENDEZVOUS_RELAY
from wormhole.twisted.transcribe import Wormhole
from wormhole.twisted.transcribe import wormhole
outbound_message = b"outbound data"
w1 = Wormhole(u"appid", RENDEZVOUS_RELAY)
w1 = wormhole(u"appid", RENDEZVOUS_RELAY, reactor)
d = w1.get_code()
def _got_code(code):
print "Invitation Code:", code
@ -136,7 +136,7 @@ reactor.run()
On the other side, you call `set_code()` instead of waiting for `get_code()`:
```python
w2 = Wormhole(u"appid", RENDEZVOUS_RELAY)
w2 = wormhole(u"appid", RENDEZVOUS_RELAY, reactor)
w2.set_code(code)
d = w2.send(my_message)
...
@ -253,9 +253,8 @@ You may not be able to hold the Wormhole 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 = w.serialize()`, which will return a printable
bytestring (the JSON-encoding of a small dictionary). To restore, use the
`from_serialized(data)` classmethod (e.g. `w =
Wormhole.from_serialized(data)`).
bytestring (the JSON-encoding of a small dictionary). To restore, use `w =
wormhole_from_serialized(data, reactor)`.
There is exactly one point at which you can serialize the wormhole: *after*
establishing the invitation code, but before waiting for `get_verifier()` or

View File

@ -3,7 +3,7 @@ import os, sys, json, binascii, six, tempfile, zipfile
from tqdm import tqdm
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue
from ..twisted.transcribe import Wormhole
from ..twisted.transcribe import wormhole
from ..twisted.transit import TransitReceiver
from ..errors import TransferError
@ -45,9 +45,8 @@ class TwistedReceiver:
# can lazy-provide an endpoint, and overlap the startup process
# with the user handing off the wormhole code
yield tor_manager.start()
w = Wormhole(APPID, self.args.relay_url, tor_manager,
timing=self.args.timing,
reactor=self._reactor)
w = wormhole(APPID, self.args.relay_url, self._reactor,
tor_manager, timing=self.args.timing)
# I wanted to do this instead:
#
# try:

View File

@ -5,7 +5,7 @@ from twisted.protocols import basic
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue
from ..errors import TransferError
from ..twisted.transcribe import Wormhole
from ..twisted.transcribe import wormhole
from ..twisted.transit import TransitSender
APPID = u"lothar.com/wormhole/text-or-file-xfer"
@ -49,8 +49,8 @@ def send(args, reactor=reactor):
# user handing off the wormhole code
yield tor_manager.start()
w = Wormhole(APPID, args.relay_url, tor_manager, timing=args.timing,
reactor=reactor)
w = wormhole(APPID, args.relay_url, reactor, tor_manager,
timing=args.timing)
d = _send(reactor, w, args, phase1, fd_to_send, tor_manager)
d.addBoth(w.close)

View File

@ -1,12 +1,17 @@
from __future__ import print_function
import json
from twisted.trial import unittest
from twisted.internet import reactor
from twisted.internet.defer import gatherResults, inlineCallbacks
from ..twisted.transcribe import Wormhole, UsageError, WrongPasswordError
from ..twisted.transcribe import (wormhole, wormhole_from_serialized,
UsageError, WrongPasswordError)
from .common import ServerBase
APPID = u"appid"
def Wormhole(appid, relayurl):
return wormhole(appid, relayurl, reactor)
class Basic(ServerBase, unittest.TestCase):
def doBoth(self, d1, d2):
@ -220,7 +225,7 @@ class Basic(ServerBase, unittest.TestCase):
unpacked = json.loads(s) # this is supposed to be JSON
self.assertEqual(type(unpacked), dict)
self.new_w1 = Wormhole.from_serialized(s)
self.new_w1 = wormhole_from_serialized(s, reactor)
yield self.doBoth(self.new_w1.send(b"data1"), w2.send(b"data2"))
dl = yield self.doBoth(self.new_w1.get(), w2.get())
(dataX, dataY) = dl

View File

@ -2,7 +2,7 @@ from __future__ import print_function
import os, sys, json, re, unicodedata
from six.moves.urllib_parse import urlparse
from binascii import hexlify, unhexlify
from twisted.internet import reactor, defer, endpoints, error
from twisted.internet import defer, endpoints, error
from twisted.internet.threads import deferToThread, blockingCallFromThread
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.python import log
@ -53,13 +53,13 @@ class WSFactory(websocket.WebSocketClientFactory):
proto.wormhole_open = False
return proto
class Wormhole:
class _Wormhole:
motd_displayed = False
version_warning_displayed = False
_send_confirm = True
def __init__(self, appid, relay_url, tor_manager=None, timing=None,
reactor=reactor):
def __init__(self, appid, relay_url, reactor,
tor_manager=None, timing=None):
if not isinstance(appid, type(u"")): raise TypeError(type(appid))
if not isinstance(relay_url, type(u"")):
raise TypeError(type(relay_url))
@ -351,9 +351,9 @@ class Wormhole:
# entry point 3: resume a previously-serialized session
@classmethod
def from_serialized(klass, data):
def from_serialized(klass, data, reactor):
d = json.loads(data)
self = klass(d["appid"], d["relay_url"])
self = klass(d["appid"], d["relay_url"], reactor)
self._side = d["side"]
self._channelid = d["channelid"]
self._set_code(d["code"])
@ -556,3 +556,11 @@ class Wormhole:
def _ws_handle_deallocated(self, msg):
self._deallocated_status = msg["status"]
self._wakeup()
def wormhole(appid, relay_url, reactor, tor_manager=None, timing=None):
w = _Wormhole(appid, relay_url, reactor, tor_manager, timing)
return w
def wormhole_from_serialized(data, reactor):
w = _Wormhole.from_serialized(data, reactor)
return w