def test_errback(framework): f = txaio.create_future() exception = RuntimeError("it failed") errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) try: raise exception except: fail = txaio.create_failure() txaio.reject(f, fail) run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) assert exception == errors[0].value assert txaio.failure_traceback(errors[0]) is not None tb = txaio.failure_format_traceback(errors[0]) assert 'RuntimeError' in tb assert 'it failed' in tb assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed' assert 'it failed' in str(errors[0])
def test_add_and_subscribe(self): """ Create an application session that subscribes to some topic and add it to a router to run embedded. """ d = txaio.create_future() class TestSession(ApplicationSession): def onJoin(self, details): # noinspection PyUnusedLocal def on_event(*arg, **kwargs): pass d2 = self.subscribe(on_event, u'com.example.topic1') def ok(_): txaio.resolve(d, None) def error(err): txaio.reject(d, err) txaio.add_callbacks(d2, ok, error) session = TestSession(types.ComponentConfig(u'realm1')) self.session_factory.add(session) return d
def test_is_future_generic(): ''' Returning an immediate value from as_future ''' f = txaio.create_future('result') assert txaio.is_future(f)
def test_errback_reject_no_args(): """ txaio.reject() with no args """ f = txaio.create_future() exception = RuntimeError("it failed") errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) try: raise exception except: txaio.reject(f) run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) assert exception == errors[0].value tb = txaio.failure_format_traceback(errors[0]) assert 'RuntimeError' in tb assert 'it failed' in tb assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed' assert 'it failed' in str(errors[0])
def is_closed(self): if hasattr(self, '_wait_closed'): return self._wait_closed else: f = txaio.create_future() f.set_result(True) return f
def _unsubscribe(self, subscription): """ Called from :meth:`autobahn.wamp.protocol.Subscription.unsubscribe` """ assert(isinstance(subscription, Subscription)) assert subscription.active assert(subscription.id in self._subscriptions) assert(subscription in self._subscriptions[subscription.id]) if not self._transport: raise exception.TransportLost() # remove handler subscription and mark as inactive self._subscriptions[subscription.id].remove(subscription) subscription.active = False # number of handler subscriptions left .. scount = len(self._subscriptions[subscription.id]) if scount == 0: # if the last handler was removed, unsubscribe from broker .. request_id = util.id() on_reply = txaio.create_future() self._unsubscribe_reqs[request_id] = UnsubscribeRequest(request_id, on_reply, subscription.id) msg = message.Unsubscribe(request_id, subscription.id) self._transport.send(msg) return on_reply else: # there are still handlers active on the subscription! return txaio.create_future_success(scount)
def _unsubscribe(self, subscription): """ Called from :meth:`autobahn.wamp.protocol.Subscription.unsubscribe` """ assert (isinstance(subscription, Subscription)) assert subscription.active assert (subscription.id in self._subscriptions) assert (subscription in self._subscriptions[subscription.id]) if not self._transport: raise exception.TransportLost() # remove handler subscription and mark as inactive self._subscriptions[subscription.id].remove(subscription) subscription.active = False # number of handler subscriptions left .. scount = len(self._subscriptions[subscription.id]) if scount == 0: # if the last handler was removed, unsubscribe from broker .. request_id = self._request_id_gen.next() on_reply = txaio.create_future() self._unsubscribe_reqs[request_id] = UnsubscribeRequest( request_id, on_reply, subscription.id) msg = message.Unsubscribe(request_id, subscription.id) self._transport.send(msg) return on_reply else: # there are still handlers active on the subscription! return txaio.create_future_success(scount)
def test_is_future_generic(framework): ''' Returning an immediate value from as_future ''' f = txaio.create_future('result') assert txaio.is_future(f)
def test_errback_without_except(framework): ''' Create a failure without an except block ''' f = txaio.create_future() exception = RuntimeError("it failed") errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) fail = txaio.create_failure(exception) txaio.reject(f, fail) run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) tb = txaio.failure_format_traceback(errors[0]) assert 'RuntimeError' in tb assert 'it failed' in tb assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed' assert 'it failed' in str(errors[0])
def test_add_and_subscribe(self): """ Create an application session that subscribes to some topic and add it to a router to run embedded. """ d = txaio.create_future() class TestSession(ApplicationSession): def onJoin(self, details): d2 = self.subscribe(lambda: None, 'com.example.topic1') def ok(_): txaio.resolve(d, None) def error(err): txaio.reject(d, err) txaio.add_callbacks(d2, ok, error) session = TestSession(types.ComponentConfig('realm1')) self.session_factory.add(session, self.router, authrole='test_role') return d
def _subscribe(self, obj, fn, topic, options): request_id = self._request_id_gen.next() on_reply = txaio.create_future() handler_obj = Handler(fn, obj, None) self._subscribe_reqs[request_id] = SubscribeRequest(request_id, topic, on_reply, handler_obj) self._transport.send(AkSubscribe(request_id, topic, options)) return on_reply
def test_errback_cancel_exception(framework): ''' reject a future with a CancelledError ''' f = txaio.create_future() errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) txaio.cancel(f, msg="future cancelled") run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) tb = txaio.failure_format_traceback(errors[0]) assert 'CancelledError' in tb if txaio.using_asyncio and sys.version_info >= (3, 9): assert txaio.failure_message( errors[0]) == 'CancelledError: future cancelled' assert 'future cancelled' in str(errors[0]) else: assert txaio.failure_message(errors[0]) == 'CancelledError: '
def sign_challenge(data: bytes, signer_func: Callable): """ Sign the provided data using the provided signer. :param data: challenge to sign :param signer_func: The callable function to use for signing :returns: A Deferred/Future that resolves to the computed signature. :rtype: str """ # a raw byte string is signed, and the signature is also a raw byte string d1 = signer_func(data) # asyncio lacks callback chaining (and we cannot use co-routines, since we want # to support older Pythons), hence we need d2 d2 = txaio.create_future() def process(signature_raw): # convert the raw signature into a hex encode value (unicode string) signature_hex = binascii.b2a_hex(signature_raw).decode('ascii') # we return the concatenation of the signature and the message signed (96 bytes) data_hex = binascii.b2a_hex(data).decode('ascii') sig = signature_hex + data_hex txaio.resolve(d2, sig) txaio.add_callbacks(d1, process, None) return d2
def notify_connect_error(fail): chain_f = txaio.create_future() handler_f = self.fire('connectfailure', self, fail.value) txaio.add_callbacks(handler_f, lambda _: txaio.reject(chain_f, fail), lambda _: txaio.reject(chain_f, fail)) return chain_f
def test_add_and_subscribe(self): """ Create an application session that subscribes to some topic and add it to a router to run embedded. """ d = txaio.create_future() class TestSession(ApplicationSession): def onJoin(self, details): d2 = self.subscribe(lambda: None, u'com.example.topic1') def ok(_): txaio.resolve(d, None) def error(err): txaio.reject(d, err) txaio.add_callbacks(d2, ok, error) session = TestSession(types.ComponentConfig(u'realm1')) self.session_factory.add(session, authrole=u'test_role') return d
def test_create_error(framework): f = txaio.create_future(error=RuntimeError("test")) if txaio.using_twisted: assert f.called else: assert f.done() # cancel the error; we expected it txaio.add_callbacks(f, None, lambda _: None)
def connection_made(self, transport): self.transport = transport peer = transport.get_extra_info('peername') self.peer = peer2str(peer) self.log.debug('RawSocker Asyncio: Connection made with peer {peer}', peer=self.peer) self._buffer = b'' self._header = None self._wait_closed = txaio.create_future()
def test_create_error(): f = txaio.create_future(error=RuntimeError("test")) if txaio.using_twisted: assert f.called else: assert f.done() # cancel the error; we expected it txaio.add_callbacks(f, None, lambda _: None)
def on_connect(req): f = txaio.create_future() def cb(x): f = foo(42) f.add_callbacks(f, lambda v: values.append(v), None) return f txaio.add_callbacks(f, cb, None) return f
def test_errback_illegal_args(framework): ''' non-Exception/Failures should be rejected ''' f = txaio.create_future() try: txaio.reject(f, object()) assert "should have raised exception." except RuntimeError: pass
def notify_connect_error(fail): chain_f = txaio.create_future() # hmm, if connectfailure took a _Transport instead of # (or in addition to?) self it could .failed() the # transport and we could do away with the is_fatal # listener? handler_f = self.fire('connectfailure', self, fail.value) txaio.add_callbacks(handler_f, lambda _: txaio.reject(chain_f, fail), lambda _: txaio.reject(chain_f, fail)) return chain_f
def sign_challenge(self, session, challenge): """ Sign WAMP-cryptosign challenge. :param challenge: The WAMP-cryptosign challenge object for which a signature should be computed. :type challenge: instance of autobahn.wamp.types.Challenge :returns: A Deferred/Future that resolves to the computed signature. :rtype: str """ if not isinstance(challenge, Challenge): raise Exception( "challenge must be instance of autobahn.wamp.types.Challenge, not {}" .format(type(challenge))) if u'challenge' not in challenge.extra: raise Exception("missing challenge value in challenge.extra") # the challenge sent by the router (a 32 bytes random value) challenge_hex = challenge.extra[u'challenge'] # the challenge for WAMP-cryptosign is a 32 bytes random value in Hex encoding (that is, a unicode string) challenge_raw = binascii.a2b_hex(challenge_hex) # if the transport has a channel ID, the message to be signed by the client actually # is the XOR of the challenge and the channel ID channel_id_raw = session._transport.get_channel_id() if channel_id_raw: data = util.xor(challenge_raw, channel_id_raw) else: data = challenge_raw # a raw byte string is signed, and the signature is also a raw byte string d1 = self.sign(data) # asyncio lacks callback chaining (and we cannot use co-routines, since we want # to support older Pythons), hence we need d2 d2 = txaio.create_future() def process(signature_raw): # convert the raw signature into a hex encode value (unicode string) signature_hex = binascii.b2a_hex(signature_raw).decode('ascii') # we return the concatenation of the signature and the message signed (96 bytes) data_hex = binascii.b2a_hex(data).decode('ascii') sig = signature_hex + data_hex txaio.resolve(d2, sig) txaio.add_callbacks(d1, process, None) return d2
def _register(obj, fn, procedure, options): request_id = self._request_id_gen.next() on_reply = txaio.create_future() endpoint_obj = Endpoint(fn, obj, options.details_arg if options else None) self._register_reqs[request_id] = RegisterRequest(request_id, on_reply, procedure, endpoint_obj) if options: msg = message.Register(request_id, procedure, **options.message_attr()) else: msg = message.Register(request_id, procedure) self._transport.send(msg) return on_reply
def _subscribe(obj, fn, topic, options): request_id = self._request_id_gen.next() on_reply = txaio.create_future() handler_obj = Handler(fn, obj, options.details_arg if options else None) self._subscribe_reqs[request_id] = SubscribeRequest(request_id, on_reply, handler_obj) if options: msg = message.Subscribe(request_id, topic, **options.message_attr()) else: msg = message.Subscribe(request_id, topic) self._transport.send(msg) return on_reply
def _register(obj, fn, procedure, options): request_id = util.id() on_reply = txaio.create_future() endpoint_obj = Endpoint(fn, obj, options.details_arg if options else None) self._register_reqs[request_id] = RegisterRequest(request_id, on_reply, procedure, endpoint_obj) if options: msg = message.Register(request_id, procedure, **options.message_attr()) else: msg = message.Register(request_id, procedure) self._transport.send(msg) return on_reply
def test_callback(framework): f = txaio.create_future() results = [] def cb(f): results.append(f) txaio.add_callbacks(f, cb, None) txaio.resolve(f, "it worked") run_once() assert len(results) == 1 assert results[0] == "it worked"
def notify_connect_error(fail): chain_f = txaio.create_future() # hmm, if connectfailure took a _Transport instead of # (or in addition to?) self it could .failed() the # transport and we could do away with the is_fatal # listener? handler_f = self.fire('connectfailure', self, fail.value) txaio.add_callbacks( handler_f, lambda _: txaio.reject(chain_f, fail), lambda _: txaio.reject(chain_f, fail) ) return chain_f
def _subscribe(obj, fn, topic, options): request_id = util.id() on_reply = txaio.create_future() handler_obj = Handler(fn, obj, options.details_arg if options else None) self._subscribe_reqs[request_id] = SubscribeRequest(request_id, on_reply, handler_obj) if options: msg = message.Subscribe(request_id, topic, **options.message_attr()) else: msg = message.Subscribe(request_id, topic) self._transport.send(msg) return on_reply
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert (isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = self._request_id_gen.next() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): options = kwargs.pop('options') msg = message.Call(request_id, procedure, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Call(request_id, procedure, args=args, kwargs=kwargs) # FIXME # def canceller(_d): # cancel_msg = message.Cancel(request) # self._transport.send(cancel_msg) # d = Deferred(canceller) on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, on_reply, options) try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except: if request_id in self._call_reqs: del self._call_reqs[request_id] raise return on_reply
def sign_challenge(self, session, challenge): """ Sign WAMP-cryptosign challenge. :param challenge: The WAMP-cryptosign challenge object for which a signature should be computed. :type challenge: instance of autobahn.wamp.types.Challenge :returns: A Deferred/Future that resolves to the computed signature. :rtype: str """ if not isinstance(challenge, Challenge): raise Exception("challenge must be instance of autobahn.wamp.types.Challenge, not {}".format(type(challenge))) if u'challenge' not in challenge.extra: raise Exception("missing challenge value in challenge.extra") # the challenge sent by the router (a 32 bytes random value) challenge_hex = challenge.extra[u'challenge'] # the challenge for WAMP-cryptosign is a 32 bytes random value in Hex encoding (that is, a unicode string) challenge_raw = binascii.a2b_hex(challenge_hex) # if the transport has a channel ID, the message to be signed by the client actually # is the XOR of the challenge and the channel ID channel_id_raw = session._transport.get_channel_id() if channel_id_raw: data = util.xor(challenge_raw, channel_id_raw) else: data = challenge_raw # a raw byte string is signed, and the signature is also a raw byte string d1 = self.sign(data) # asyncio lacks callback chaining (and we cannot use co-routines, since we want # to support older Pythons), hence we need d2 d2 = txaio.create_future() def process(signature_raw): # convert the raw signature into a hex encode value (unicode string) signature_hex = binascii.b2a_hex(signature_raw).decode('ascii') # we return the concatenation of the signature and the message signed (96 bytes) data_hex = binascii.b2a_hex(data).decode('ascii') sig = signature_hex + data_hex txaio.resolve(d2, sig) txaio.add_callbacks(d1, process, None) return d2
def publish(self, topic, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.IPublisher.publish` """ if six.PY2 and type(topic) == str: topic = six.u(topic) assert (type(topic) == six.text_type) if not self._transport: raise exception.TransportLost() request_id = self._request_id_gen.next() if 'options' in kwargs and isinstance(kwargs['options'], types.PublishOptions): options = kwargs.pop('options') msg = message.Publish(request_id, topic, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Publish(request_id, topic, args=args, kwargs=kwargs) if options and options.acknowledge: # only acknowledged publications expect a reply .. on_reply = txaio.create_future() self._publish_reqs[request_id] = PublishRequest( request_id, on_reply) else: on_reply = None try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._publish_reqs: del self._publish_reqs[request_id] raise e return on_reply
def test_explicit_reactor_future(framework): """ If we set an event-loop, Futures + Tasks should use it. """ pytest.importorskip('asyncio') if txaio.using_twisted: pytest.skip() with patch.object(txaio.config, 'loop') as fake_loop: f = txaio.create_future('result') f.add_done_callback(lambda _: None) assert len(fake_loop.method_calls) == 2 c = fake_loop.method_calls[1] assert c[0] == 'call_soon'
def test_explicit_reactor_future(): """ If we set an event-loop, Futures + Tasks should use it. """ pytest.importorskip('asyncio') if txaio.using_twisted: pytest.skip() with patch.object(txaio.config, 'loop') as fake_loop: f = txaio.create_future('result') f.add_done_callback(lambda _: None) assert len(fake_loop.method_calls) == 2 c = fake_loop.method_calls[1] assert c[0] == 'call_soon'
def test_add(self): """ Create an application session and add it to a router to run embedded. """ d = txaio.create_future() class TestSession(ApplicationSession): def onJoin(self, details): txaio.resolve(d, None) session = TestSession(types.ComponentConfig('realm1')) self.session_factory.add(session, self.router) return d
def test_add(self): """ Create an application session and add it to a router to run embedded. """ d = txaio.create_future() class TestSession(ApplicationSession): def onJoin(self, details): txaio.resolve(d, None) session = TestSession(types.ComponentConfig(u"realm1")) self.session_factory.add(session) return d
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert(isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): options = kwargs.pop('options') msg = message.Call(request_id, procedure, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Call(request_id, procedure, args=args, kwargs=kwargs) # FIXME # def canceller(_d): # cancel_msg = message.Cancel(request) # self._transport.send(cancel_msg) # d = Deferred(canceller) on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, on_reply, options) try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def connection_made(self, transport): # asyncio networking framework entry point, called by asyncio # when the connection is established (either a client or a server) self.log.debug('RawSocker Asyncio: Connection made with peer {peer}', peer=self.peer) self.transport = transport # determine preliminary transport details (what is know at this point) self._transport_details = create_transport_details( self.transport, self.is_server) # backward compatibility self.peer = self._transport_details.peer self._buffer = b'' self._header = None self._wait_closed = txaio.create_future()
def publish(self, topic, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.IPublisher.publish` """ if six.PY2 and type(topic) == str: topic = six.u(topic) assert(type(topic) == six.text_type) if not self._transport: raise exception.TransportLost() request_id = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.PublishOptions): options = kwargs.pop('options') msg = message.Publish(request_id, topic, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Publish(request_id, topic, args=args, kwargs=kwargs) if options and options.acknowledge: # only acknowledged publications expect a reply .. on_reply = txaio.create_future() self._publish_reqs[request_id] = PublishRequest(request_id, on_reply) else: on_reply = None try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._publish_reqs: del self._publish_reqs[request_id] raise e return on_reply
def call(self, procedure, *args, **kwargs): """ Reimplemented to support calls with custom options """ if not self._transport: raise exception.TransportLost() request_id = random.randint(0, 9007199254740992) on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, procedure, on_reply, {}) try: self._transport.send(AkCall(request_id, procedure, args, kwargs)) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def _unregister(self, registration): """ Called from :meth:`autobahn.wamp.protocol.Registration.unregister` """ assert(isinstance(registration, Registration)) assert registration.active assert(registration.id in self._registrations) if not self._transport: raise exception.TransportLost() request_id = util.id() on_reply = txaio.create_future() self._unregister_reqs[request_id] = UnregisterRequest(request_id, on_reply, registration.id) msg = message.Unregister(request_id, registration.id) self._transport.send(msg) return on_reply
def _unregister(self, registration): """ Called from :meth:`autobahn.wamp.protocol.Registration.unregister` """ assert(isinstance(registration, Registration)) assert registration.active assert(registration.id in self._registrations) if not self._transport: raise exception.TransportLost() request_id = self._request_id_gen.next() on_reply = txaio.create_future() self._unregister_reqs[request_id] = UnregisterRequest(request_id, on_reply, registration.id) msg = message.Unregister(request_id, registration.id) self._transport.send(msg) return on_reply
def test_cancel(framework): cancels = [] def it_died(f): cancels.append(f) f = txaio.create_future(canceller=it_died) # both Future and Deferred have .cancel() methods .. but seemed # more "symmetric"/expected to make a method? But could just stick # with "f.cancel()" here ... txaio.cancel(f) # at least for Twisted, we have to "handle" the "CancelledError" # -- in practice, dropping a future on the floor with no # error-handler is A Bad Thing anyway txaio.add_callbacks(f, None, lambda _: None) run_once() run_once() assert cancels == [f]
def call(self, procedure, *args, **kwargs): """ Reimplemented to support calls with custom options """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert(isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = util.id() on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, procedure, on_reply, {}) try: self._transport.send(AkCall(request_id, procedure, args, kwargs)) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def fire(self, event, *args, **kwargs): """ Fire a particular event. :param event: the event to fire. All other args and kwargs are passed on to the handler(s) for the event. :return: a Deferred/Future gathering all async results from all handlers and/or parent handlers. """ # print("firing '{}' from '{}'".format(event, hash(self))) if self._listeners is None: return txaio.create_future(result=[]) self._check_event(event) res = [] for handler in self._listeners.get(event, set()): future = txaio.as_future(handler, *args, **kwargs) res.append(future) if self._parent is not None: res.append(self._parent.fire(event, *args, **kwargs)) return txaio.gather(res, consume_exceptions=False)
def test_errback_plain_exception(framework): ''' reject a future with just an Exception ''' f = txaio.create_future() exception = RuntimeError("it failed") errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) txaio.reject(f, exception) run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) tb = txaio.failure_format_traceback(errors[0]) assert 'RuntimeError' in tb assert 'it failed' in tb assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed' assert 'it failed' in str(errors[0])
def test_chained_callback(framework): """ Chain two callbacks where the first one alters the value. """ calls = [] def callback0(arg): calls.append(arg) return arg + " pray I do not alter it futher" def callback1(arg): calls.append(arg) f = txaio.create_future() txaio.add_callbacks(f, callback0, None) txaio.add_callbacks(f, callback1, None) txaio.resolve(f, "the deal") run_once() assert len(calls) == 2 assert calls[0] == "the deal" assert calls[1] == "the deal pray I do not alter it futher"
def connectionMade(self): self.log.debug("WampRawSocketProtocol: connection made") # the peer we are connected to # try: peer = self.transport.getPeer() except AttributeError: # ProcessProtocols lack getPeer() self.peer = "?" else: self.peer = peer2str(peer) # a Future/Deferred that fires when we hit STATE_CLOSED self.is_closed = txaio.create_future() # this will hold an ApplicationSession object # once the RawSocket opening handshake has been # completed # self._session = None # Will hold the negotiated serializer once the opening handshake is complete # self._serializer = None # Will be set to True once the opening handshake is complete # self._handshake_complete = False # Buffer for opening handshake received bytes. # self._handshake_bytes = b'' # Clinet requested maximum length of serialized messages. # self._max_len_send = None
def callRemoteMessage(self, mcall, timeout = None): """ Uses the specified L{message.MethodCallMessage} to call a remote method. @rtype: L{twisted.internet.defer.Deferred} @returns: a Deferred to the result of the remote method call """ assert isinstance(mcall, message.MethodCallMessage) if mcall.expectReply: d = txaio.create_future() if timeout: timeout = txaio.call_later(timeout, self._onMethodTimeout, mcall.serial, d) self._pendingCalls[ mcall.serial ] = (d, timeout) self.sendMessage( mcall ) return d else: self.sendMessage( mcall ) return txaio.create_future_success(None)
def test_errback_without_except(): ''' Create a failure without an except block ''' f = txaio.create_future() exception = RuntimeError("it failed") errors = [] def err(f): errors.append(f) txaio.add_callbacks(f, None, err) fail = txaio.create_failure(exception) txaio.reject(f, fail) run_once() assert len(errors) == 1 assert isinstance(errors[0], txaio.IFailedFuture) tb = txaio.failure_format_traceback(errors[0]) assert 'RuntimeError' in tb assert 'it failed' in tb assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed' assert 'it failed' in str(errors[0])
def foo(x): f = txaio.create_future() txaio.resolve(f, x * x) return f
def _connect_once(self, reactor, transport): self.log.info( 'connecting once using transport type "{transport_type}" ' 'over endpoint "{endpoint_desc}"', transport_type=transport.type, endpoint_desc=transport.describe_endpoint(), ) done = txaio.create_future() # factory for ISession objects def create_session(): cfg = ComponentConfig(self._realm, self._extra) try: self._session = session = self.session_factory(cfg) for auth_name, auth_config in self._authentication.items(): authenticator = create_authenticator(auth_name, **auth_config) session.add_authenticator(authenticator) except Exception as e: # couldn't instantiate session calls, which is fatal. # let the reconnection logic deal with that f = txaio.create_failure(e) txaio.reject(done, f) raise else: # hook up the listener to the parent so we can bubble # up events happning on the session onto the # connection. This lets you do component.on('join', # cb) which will work just as if you called # session.on('join', cb) for every session created. session._parent = self # listen on leave events; if we get errors # (e.g. no_such_realm), an on_leave can happen without # an on_join before def on_leave(session, details): self.log.info( "session leaving '{details.reason}'", details=details, ) if not txaio.is_called(done): if details.reason in [u"wamp.error.no_auth_method"]: txaio.resolve(done, txaio.create_failure( ApplicationError( u"wamp.error.no_auth_method" ) )) else: txaio.resolve(done, None) session.on('leave', on_leave) # if we were given a "main" procedure, we run through # it completely (i.e. until its Deferred fires) and # then disconnect this session def on_join(session, details): transport.connect_sucesses += 1 self.log.debug("session on_join: {details}", details=details) d = txaio.as_future(self._entry, reactor, session) def main_success(_): self.log.debug("main_success") def leave(): try: session.leave() except SessionNotReady: # someone may have already called # leave() pass txaio.call_later(0, leave) def main_error(err): self.log.debug("main_error: {err}", err=err) txaio.reject(done, err) session.disconnect() txaio.add_callbacks(d, main_success, main_error) if self._entry is not None: session.on('join', on_join) # listen on disconnect events. Note that in case we # had a "main" procedure, we could have already # resolve()'d our "done" future def on_disconnect(session, was_clean): self.log.debug( "session on_disconnect: was_clean={was_clean}", was_clean=was_clean, ) if not txaio.is_called(done): if not was_clean: self.log.warn( u"Session disconnected uncleanly" ) # eg the session has left the realm, and the transport was properly # shut down. successfully finish the connection txaio.resolve(done, None) session.on('disconnect', on_disconnect) # return the fresh session object return session transport.connect_attempts += 1 d = self._connect_transport(reactor, transport, create_session) def on_connect_sucess(proto): # if e.g. an SSL handshake fails, we will have # successfully connected (i.e. get here) but need to # 'listen' for the "connectionLost" from the underlying # protocol in case of handshake failure .. so we wrap # it. Also, we don't increment transport.success_count # here on purpose (because we might not succeed). orig = proto.connectionLost @wraps(orig) def lost(fail): rtn = orig(fail) if not txaio.is_called(done): txaio.reject(done, fail) return rtn proto.connectionLost = lost def on_connect_failure(err): transport.connect_failures += 1 # failed to establish a connection in the first place txaio.reject(done, err) txaio.add_callbacks(d, on_connect_sucess, None) txaio.add_callbacks(d, None, on_connect_failure) return done