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 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)
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 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)
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'))
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 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
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)
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)
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)
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)
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)
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)
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
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_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 _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'))
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
def main_error(err): self.log.debug("main_error: {err}", err=err) txaio.reject(done, err) session.disconnect()
def lost(fail): rtn = orig(fail) if not txaio.is_called(done): txaio.reject(done, fail) return rtn
def main_error(err): self.log.debug("main_error: {err}", err=err) txaio.reject(done, err)
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)
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()))
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__))
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
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)
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
def on_connect_failure(err): transport.connect_failures += 1 # failed to establish a connection in the first place txaio.reject(done, err)
def error(err): txaio.reject(d, err)