Пример #1
0
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])
Пример #2
0
        def transport_check(_):
            self.log.debug('Entering re-connect loop')

            if not self._can_reconnect():
                err_msg = u"Component failed: Exhausted all transport connect attempts"
                self.log.info(err_msg)
                try:
                    raise RuntimeError(err_msg)
                except RuntimeError as e:
                    txaio.reject(self._done_f, e)
                    return

            while True:

                transport = next(transport_gen)

                if transport.can_reconnect():
                    transport_candidate[0] = transport
                    break

            delay = transport.next_delay()
            self.log.debug(
                'trying transport {transport_idx} using connect delay {transport_delay}',
                transport_idx=transport.idx,
                transport_delay=delay,
            )

            self._delay_f = txaio.sleep(delay)
            txaio.add_callbacks(self._delay_f, attempt_connect, error)
Пример #3
0
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])
Пример #4
0
 def on_leave(session, details):
     self.log.debug("session on_leave: {details}", details=details)
     # this could be a "leave" that's expected e.g. our
     # main() exited, or it could be an error
     if not txaio.is_called(done):
         if details.reason.startswith('wamp.error.'):
             txaio.reject(done, ApplicationError(details.reason, details.message))
         else:
             txaio.resolve(done, None)
Пример #5
0
                def on_disconnect(session, was_clean):
                    self.log.debug("session on_disconnect: {was_clean}", was_clean=was_clean)

                    if was_clean:
                        # eg the session has left the realm, and the transport was properly
                        # shut down. successfully finish the connection
                        txaio.resolve(done, None)
                    else:
                        txaio.reject(done, RuntimeError('transport closed uncleanly'))
Пример #6
0
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
Пример #7
0
 def lost(fail):
     rtn = orig(fail)
     if not txaio.is_called(done):
         # asyncio will call connection_lost(None) in case of
         # a transport failure, in which case we create an
         # appropriate exception
         if fail is None:
             fail = TransportLost("failed to complete connection")
         txaio.reject(done, fail)
     return rtn
Пример #8
0
 def on_error(err):
     """
     this may seem redundant after looking at _connect_transport, but
     it will handle a case where something goes wrong in
     _connect_transport itself -- as the only connect our
     caller has is the 'done' future
     """
     transport.connect_failures += 1
     # something bad has happened, and maybe didn't get caught
     # upstream yet
     if not txaio.is_called(done):
         txaio.reject(done, err)
Пример #9
0
 def error(fail):
     self._delay_f = None
     if self._stopping:
         # might be better to add framework-specific checks in
         # subclasses to see if this is CancelledError (for
         # Twisted) and whatever asyncio does .. but tracking
         # if we're in the shutdown path is fine too
         txaio.resolve(self._done_f, None)
     else:
         self.log.info("Internal error {msg}", msg=txaio.failure_message(fail))
         self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
         txaio.reject(self._done_f, fail)
Пример #10
0
 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.close.normal"]:
             txaio.resolve(done, None)
         else:
             f = txaio.create_failure(
                 ApplicationError(details.reason)
             )
             txaio.reject(done, f)
Пример #11
0
 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 connect_error(fail):
                        if isinstance(fail.value, asyncio.CancelledError):
                            reconnect[0] = False
                            txaio.reject(done_f, fail)
                            return

                        self.log.debug(u'component failed: {error}', error=txaio.failure_message(fail))
                        self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                        # If this is a "fatal error" that will never work,
                        # we bail out now
                        if isinstance(fail.value, ApplicationError):
                            if fail.value.error in [u'wamp.error.no_such_realm']:
                                reconnect[0] = False
                                self.log.error(u"Fatal error, not reconnecting")
                                txaio.reject(done_f, fail)
                                return

                            self.log.error(u"{msg}", msg=fail.value.error_message())
                            return one_reconnect_loop(None)

                        elif isinstance(fail.value, OSError):
                            # failed to connect entirely, like nobody
                            # listening etc.
                            self.log.info(u"Connection failed: {msg}", msg=txaio.failure_message(fail))
                            return one_reconnect_loop(None)

                        elif _is_ssl_error(fail.value):
                            # Quoting pyOpenSSL docs: "Whenever
                            # [SSL.Error] is raised directly, it has a
                            # list of error messages from the OpenSSL
                            # error queue, where each item is a tuple
                            # (lib, function, reason). Here lib, function
                            # and reason are all strings, describing where
                            # and what the problem is. See err(3) for more
                            # information."
                            self.log.error(u"TLS failure: {reason}", reason=fail.value.args[1])
                            self.log.error(u"Marking this transport as failed")
                            transport.failed()
                        else:
                            self.log.error(
                                u'Connection failed: {error}',
                                error=txaio.failure_message(fail),
                            )
                            # some types of errors should probably have
                            # stacktraces logged immediately at error
                            # level, e.g. SyntaxError?
                            self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                            return one_reconnect_loop(None)
Пример #13
0
 def errorReceived(self, merr):
     """
     Called when an error message is received
     """
     d, timeout = self._pendingCalls.get(merr.reply_serial, (None,None))
     if timeout:
         timeout.cancel()
     if d:
         del self._pendingCalls[ merr.reply_serial ]
         e = error.RemoteError( merr.error_name )
         e.message = ''
         e.values  = []
         if merr.body:
             if isinstance(merr.body[0], six.string_types):
                 e.message = merr.body[0]
             e.values = merr.body
         txaio.reject(d, e)
Пример #14
0
    def connectionLost(self, reason):
        """
        Called when the transport loses connection to the bus
        """
        if self.busName is None:
            return

        for cb in self._dcCallbacks:
            cb(self, reason)
        
        for d, timeout in self._pendingCalls.values():
            if timeout:
                timeout.cancel()
            txaio.reject(d, reason)
        self._pendingCalls = dict()

        self.objHandler.connectionLost(reason)
Пример #15
0
def connect( reactor,  busAddress='session' ):
    """
    Connects to the specified bus and returns a
    L{twisted.internet.defer.Deferred} to the fully-connected
    L{DBusClientConnection}. 

    @param reactor: L{twisted.internet.interfaces.IReactor} implementor
    
    @param busAddress: 'session', 'system', or a valid bus address as defined by
                       the DBus specification. If 'session' (the default) or 'system'
                       is supplied, the contents of the DBUS_SESSION_BUS_ADDRESS or
                       DBUS_SYSTEM_BUS_ADDRESS environment variables will be used for
                       the bus address, respectively. If DBUS_SYSTEM_BUS_ADDRESS is not
                       set, the well-known address unix:path=/var/run/dbus/system_bus_socket
                       will be used.
    @type busAddress: C{string}

    @rtype: L{DBusClientConnection}
    @returns: Deferred to L{DBusClientConnection} 
    """
    from txdbus import endpoints

    f = DBusClientFactory()

    d = f.getConnection()

    eplist = endpoints.getDBusEndpoints(reactor, busAddress)

    eplist.reverse()

    def try_next_ep(err):
        if eplist:
            txaio.add_callbacks(eplist.pop().connect(f), None, try_next_ep)
        else:
            txaio.reject(d, error.ConnectError(string='Failed to connect to any bus address. Last error: ' + err.getErrorMessage()))

    if eplist:
        try_next_ep(None)
    else:
        txaio.reject(d, error.ConnectError(string='Failed to connect to any bus address. No valid bus addresses found'))

    return d
Пример #16
0
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])
Пример #17
0
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])
Пример #18
0
 def _onMethodTimeout(self, serial, d):
     """
     Called when a remote method invocation timeout occurs
     """
     del self._pendingCalls[ serial ]
     txaio.reject(d, error.TimeOut('Method call timed out'))
Пример #19
0
        def create_session():
            cfg = ComponentConfig(self._realm, self._extra)
            try:
                session = self.session_factory(cfg)
                for auth_name, auth_config in self._authentication.items():
                    session.add_authenticator(auth_name, **auth_config)

            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 self._entry:
                        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):
                    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)

                    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 was_clean:
                            # eg the session has left the realm, and the transport was properly
                            # shut down. successfully finish the connection
                            txaio.resolve(done, None)
                        else:
                            txaio.reject(
                                done,
                                RuntimeError('transport closed uncleanly'))

                session.on('disconnect', on_disconnect)

                # return the fresh session object
                return session
Пример #20
0
 def main_error(err):
     self.log.debug("main_error: {err}", err=err)
     txaio.reject(done, err)
     session.disconnect()
Пример #21
0
 def lost(fail):
     rtn = orig(fail)
     if not txaio.is_called(done):
         txaio.reject(done, fail)
     return rtn
Пример #22
0
 def main_error(err):
     self.log.debug("main_error: {err}", err=err)
     txaio.reject(done, err)
Пример #23
0
from __future__ import print_function
import txaio

def cb(value):
    print("Callback:", value)
    return value  # should always return input arg

def eb(fail):
    # fail will implement txaio.IFailedPromise
    print("Errback:", fail)
    # fail.printTraceback()
    return fail  # should always return input arg

f0 = txaio.create_future()
f1 = txaio.create_future()
txaio.add_callbacks(f0, cb, eb)
txaio.add_callbacks(f1, cb, eb)

# ...

txaio.reject(f0, RuntimeError("it failed"))
# or can just "txaio.reject(f0)" if inside an except: block
txaio.resolve(f1, "The answer is: 42")

if txaio.using_asyncio:
    # for twisted, we don't need to enter the event-loop for this
    # simple example (since all results are already available), but
    # you'd simply use reactor.run()/.stop() or task.react() as normal
    import asyncio
    asyncio.get_event_loop().run_until_complete(f1)
Пример #24
0
 def try_next_ep(err):
     if eplist:
         txaio.add_callbacks(eplist.pop().connect(f), None, try_next_ep)
     else:
         txaio.reject(d, error.ConnectError(string='Failed to connect to any bus address. Last error: ' + err.getErrorMessage()))
Пример #25
0
    def onMessage(self, msg):
        """
        Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onMessage`
        """
        if self._session_id is None:

            # the first message must be WELCOME, ABORT or CHALLENGE ..
            if isinstance(msg, message.Welcome):
                self._session_id = msg.session

                details = SessionDetails(self._realm, self._session_id, msg.authid, msg.authrole, msg.authmethod)
                d = txaio.as_future(self.onJoin, details)

                def _error(e):
                    return self._swallow_error(e, "While firing onJoin")
                txaio.add_callbacks(d, None, _error)

            elif isinstance(msg, message.Abort):

                # fire callback and close the transport
                details = types.CloseDetails(msg.reason, msg.message)
                d = txaio.as_future(self.onLeave, details)

                def _error(e):
                    return self._swallow_error(e, "While firing onLeave")
                txaio.add_callbacks(d, None, _error)

            elif isinstance(msg, message.Challenge):

                challenge = types.Challenge(msg.method, msg.extra)
                d = txaio.as_future(self.onChallenge, challenge)

                def success(signature):
                    reply = message.Authenticate(signature)
                    self._transport.send(reply)

                def error(err):
                    reply = message.Abort(u"wamp.error.cannot_authenticate", u"{0}".format(err.value))
                    self._transport.send(reply)
                    # fire callback and close the transport
                    details = types.CloseDetails(reply.reason, reply.message)
                    d = txaio.as_future(self.onLeave, details)

                    def _error(e):
                        return self._swallow_error(e, "While firing onLeave")
                    txaio.add_callbacks(d, None, _error)
                    # switching to the callback chain, effectively
                    # cancelling error (which we've now handled)
                    return d

                txaio.add_callbacks(d, success, error)

            else:
                raise ProtocolError("Received {0} message, and session is not yet established".format(msg.__class__))

        else:
            # self._session_id != None (aka "session established")
            if isinstance(msg, message.Goodbye):
                if not self._goodbye_sent:
                    # the peer wants to close: send GOODBYE reply
                    reply = message.Goodbye()
                    self._transport.send(reply)

                self._session_id = None

                # fire callback and close the transport
                details = types.CloseDetails(msg.reason, msg.message)
                d = txaio.as_future(self.onLeave, details)

                def _error(e):
                    errmsg = 'While firing onLeave for reason "{0}" and message "{1}"'.format(msg.reason, msg.message)
                    return self._swallow_error(e, errmsg)
                txaio.add_callbacks(d, None, _error)

            elif isinstance(msg, message.Event):

                if msg.subscription in self._subscriptions:

                    # fire all event handlers on subscription ..
                    for subscription in self._subscriptions[msg.subscription]:

                        handler = subscription.handler

                        invoke_args = (handler.obj,) if handler.obj else tuple()
                        if msg.args:
                            invoke_args = invoke_args + tuple(msg.args)

                        invoke_kwargs = msg.kwargs if msg.kwargs else dict()
                        if handler.details_arg:
                            invoke_kwargs[handler.details_arg] = types.EventDetails(publication=msg.publication, publisher=msg.publisher, topic=msg.topic)

                        def _error(e):
                            errmsg = 'While firing {0} subscribed under {1}.'.format(
                                handler.fn, msg.subscription)
                            return self._swallow_error(e, errmsg)

                        future = txaio.as_future(handler.fn, *invoke_args, **invoke_kwargs)
                        txaio.add_callbacks(future, None, _error)

                else:
                    raise ProtocolError("EVENT received for non-subscribed subscription ID {0}".format(msg.subscription))

            elif isinstance(msg, message.Published):

                if msg.request in self._publish_reqs:

                    # get and pop outstanding publish request
                    publish_request = self._publish_reqs.pop(msg.request)

                    # create a new publication object
                    publication = Publication(msg.publication)

                    # resolve deferred/future for publishing successfully
                    txaio.resolve(publish_request.on_reply, publication)
                else:
                    raise ProtocolError("PUBLISHED received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Subscribed):

                if msg.request in self._subscribe_reqs:

                    # get and pop outstanding subscribe request
                    request = self._subscribe_reqs.pop(msg.request)

                    # create new handler subscription list for subscription ID if not yet tracked
                    if msg.subscription not in self._subscriptions:
                        self._subscriptions[msg.subscription] = []

                    subscription = Subscription(msg.subscription, self, request.handler)

                    # add handler to existing subscription
                    self._subscriptions[msg.subscription].append(subscription)

                    # resolve deferred/future for subscribing successfully
                    txaio.resolve(request.on_reply, subscription)
                else:
                    raise ProtocolError("SUBSCRIBED received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Unsubscribed):

                if msg.request in self._unsubscribe_reqs:

                    # get and pop outstanding subscribe request
                    request = self._unsubscribe_reqs.pop(msg.request)

                    # if the subscription still exists, mark as inactive and remove ..
                    if request.subscription_id in self._subscriptions:
                        for subscription in self._subscriptions[request.subscription_id]:
                            subscription.active = False
                        del self._subscriptions[request.subscription_id]

                    # resolve deferred/future for unsubscribing successfully
                    txaio.resolve(request.on_reply, 0)
                else:
                    raise ProtocolError("UNSUBSCRIBED received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Result):

                if msg.request in self._call_reqs:

                    if msg.progress:

                        # progressive result
                        call_request = self._call_reqs[msg.request]
                        if call_request.options.on_progress:
                            kw = msg.kwargs or dict()
                            args = msg.args or tuple()
                            try:
                                # XXX what if on_progress returns a Deferred/Future?
                                call_request.options.on_progress(*args, **kw)
                            except Exception as e:
                                try:
                                    self.onUserError(e, "While firing on_progress")
                                except:
                                    pass

                        else:
                            # silently ignore progressive results
                            pass

                    else:
                        # final result
                        #
                        call_request = self._call_reqs.pop(msg.request)

                        on_reply = call_request.on_reply

                        if msg.kwargs:
                            if msg.args:
                                res = types.CallResult(*msg.args, **msg.kwargs)
                            else:
                                res = types.CallResult(**msg.kwargs)
                            txaio.resolve(on_reply, res)
                        else:
                            if msg.args:
                                if len(msg.args) > 1:
                                    res = types.CallResult(*msg.args)
                                    txaio.resolve(on_reply, res)
                                else:
                                    txaio.resolve(on_reply, msg.args[0])
                            else:
                                txaio.resolve(on_reply, None)
                else:
                    raise ProtocolError("RESULT received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Invocation):

                if msg.request in self._invocations:

                    raise ProtocolError("INVOCATION received for request ID {0} already invoked".format(msg.request))

                else:

                    if msg.registration not in self._registrations:

                        raise ProtocolError("INVOCATION received for non-registered registration ID {0}".format(msg.registration))

                    else:
                        registration = self._registrations[msg.registration]

                        endpoint = registration.endpoint

                        if endpoint.obj:
                            invoke_args = (endpoint.obj,)
                        else:
                            invoke_args = tuple()

                        if msg.args:
                            invoke_args = invoke_args + tuple(msg.args)

                        invoke_kwargs = msg.kwargs if msg.kwargs else dict()

                        if endpoint.details_arg:

                            if msg.receive_progress:
                                def progress(*args, **kwargs):
                                    progress_msg = message.Yield(msg.request, args=args, kwargs=kwargs, progress=True)
                                    self._transport.send(progress_msg)
                            else:
                                progress = None

                            invoke_kwargs[endpoint.details_arg] = types.CallDetails(progress, caller=msg.caller, procedure=msg.procedure)

                        on_reply = txaio.as_future(endpoint.fn, *invoke_args, **invoke_kwargs)

                        def success(res):
                            del self._invocations[msg.request]

                            if isinstance(res, types.CallResult):
                                reply = message.Yield(msg.request, args=res.results, kwargs=res.kwresults)
                            else:
                                reply = message.Yield(msg.request, args=[res])

                            try:
                                self._transport.send(reply)
                            except SerializationError as e:
                                # the application-level payload returned from the invoked procedure can't be serialized
                                reply = message.Error(message.Invocation.MESSAGE_TYPE, msg.request, ApplicationError.INVALID_PAYLOAD,
                                                      args=[u'success return value from invoked procedure "{0}" could not be serialized: {1}'.format(registration.procedure, e)])
                                self._transport.send(reply)

                        def error(err):
                            errmsg = 'Failure while invoking procedure {0} registered under "{1}".'.format(endpoint.fn, registration.procedure)
                            try:
                                self.onUserError(err, errmsg)
                            except:
                                pass
                            formatted_tb = None
                            if self.traceback_app:
                                # if asked to marshal the traceback within the WAMP error message, extract it
                                # noinspection PyCallingNonCallable
                                tb = StringIO()
                                err.printTraceback(file=tb)
                                formatted_tb = tb.getvalue().splitlines()

                            del self._invocations[msg.request]

                            if hasattr(err, 'value'):
                                exc = err.value
                            else:
                                exc = err

                            reply = self._message_from_exception(message.Invocation.MESSAGE_TYPE, msg.request, exc, formatted_tb)

                            try:
                                self._transport.send(reply)
                            except SerializationError as e:
                                # the application-level payload returned from the invoked procedure can't be serialized
                                reply = message.Error(message.Invocation.MESSAGE_TYPE, msg.request, ApplicationError.INVALID_PAYLOAD,
                                                      args=[u'error return value from invoked procedure "{0}" could not be serialized: {1}'.format(registration.procedure, e)])
                                self._transport.send(reply)
                            # we have handled the error, so we eat it
                            return None

                        self._invocations[msg.request] = InvocationRequest(msg.request, on_reply)

                        txaio.add_callbacks(on_reply, success, error)

            elif isinstance(msg, message.Interrupt):

                if msg.request not in self._invocations:
                    raise ProtocolError("INTERRUPT received for non-pending invocation {0}".format(msg.request))
                else:
                    # noinspection PyBroadException
                    try:
                        self._invocations[msg.request].cancel()
                    except Exception as e:
                        # XXX can .cancel() return a Deferred/Future?
                        try:
                            self.onUserError(e, "While cancelling call.")
                        except:
                            pass
                    finally:
                        del self._invocations[msg.request]

            elif isinstance(msg, message.Registered):

                if msg.request in self._register_reqs:

                    # get and pop outstanding register request
                    request = self._register_reqs.pop(msg.request)

                    # create new registration if not yet tracked
                    if msg.registration not in self._registrations:
                        registration = Registration(self, msg.registration, request.procedure, request.endpoint)
                        self._registrations[msg.registration] = registration
                    else:
                        raise ProtocolError("REGISTERED received for already existing registration ID {0}".format(msg.registration))

                    txaio.resolve(request.on_reply, registration)
                else:
                    raise ProtocolError("REGISTERED received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Unregistered):

                if msg.request in self._unregister_reqs:

                    # get and pop outstanding subscribe request
                    request = self._unregister_reqs.pop(msg.request)

                    # if the registration still exists, mark as inactive and remove ..
                    if request.registration_id in self._registrations:
                        self._registrations[request.registration_id].active = False
                        del self._registrations[request.registration_id]

                    # resolve deferred/future for unregistering successfully
                    txaio.resolve(request.on_reply)
                else:
                    raise ProtocolError("UNREGISTERED received for non-pending request ID {0}".format(msg.request))

            elif isinstance(msg, message.Error):

                # remove outstanding request and get the reply deferred/future
                on_reply = None

                # ERROR reply to CALL
                if msg.request_type == message.Call.MESSAGE_TYPE and msg.request in self._call_reqs:
                    on_reply = self._call_reqs.pop(msg.request).on_reply

                # ERROR reply to PUBLISH
                elif msg.request_type == message.Publish.MESSAGE_TYPE and msg.request in self._publish_reqs:
                    on_reply = self._publish_reqs.pop(msg.request).on_reply

                # ERROR reply to SUBSCRIBE
                elif msg.request_type == message.Subscribe.MESSAGE_TYPE and msg.request in self._subscribe_reqs:
                    on_reply = self._subscribe_reqs.pop(msg.request).on_reply

                # ERROR reply to UNSUBSCRIBE
                elif msg.request_type == message.Unsubscribe.MESSAGE_TYPE and msg.request in self._unsubscribe_reqs:
                    on_reply = self._unsubscribe_reqs.pop(msg.request).on_reply

                # ERROR reply to REGISTER
                elif msg.request_type == message.Register.MESSAGE_TYPE and msg.request in self._register_reqs:
                    on_reply = self._register_reqs.pop(msg.request).on_reply

                # ERROR reply to UNREGISTER
                elif msg.request_type == message.Unregister.MESSAGE_TYPE and msg.request in self._unregister_reqs:
                    on_reply = self._unregister_reqs.pop(msg.request).on_reply

                if on_reply:
                    txaio.reject(on_reply, self._exception_from_message(msg))
                else:
                    raise ProtocolError("WampAppSession.onMessage(): ERROR received for non-pending request_type {0} and request ID {1}".format(msg.request_type, msg.request))

            else:

                raise ProtocolError("Unexpected message {0}".format(msg.__class__))
Пример #26
0
 def lost(fail):
     rtn = orig(fail)
     if not txaio.is_called(done):
         txaio.reject(done, fail)
     return rtn
Пример #27
0
        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
Пример #28
0
 def setup_error(err):
     self.log.debug("setup_error: {err}", err=err)
     txaio.reject(done, err)
 def error(fail):
     self.log.info("Internal error {msg}", msg=txaio.failure_message(fail))
     self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
     txaio.reject(done_f, fail)
Пример #30
0
 def main_error(err):
     self.log.debug("main_error: {err}", err=err)
     txaio.reject(done, err)
     session.disconnect()
Пример #31
0
        def create_session():
            cfg = ComponentConfig(self._realm, self._extra)
            try:
                session = self.session_factory(cfg)
            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

                # the only difference bewteen MAIN and SETUP-type
                # entry-points is that we want to shut down the
                # component when a MAIN-type entrypoint's Deferred is
                # done.
                if self._entry_type == Component.TYPE_MAIN:

                    def on_join(session, details):
                        self.log.debug("session on_join: {details}", details=details)
                        transport.connect_sucesses += 1
                        self.log.info(
                            'Successfully connected to transport #{transport_idx}: url={url}',
                            transport_idx=transport.idx,
                            url=transport.config['url'],
                        )
                        d = txaio.as_future(self._entry, reactor, session)

                        def main_success(_):
                            self.log.debug("main_success")
                            session.leave()

                        def main_error(err):
                            self.log.debug("main_error: {err}", err=err)
                            txaio.reject(done, err)
                            # I guess .leave() here too...?

                        txaio.add_callbacks(d, main_success, main_error)

                    session.on('join', on_join)

                elif self._entry_type == Component.TYPE_SETUP:

                    def on_join(session, details):
                        self.log.debug("session on_join: {details}", details=details)
                        self.log.info(
                            'Successfully connected to transport #{transport_idx}: url={url}',
                            transport_idx=transport.idx,
                            url=transport.config['url'],
                        )
                        d = txaio.as_future(self._entry, reactor, session)

                        def setup_success(_):
                            self.log.debug("setup_success")

                        def setup_error(err):
                            self.log.debug("setup_error: {err}", err=err)
                            txaio.reject(done, err)

                        txaio.add_callbacks(d, setup_success, setup_error)

                    session.on('join', on_join)

                else:
                    assert(False), 'logic error'

                # listen on leave events
                def on_leave(session, details):
                    self.log.debug("session on_leave: {details}", details=details)
                    # this could be a "leave" that's expected e.g. our
                    # main() exited, or it could be an error
                    if not txaio.is_called(done):
                        if details.reason.startswith('wamp.error.'):
                            txaio.reject(done, ApplicationError(details.reason, details.message))
                        else:
                            txaio.resolve(done, None)
                session.on('leave', on_leave)

                # listen on disconnect events
                def on_disconnect(session, was_clean):
                    self.log.debug("session on_disconnect: {was_clean}", was_clean=was_clean)

                    if was_clean:
                        # eg the session has left the realm, and the transport was properly
                        # shut down. successfully finish the connection
                        txaio.resolve(done, None)
                    else:
                        txaio.reject(done, RuntimeError('transport closed uncleanly'))

                session.on('disconnect', on_disconnect)

                # return the fresh session object
                return session
Пример #32
0
 def on_connect_failure(err):
     transport.connect_failures += 1
     # failed to establish a connection in the first place
     txaio.reject(done, err)
Пример #33
0
 def main_error(err):
     self.log.debug("main_error: {err}", err=err)
     txaio.reject(done, err)
Пример #34
0
 def error(err):
     txaio.reject(d, err)
Пример #35
0
 def error(err):
     txaio.reject(d, err)