diff --git a/src/wormhole/_boss.py b/src/wormhole/_boss.py index 15a86c5..22f28eb 100644 --- a/src/wormhole/_boss.py +++ b/src/wormhole/_boss.py @@ -1,4 +1,6 @@ from zope.interface import implementer +from attr import attrs, attrib +from attr.validators import provides, instance_of from automat import MethodicalMachine from . import _interfaces from ._mailbox import Mailbox @@ -13,7 +15,7 @@ from .util import bytes_to_dict @attrs @implementer(_interfaces.IBoss) -class Boss: +class Boss(object): _side = attrib(validator=instance_of(type(u""))) _url = attrib(validator=instance_of(type(u""))) _appid = attrib(validator=instance_of(type(u""))) diff --git a/src/wormhole/wormhole.py b/src/wormhole/wormhole.py index 23a6c6a..5351bb0 100644 --- a/src/wormhole/wormhole.py +++ b/src/wormhole/wormhole.py @@ -1,10 +1,54 @@ from __future__ import print_function, absolute_import, unicode_literals import sys +from attr import attrs, attrib from .timing import DebugTiming from .journal import ImmediateJournal from ._boss import Boss -class _Wormhole(object): +# We can provide different APIs to different apps: +# * Deferreds +# w.when_got_code().addCallback(print_code) +# w.send(data) +# w.receive().addCallback(got_data) +# w.close().addCallback(closed) + +# * delegate callbacks (better for journaled environments) +# w = wormhole(delegate=app) +# w.send(data) +# app.wormhole_got_code(code) +# app.wormhole_receive(data) +# w.close() +# app.wormhole_closed() +# +# * potential delegate options +# wormhole(delegate=app, delegate_prefix="wormhole_", +# delegate_args=(args, kwargs)) + +@attrs +class _DelegatedWormhole(object): + _delegate = attrib() + + def _set_boss(self, boss): + self._boss = boss + + # from above + def send(self, phase, plaintext): + self._boss.send(phase, plaintext) + def close(self): + self._boss.close() + + # from below + def got_code(self, code): + self._delegate.wormhole_got_code(code) + def got_verifier(self, verifier): + self._delegate.wormhole_got_verifier(verifier) + def received(self, phase, plaintext): + # TODO: deliver phases in order + self._delegate.wormhole_received(phase, plaintext) + def closed(self, result): + self._delegate.wormhole_closed(result) + +class _DeferredWormhole(object): def __init__(self): self._code = None self._code_observers = [] @@ -15,7 +59,6 @@ class _Wormhole(object): self._boss = boss # from above - def when_code(self): if self._code: return defer.succeed(self._code) @@ -53,58 +96,39 @@ class _Wormhole(object): def closed(self, result): print("closed", result) -def wormhole(appid, relay_url, reactor, - tor_manager=None, timing=None, - journal=None, - stderr=sys.stderr, - ): +def _wormhole(appid, relay_url, reactor, delegate=None, + tor_manager=None, timing=None, + journal=None, + stderr=sys.stderr, + ): timing = timing or DebugTiming() code_length = 2 side = bytes_to_hexstr(os.urandom(5)) journal = journal or ImmediateJournal() - w = _Wormhole() + if delegate: + w = _DelegatedWormhole(delegate) + else: + w = _DeferredWormhole() b = Boss(w, side, relay_url, appid, reactor, journal, timing) w._set_boss(b) # force allocate for now b.start() b.allocate(code_length) - w = _Wormhole(appid, relay_url, reactor, tor_manager, timing, stderr) - w._start() return w -#def wormhole_from_serialized(data, reactor, timing=None): -# timing = timing or DebugTiming() -# w = _Wormhole.from_serialized(data, reactor, timing) -# return w +def delegated_wormhole(appid, relay_url, reactor, delegate, + tor_manager=None, timing=None, + journal=None, + stderr=sys.stderr, + ): + assert delegate + return _wormhole(appid, relay_url, reactor, delegate, + tor_manager, timing, journal, stderr) - -# considerations for activity management: -# * websocket to server wants to be a t.a.i.ClientService -# * if Wormhole is a MultiService: -# * makes it easier to chain the ClientService to it -# * implies that nothing will happen before w.startService() -# * implies everything stops upon d=w.stopService() -# * if not: -# * - -class _JournaledWormhole(object): - def __init__(self, reactor, journal_manager, event_dispatcher, - event_dispatcher_args=()): - pass - -class _Wormhole(_JournaledWormhole): - # send events to self, deliver them via Deferreds - def __init__(self, reactor): - _JournaledWormhole.__init__(self, reactor, ImmediateJournal(), self) - -def wormhole2(reactor): - w = _Wormhole(reactor) - w.startService() - return w - -def journaled_from_data(state, reactor, journal, - event_handler, event_handler_args=()): - pass - -def journaled(reactor, journal, event_handler, event_handler_args=()): - pass +def deferred_wormhole(appid, relay_url, reactor, + tor_manager=None, timing=None, + journal=None, + stderr=sys.stderr, + ): + return _wormhole(appid, relay_url, reactor, delegate=None, + tor_manager, timing, journal, stderr)