def component(config): session = ApplicationSession(config) for name, fn in callbacks.items(): session.on(name, fn) return session
def _setup_invocation_forwarding(self, other: ApplicationSession): self.log.info( "setup invocation forwarding between {me} and {other} (exclude_authid={exclude_authid}, exclude_authrole={exclude_authrole})", exclude_authid=self._exclude_authid, exclude_authrole=self._exclude_authrole, me=self, other=other) # called when a registration is created on the local router @inlineCallbacks def on_registration_create(reg_session, reg_details, details=None): """ Event handler fired when a new registration was created on this router. The handler will then also register on the other router, and when receiving calls, re-issue those on this router. :param reg_session: :param reg_details: :param details: :return: """ if reg_details['uri'].startswith("wamp."): return if reg_details['id'] in self._regs: # this should not happen actually, but not sure .. self.log.error( 'on_registration_create: reg ID {reg_id} already in map {method}', reg_id=reg_details['id'], method=hltype(BridgeSession._setup_invocation_forwarding)) return self._regs[reg_details['id']] = reg_details self._regs[reg_details['id']]['reg'] = None uri = reg_details['uri'] ERR_MSG = [None] @inlineCallbacks def on_call(*args, **kwargs): assert 'details' in kwargs details = kwargs.pop('details') options = kwargs.pop('options', None) if details.caller is None or details.caller_authrole is None or details.caller_authid is None: raise RuntimeError( "Internal error attempting rlink forwarding") self.log.info( 'Received invocation on uri={uri}, options={options} (caller={caller}, caller_authid={caller_authid}, caller_authrole={caller_authrole}, forward_for={forward_for})', uri=uri, options=options, caller=details.caller, caller_authid=details.caller_authid, caller_authrole=details.caller_authrole, forward_for=details.forward_for) this_forward = { 'session': details.caller, 'authid': details.caller_authrole, 'authrole': details.caller_authrole, } if details.forward_for: # the call comes already forwarded from a router node .. if len(details.forward_for) >= 0: self.log.debug('SKIP! already forwarded') return forward_for = copy.deepcopy(details.forward_for) forward_for.append(this_forward) else: forward_for = [this_forward] options = CallOptions(forward_for=forward_for) try: result = yield self.call(uri, *args, options=options, **kwargs) except TransportLost: return except ApplicationError as e: if e.error not in ['wamp.close.normal']: self.log.warn('FAILED TO CALL 1: {} {}'.format( type(e), str(e))) return except Exception as e: if not ERR_MSG[0]: self.log.warn('FAILED TO CALL 2: {} {}'.format( type(e), str(e))) ERR_MSG[0] = True return self.log.info( "RLink forward-invoked call {dir} (options={options})", dir=self.DIR, options=options, ) return result try: reg = yield other.register(on_call, uri, options=RegisterOptions( details_arg='details', invoke=reg_details.get( 'invoke', None), )) except Exception as e: # FIXME: partially fixes https://github.com/crossbario/crossbar/issues/1894, # however we need to make sure this situation never happens. if isinstance( e, ApplicationError ) and e.error == 'wamp.error.procedure_already_exists': other_leg = 'local' if self.IS_REMOTE_LEG else 'remote' self.log.debug( f"on_registration_create: tried to register procedure {uri} on {other_leg} " f"session but it's already registered.") return raise Exception( "fatal: could not forward-register '{}'".format(uri)) # so ... if, during that "yield" above while we register # on the "other" router, *this* router may have already # un-registered. If that happened, our registration will # be gone, so we immediately un-register on the other side if reg_details['id'] not in self._regs: self.log.info("registration already gone: {uri}", uri=reg_details['uri']) yield reg.unregister() else: self._regs[reg_details['id']]['reg'] = reg self.log.info( "created forwarding registration: me={me} other={other} reg_id={reg_id} reg_details={reg_details} details={details} reg_session={reg_session}", me=self._session_id, other=other._session_id, reg_id=reg_details['id'], reg_details=reg_details, details=details, reg_session=reg_session, ) # called when a registration is removed from the local router @inlineCallbacks def on_registration_delete(session_id, reg_id, details=None): self.log.info( "Registration deleted: {me} {session} {reg_id} {details}", me=self, session=session_id, reg_id=reg_id, details=details, ) reg_details = self._regs.get(reg_id, None) if not reg_details: self.log.info("registration not tracked - huh??") return uri = reg_details['uri'] reg = self._regs[reg_id]['reg'] if reg is None: # see above; we might have un-registered here before # we got an answer from the other router self.log.info("registration has no 'reg'") else: yield reg.unregister() del self._regs[reg_id] self.log.info("{other} unsubscribed from {uri}".format(other=other, uri=uri)) @inlineCallbacks def register_current(): # get current registrations on the router regs = yield self.call("wamp.registration.list") for reg_id in regs['exact']: reg = yield self.call("wamp.registration.get", reg_id) assert reg[ 'id'] == reg_id, "Logic error, registration IDs don't match" yield on_registration_create(self._session_id, reg) @inlineCallbacks def on_remote_join(_session, _details): yield register_current() def on_remote_leave(_session, _details): # The remote session has ended, clear registration records. # Clearing this dictionary helps avoid the case where # local procedures are not registered on the remote leg # on reestablishment of remote session. # See: https://github.com/crossbario/crossbar/issues/1909 self._regs = {} if self.IS_REMOTE_LEG: yield register_current() else: # from the local leg, don't try to register procedures on the # remote leg unless the remote session is established. # This avoids issues where in-router components register procedures # on startup and when the rlink is setup, the local leg tries to # register procedures on the remote leg, even though the connection # hasn't established. # See: https://github.com/crossbario/crossbar/issues/1895 other.on('join', on_remote_join) other.on('leave', on_remote_leave) # listen to when new registrations are created on the local router yield self.subscribe(on_registration_create, "wamp.registration.on_create", options=SubscribeOptions(details_arg="details")) # listen to when a registration is removed from the local router yield self.subscribe(on_registration_delete, "wamp.registration.on_delete", options=SubscribeOptions(details_arg="details")) self.log.info("{me}: call forwarding setup done", me=self._session_id)