diff --git a/docs/api.md b/docs/api.md index 53d7079..2efb436 100644 --- a/docs/api.md +++ b/docs/api.md @@ -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 diff --git a/src/wormhole/cli/cmd_receive.py b/src/wormhole/cli/cmd_receive.py index b39e3c6..5d308a3 100644 --- a/src/wormhole/cli/cmd_receive.py +++ b/src/wormhole/cli/cmd_receive.py @@ -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: diff --git a/src/wormhole/cli/cmd_send.py b/src/wormhole/cli/cmd_send.py index cdc5cec..8ad6973 100644 --- a/src/wormhole/cli/cmd_send.py +++ b/src/wormhole/cli/cmd_send.py @@ -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) diff --git a/src/wormhole/test/test_twisted.py b/src/wormhole/test/test_twisted.py index aa1c38d..da87c97 100644 --- a/src/wormhole/test/test_twisted.py +++ b/src/wormhole/test/test_twisted.py @@ -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 diff --git a/src/wormhole/twisted/transcribe.py b/src/wormhole/twisted/transcribe.py index 8b8fc47..248d1b9 100644 --- a/src/wormhole/twisted/transcribe.py +++ b/src/wormhole/twisted/transcribe.py @@ -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