def test_outstanding_invoke(self): """ When a call is pending and the callee goes away, it cancels the in-flight call """ raise unittest.SkipTest('FIXME: Adjust unit test mocks #1567') session = mock.Mock() session._realm = u'realm1' self.router.authorize = mock.Mock( return_value=defer.succeed({u'allow': True, u'disclose': True}) ) rap = RouterApplicationSession(session, self.router_factory) rap.send(message.Hello(u"realm1", {u'caller': role.RoleCallerFeatures()})) rap.send(message.Register(1, u'foo')) # we can retrieve the Registration via # session.mock_calls[-1][1][0] if req'd # re-set the authorize, as the Deferred from above is already # used-up and it gets called again to authorize the Call self.router.authorize = mock.Mock( return_value=defer.succeed({u'allow': True, u'disclose': True}) ) rap.send(message.Call(42, u'foo')) orig = rap.send d = defer.Deferred() rap.send(message.Goodbye()) def wrapper(*args, **kw): d.callback(args[0]) return orig(*args, **kw) rap.send = wrapper # we can do this *after* the call to send() the Goodbye # (above) because it takes a reactor-turn to actually # process the cancel/errors etc -- hence the Deferred and # yield in this test... msg = yield d self.assertEqual(42, msg.request) self.assertEqual(u'wamp.error.canceled', msg.error)
def test_on_leave_valid_session_deferred(self): ''' cover when onLeave called after we have a valid session ''' session = MockApplicationSession() exception = RuntimeError("such challenge") session.onLeave = async_exception_raiser(exception) # we have to get to an established connection first... session.onMessage(create_mock_welcome()) self.assertTrue(session._session_id is not None) # okay we have a session ("because ._session_id is not None") msg = message.Goodbye() session.onMessage(msg) self.assertEqual(1, len(session.errors)) self.assertEqual(exception, session.errors[0][0])
def test_router_session_goodbye_custom_message(self): """ Reason should be propagated properly from Goodbye message """ from crossbar.router.session import RouterApplicationSession session = mock.Mock() session._realm = u'realm' router_factory = mock.Mock() rap = RouterApplicationSession(session, router_factory) rap.send(message.Hello(u'realm', {u'caller': role.RoleCallerFeatures()})) session.reset_mock() rap.send(message.Goodbye(u'wamp.reason.logout', u'some custom message')) leaves = [call for call in session.mock_calls if call[0] == 'onLeave'] self.assertEqual(1, len(leaves)) details = leaves[0][1][0] self.assertEqual(u'wamp.reason.logout', details.reason) self.assertEqual(u'some custom message', details.message)
def generate_test_messages(): return [ message.Hello(u"realm1", [role.RoleBrokerFeatures()]), message.Goodbye(), message.Heartbeat(123, 456), message.Yield(123456), message.Yield(123456, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Yield(123456, progress = True), message.Interrupt(123456), message.Interrupt(123456, mode = message.Interrupt.KILL), message.Invocation(123456, 789123), message.Invocation(123456, 789123, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Invocation(123456, 789123, timeout = 10000), message.Result(123456), message.Result(123456, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Result(123456, progress = True), message.Cancel(123456), message.Cancel(123456, mode = message.Cancel.KILL), message.Call(123456, u'com.myapp.procedure1'), message.Call(123456, u'com.myapp.procedure1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Call(123456, u'com.myapp.procedure1', timeout = 10000), message.Unregistered(123456), message.Unregister(123456, 789123), message.Registered(123456, 789123), message.Register(123456, u'com.myapp.procedure1'), message.Register(123456, u'com.myapp.procedure1', pkeys = [10, 11, 12]), message.Event(123456, 789123), message.Event(123456, 789123, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Event(123456, 789123, publisher = 300), message.Published(123456, 789123), message.Publish(123456, u'com.myapp.topic1'), message.Publish(123456, u'com.myapp.topic1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Publish(123456, u'com.myapp.topic1', excludeMe = False, exclude = [300], eligible = [100, 200, 300], discloseMe = True), message.Unsubscribed(123456), message.Unsubscribe(123456, 789123), message.Subscribed(123456, 789123), message.Subscribe(123456, u'com.myapp.topic1'), message.Subscribe(123456, u'com.myapp.topic1', match = message.Subscribe.MATCH_PREFIX), message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1'), message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}), message.Call(123456, u'com.myapp.\u4f60\u597d\u4e16\u754c', args=[1, 2, 3]), message.Result(123456, args=[1, 2, 3], kwargs={u'en': u'Hello World', u'jp': u'\u3053\u3093\u306b\u3061\u306f\u4e16\u754c'}) ]
def test_onleave_publish(self): """ Receiving a Goodbye should put the session in a "detached" state *before* the onLeave method is triggered """ router = mock.MagicMock() router.new_correlation_id = lambda: 'fake correlation id' utest = self class TestSession(RouterSession): def __init__(self, *args, **kw): super(TestSession, self).__init__(*args, **kw) # for this test, pretend we're connected (without # going through sending a Hello etc.) self._service_session = mock.MagicMock() self._transport = mock.MagicMock() self._session_id = 1234 self._router = router # normally done in Hello processing self.on_leave_called = False # so the test ensures onLeave called def onLeave(self, reason): utest.assertFalse(self.on_leave_called) # we check that when this method is called, we look # like we're un-joined utest.assertIs(None, self._session_id) utest.assertTrue(self._goodbye_sent) # on the router, .detach() should have been called utest.assertEqual(1, len(router.method_calls)) utest.assertEqual('detach', router.method_calls[0][0]) self.on_leave_called = True router_factory = mock.MagicMock() session = TestSession(router_factory) goodbye = message.Goodbye('wamp.close.normal', 'hi there') self.assertFalse(session._goodbye_sent) # do the test; we check results in onLeave self.assertFalse(session.on_leave_called) session.onMessage(goodbye) self.assertTrue(session.on_leave_called)
def test_router_session_goodbye_onLeave_error(self): """ Reason should be propagated properly from Goodbye message """ from crossbar.router.session import RouterApplicationSession session = mock.Mock() the_exception = RuntimeError("onLeave fails") def boom(*args, **kw): raise the_exception session.onLeave = mock.Mock(side_effect=boom) session._realm = u'realm' router_factory = mock.Mock() rap = RouterApplicationSession(session, router_factory) rap.send(message.Hello(u'realm', {u'caller': role.RoleCallerFeatures()})) session.reset_mock() rap.send(message.Goodbye(u'wamp.reason.logout', u'some custom message')) errors = self.flushLoggedErrors() self.assertEqual(1, len(errors)) self.assertEqual(the_exception, errors[0].value)
def test_wamp_session_on_leave(self): """ wamp.session.on_leave receives valid session_id """ router = mock.MagicMock() router.new_correlation_id = lambda: 'fake correlation id' class TestSession(RouterSession): def __init__(self, *args, **kw): super(TestSession, self).__init__(*args, **kw) # for this test, pretend we're connected (without # going through sending a Hello etc.) self._transport = mock.MagicMock() self._transport.get_channel_id = mock.MagicMock( return_value=b'deadbeef') self._session_id = 1234 self._router = router # normally done in Hello processing self._service_session = mock.MagicMock() router_factory = mock.MagicMock() session = TestSession(router_factory) goodbye = message.Goodbye('wamp.close.normal', 'hi there') self.assertFalse(session._goodbye_sent) # do the test; we should publish wamp.session.on_leave via the # service-session session.onMessage(goodbye) publishes = [ call for call in session._service_session.mock_calls if call[0] == 'publish' ] self.assertEqual(1, len(publishes)) call = publishes[0] self.assertEqual(call[0], "publish") self.assertEqual(call[1], ("wamp.session.on_leave", 1234))
def test_router_session_goodbye_custom_message(self): """ Reason should be propagated properly from Goodbye message """ from crossbar.router.session import RouterApplicationSession session = ApplicationSession() session.onLeave = mock.Mock() session._realm = 'realm' router = Router(factory=mock.Mock(), realm=RouterRealm( controller=None, id='realm', config=dict(name='realm'), )) rap = RouterApplicationSession(session, router) rap.send(message.Goodbye('wamp.reason.logout', 'some custom message')) leaves = session.onLeave.mock_calls self.assertEqual(1, len(leaves)) details = leaves[0][1][0] self.assertEqual('wamp.reason.logout', details.reason) self.assertEqual('some custom message', details.message)
def test_router_session_goodbye_fire_disconnect_error(self): """ Reason should be propagated properly from Goodbye message """ from crossbar.router.session import RouterApplicationSession session = mock.Mock() the_exception = RuntimeError("sad times at ridgemont high") def boom(*args, **kw): if args[0] == 'disconnect': return defer.fail(the_exception) return defer.succeed(None) session.fire = mock.Mock(side_effect=boom) session._realm = u'realm' router_factory = mock.Mock() rap = RouterApplicationSession(session, router_factory) rap.send(message.Hello(u'realm', {u'caller': role.RoleCallerFeatures()})) session.reset_mock() rap.send(message.Goodbye(u'wamp.reason.logout', u'some custom message')) errors = self.flushLoggedErrors() self.assertEqual(1, len(errors)) self.assertEqual(the_exception, errors[0].value)
def generate_test_messages(): """ List of WAMP test message used for serializers. Expand this if you add more options or messages. This list of WAMP message does not contain any binary app payloads! """ some_bytes = os.urandom(32) some_unicode = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' some_uri = 'com.myapp.foobar' some_unicode_uri = 'com.myapp.\u4f60\u597d\u4e16\u754c.baz' some_args = [1, 2, 3, 'hello', some_bytes, some_unicode, {'foo': 23, 'bar': 'hello', 'baz': some_bytes, 'moo': some_unicode}] some_kwargs = {'foo': 23, 'bar': 'hello', 'baz': some_bytes, 'moo': some_unicode, 'arr': some_args} msgs = [ message.Hello("realm1", {'subscriber': role.RoleSubscriberFeatures()}), message.Hello("realm1", {'publisher': role.RolePublisherFeatures()}), message.Hello("realm1", {'caller': role.RoleCallerFeatures()}), message.Hello("realm1", {'callee': role.RoleCalleeFeatures()}), message.Hello("realm1", { 'subscriber': role.RoleSubscriberFeatures(), 'publisher': role.RolePublisherFeatures(), 'caller': role.RoleCallerFeatures(), 'callee': role.RoleCalleeFeatures(), }), message.Goodbye(), message.Yield(123456), message.Yield(123456, args=some_args), message.Yield(123456, args=[], kwargs=some_kwargs), message.Yield(123456, args=some_args, kwargs=some_kwargs), message.Yield(123456, progress=True), message.Interrupt(123456), message.Interrupt(123456, mode=message.Interrupt.KILL), message.Invocation(123456, 789123), message.Invocation(123456, 789123, args=some_args), message.Invocation(123456, 789123, args=[], kwargs=some_kwargs), message.Invocation(123456, 789123, args=some_args, kwargs=some_kwargs), message.Invocation(123456, 789123, timeout=10000), message.Result(123456), message.Result(123456, args=some_args), message.Result(123456, args=[], kwargs=some_kwargs), message.Result(123456, args=some_args, kwargs=some_kwargs), message.Result(123456, progress=True), message.Cancel(123456), message.Cancel(123456, mode=message.Cancel.KILL), message.Call(123456, some_uri), message.Call(123456, some_uri, args=some_args), message.Call(123456, some_uri, args=[], kwargs=some_kwargs), message.Call(123456, some_uri, args=some_args, kwargs=some_kwargs), message.Call(123456, some_uri, timeout=10000), message.Call(123456, some_unicode_uri), message.Call(123456, some_unicode_uri, args=some_args), message.Call(123456, some_unicode_uri, args=[], kwargs=some_kwargs), message.Call(123456, some_unicode_uri, args=some_args, kwargs=some_kwargs), message.Call(123456, some_unicode_uri, timeout=10000), message.Unregistered(123456), message.Unregister(123456, 789123), message.Registered(123456, 789123), message.Register(123456, some_uri), message.Register(123456, some_uri, match='prefix'), message.Register(123456, some_uri, invoke='roundrobin'), message.Register(123456, some_unicode_uri), message.Register(123456, some_unicode_uri, match='prefix'), message.Register(123456, some_unicode_uri, invoke='roundrobin'), message.Event(123456, 789123), message.Event(123456, 789123, args=some_args), message.Event(123456, 789123, args=[], kwargs=some_kwargs), message.Event(123456, 789123, args=some_args, kwargs=some_kwargs), message.Event(123456, 789123, publisher=300), message.Published(123456, 789123), message.Publish(123456, some_uri), message.Publish(123456, some_uri, args=some_args), message.Publish(123456, some_uri, args=[], kwargs=some_kwargs), message.Publish(123456, some_uri, args=some_args, kwargs=some_kwargs), message.Publish(123456, some_uri, exclude_me=False, exclude=[300], eligible=[100, 200, 300]), message.Publish(123456, some_unicode_uri), message.Publish(123456, some_unicode_uri, args=some_args), message.Publish(123456, some_unicode_uri, args=[], kwargs=some_kwargs), message.Publish(123456, some_unicode_uri, args=some_args, kwargs=some_kwargs), message.Publish(123456, some_unicode_uri, exclude_me=False, exclude=[300], eligible=[100, 200, 300]), message.Unsubscribed(123456), message.Unsubscribe(123456, 789123), message.Subscribed(123456, 789123), message.Subscribe(123456, some_uri), message.Subscribe(123456, some_uri, match=message.Subscribe.MATCH_PREFIX), message.Subscribe(123456, some_unicode_uri), message.Subscribe(123456, some_unicode_uri, match=message.Subscribe.MATCH_PREFIX), message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri), message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=some_args), message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=[], kwargs=some_kwargs), message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=some_args, kwargs=some_kwargs), message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri), message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=some_args), message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=[], kwargs=some_kwargs), message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=some_args, kwargs=some_kwargs), message.Result(123456), message.Result(123456, args=some_args), message.Result(123456, args=some_args, kwargs=some_kwargs), ] return [(False, msg) for msg in msgs]
def onMessage(self, msg): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onMessage` """ if self._session_id is None: if not self._pending_session_id: self._pending_session_id = util.id() def welcome(realm, authid=None, authrole=None, authmethod=None, authprovider=None): self._session_id = self._pending_session_id self._pending_session_id = None self._goodbye_sent = False self._router = self._router_factory.get(realm) if not self._router: raise Exception("no such realm") self._authid = authid self._authrole = authrole self._authmethod = authmethod self._authprovider = authprovider roles = self._router.attach(self) msg = message.Welcome(self._session_id, roles, authid=authid, authrole=authrole, authmethod=authmethod, authprovider=authprovider) self._transport.send(msg) self.onJoin( SessionDetails(self._realm, self._session_id, self._authid, self._authrole, self._authmethod, self._authprovider)) ## the first message MUST be HELLO if isinstance(msg, message.Hello): self._realm = msg.realm details = types.HelloDetails(msg.roles, msg.authmethods, msg.authid, self._pending_session_id) d = self._as_future(self.onHello, self._realm, details) def success(res): msg = None if isinstance(res, types.Accept): welcome(self._realm, res.authid, res.authrole, res.authmethod, res.authprovider) elif isinstance(res, types.Challenge): msg = message.Challenge(res.method, res.extra) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) def failed(err): print(err.value) self._add_future_callbacks(d, success, failed) elif isinstance(msg, message.Authenticate): d = self._as_future(self.onAuthenticate, msg.signature, msg.extra) def success(res): msg = None if isinstance(res, types.Accept): welcome(self._realm, res.authid, res.authrole, res.authmethod, res.authprovider) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) def failed(err): print(err.value) self._add_future_callbacks(d, success, failed) elif isinstance(msg, message.Abort): ## fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) self._session_id = None self._pending_session_id = None #self._transport.close() else: raise ProtocolError( "Received {0} message, and session is not yet established". format(msg.__class__)) else: if isinstance(msg, message.Hello): raise ProtocolError( u"HELLO message received, while session is already established" ) elif isinstance(msg, message.Goodbye): if not self._goodbye_sent: ## the peer wants to close: send GOODBYE reply reply = message.Goodbye() self._transport.send(reply) ## fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) self._router.detach(self) self._session_id = None self._pending_session_id = None #self._transport.close() elif isinstance(msg, message.Heartbeat): pass ## FIXME else: self._router.process(self, msg)
def connectionLost(self, reason): if self._wamp_session: msg = message.Goodbye() self._wamp_session.onMessage(msg) del self._wamp_session
def onMessage(self, msg): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onMessage` """ if self._session_id is None: if not self._pending_session_id: self._pending_session_id = util.id() def welcome(realm, authid=None, authrole=None, authmethod=None, authprovider=None): self._session_id = self._pending_session_id self._pending_session_id = None self._goodbye_sent = False self._router = self._router_factory.get(realm) if not self._router: raise Exception("no such realm") self._authid = authid self._authrole = authrole self._authmethod = authmethod self._authprovider = authprovider roles = self._router.attach(self) msg = message.Welcome(self._session_id, roles, authid=authid, authrole=authrole, authmethod=authmethod, authprovider=authprovider) self._transport.send(msg) self.onJoin( SessionDetails(self._realm, self._session_id, self._authid, self._authrole, self._authmethod, self._authprovider)) # the first message MUST be HELLO if isinstance(msg, message.Hello): self._realm = msg.realm self._session_roles = msg.roles details = types.HelloDetails(msg.roles, msg.authmethods, msg.authid, self._pending_session_id) d = txaio.as_future(self.onHello, self._realm, details) def success(res): msg = None if isinstance(res, types.Accept): welcome(self._realm, res.authid, res.authrole, res.authmethod, res.authprovider) elif isinstance(res, types.Challenge): msg = message.Challenge(res.method, res.extra) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) txaio.add_callbacks(d, success, self._swallow_error_and_abort) elif isinstance(msg, message.Authenticate): d = txaio.as_future(self.onAuthenticate, msg.signature, {}) def success(res): msg = None if isinstance(res, types.Accept): welcome(self._realm, res.authid, res.authrole, res.authmethod, res.authprovider) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) txaio.add_callbacks(d, success, self._swallow_error_and_abort) elif isinstance(msg, message.Abort): # fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) self._session_id = None self._pending_session_id = None # self._transport.close() else: raise ProtocolError( "Received {0} message, and session is not yet established". format(msg.__class__)) else: if isinstance(msg, message.Hello): raise ProtocolError( u"HELLO message received, while session is already established" ) elif isinstance(msg, message.Goodbye): if not self._goodbye_sent: # The peer wants to close: answer with GOODBYE reply. # Note: We MUST NOT send any WAMP message _after_ GOODBYE reply = message.Goodbye() self._transport.send(reply) self._goodbye_sent = True else: # This is the peer's GOODBYE reply to our own earlier GOODBYE pass # We need to first detach the session from the router before # erasing the session ID below .. self._router.detach(self) # At this point, we've either sent GOODBYE already earlier, # or we have just responded with GOODBYE. In any case, we MUST NOT # send any WAMP message from now on: # clear out session ID, so that anything that might be triggered # in the onLeave below is prohibited from sending WAMP stuff. # E.g. the client might have been subscribed to meta events like # wamp.session.on_leave - and we must not send that client's own # leave to itself! self._session_id = None self._pending_session_id = None # fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) # don't close the transport, as WAMP allows to reattach a session # to the same or a different realm without closing the transport # self._transport.close() else: self._router.process(self, msg)
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) self._as_future(self.onJoin, details) elif isinstance(msg, message.Abort): ## fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) elif isinstance(msg, message.Challenge): challenge = types.Challenge(msg.method, msg.extra) d = self._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 self.onLeave(types.CloseDetails(reply.reason, reply.message)) self._add_future_callbacks(d, success, error) else: raise ProtocolError("Received {0} message, and session is not yet established".format(msg.__class__)) else: 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 self.onLeave(types.CloseDetails(msg.reason, msg.message)) ## consumer messages ## elif isinstance(msg, message.Event): if msg.subscription in self._subscriptions: handler = self._subscriptions[msg.subscription] if handler.details_arg: if not msg.kwargs: msg.kwargs = {} msg.kwargs[handler.details_arg] = types.EventDetails(publication = msg.publication, publisher = msg.publisher) try: if handler.obj: if msg.kwargs: if msg.args: handler.fn(handler.obj, *msg.args, **msg.kwargs) else: handler.fn(handler.obj, **msg.kwargs) else: if msg.args: handler.fn(handler.obj, *msg.args) else: handler.fn(handler.obj) else: if msg.kwargs: if msg.args: handler.fn(*msg.args, **msg.kwargs) else: handler.fn(**msg.kwargs) else: if msg.args: handler.fn(*msg.args) else: handler.fn() except Exception as e: if self.debug_app: print("Failure while firing event handler {0} subscribed under '{1}' ({2}): {3}".format(handler.fn, handler.topic, msg.subscription, e)) 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: d, opts = self._publish_reqs.pop(msg.request) p = Publication(msg.publication) self._resolve_future(d, p) 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: d, obj, fn, topic, options = self._subscribe_reqs.pop(msg.request) if options: self._subscriptions[msg.subscription] = Handler(obj, fn, topic, options.details_arg) else: self._subscriptions[msg.subscription] = Handler(obj, fn, topic) s = Subscription(self, msg.subscription) self._resolve_future(d, s) 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: d, subscription = self._unsubscribe_reqs.pop(msg.request) if subscription.id in self._subscriptions: del self._subscriptions[subscription.id] subscription.active = False self._resolve_future(d, None) 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 ## _, opts = self._call_reqs[msg.request] if opts.onProgress: try: if msg.kwargs: if msg.args: opts.onProgress(*msg.args, **msg.kwargs) else: opts.onProgress(**msg.kwargs) else: if msg.args: opts.onProgress(*msg.args) else: opts.onProgress() except Exception as e: ## silently drop exceptions raised in progressive results handlers if self.debug: print("Exception raised in progressive results handler: {0}".format(e)) else: ## silently ignore progressive results pass else: ## final result ## d, opts = self._call_reqs.pop(msg.request) if msg.kwargs: if msg.args: res = types.CallResult(*msg.args, **msg.kwargs) else: res = types.CallResult(**msg.kwargs) self._resolve_future(d, res) else: if msg.args: if len(msg.args) > 1: res = types.CallResult(*msg.args) self._resolve_future(d, res) else: self._resolve_future(d, msg.args[0]) else: self._resolve_future(d, 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: endpoint = self._registrations[msg.registration] if endpoint.options and endpoint.options.details_arg: if not msg.kwargs: msg.kwargs = {} 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 msg.kwargs[endpoint.options.details_arg] = types.CallDetails(progress, caller = msg.caller, caller_transport = msg.caller_transport, authid = msg.authid, authrole = msg.authrole, authmethod = msg.authmethod) if endpoint.obj: if msg.kwargs: if msg.args: d = self._as_future(endpoint.fn, endpoint.obj, *msg.args, **msg.kwargs) else: d = self._as_future(endpoint.fn, endpoint.obj, **msg.kwargs) else: if msg.args: d = self._as_future(endpoint.fn, endpoint.obj, *msg.args) else: d = self._as_future(endpoint.fn, endpoint.obj) else: if msg.kwargs: if msg.args: d = self._as_future(endpoint.fn, *msg.args, **msg.kwargs) else: d = self._as_future(endpoint.fn, **msg.kwargs) else: if msg.args: d = self._as_future(endpoint.fn, *msg.args) else: d = self._as_future(endpoint.fn) 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]) self._transport.send(reply) def error(err): 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) tb = tb.getvalue().splitlines() else: tb = None if self.debug_app: print("Failure while invoking procedure {0} registered under '{1}' ({2}):".format(endpoint.fn, endpoint.procedure, msg.registration)) print(err) 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, tb) self._transport.send(reply) self._invocations[msg.request] = d self._add_future_callbacks(d, 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: if self.debug: print("could not cancel call {0}".format(msg.request)) finally: del self._invocations[msg.request] elif isinstance(msg, message.Registered): if msg.request in self._register_reqs: d, obj, fn, procedure, options = self._register_reqs.pop(msg.request) self._registrations[msg.registration] = Endpoint(obj, fn, procedure, options) r = Registration(self, msg.registration) self._resolve_future(d, r) 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: d, registration = self._unregister_reqs.pop(msg.request) if registration.id in self._registrations: del self._registrations[registration.id] registration.active = False self._resolve_future(d, None) else: raise ProtocolError("UNREGISTERED received for non-pending request ID {0}".format(msg.request)) elif isinstance(msg, message.Error): d = None ## ERROR reply to PUBLISH ## if msg.request_type == message.Publish.MESSAGE_TYPE and msg.request in self._publish_reqs: d = self._publish_reqs.pop(msg.request)[0] ## ERROR reply to SUBSCRIBE ## elif msg.request_type == message.Subscribe.MESSAGE_TYPE and msg.request in self._subscribe_reqs: d = self._subscribe_reqs.pop(msg.request)[0] ## ERROR reply to UNSUBSCRIBE ## elif msg.request_type == message.Unsubscribe.MESSAGE_TYPE and msg.request in self._unsubscribe_reqs: d = self._unsubscribe_reqs.pop(msg.request)[0] ## ERROR reply to REGISTER ## elif msg.request_type == message.Register.MESSAGE_TYPE and msg.request in self._register_reqs: d = self._register_reqs.pop(msg.request)[0] ## ERROR reply to UNREGISTER ## elif msg.request_type == message.Unregister.MESSAGE_TYPE and msg.request in self._unregister_reqs: d = self._unregister_reqs.pop(msg.request)[0] ## ERROR reply to CALL ## elif msg.request_type == message.Call.MESSAGE_TYPE and msg.request in self._call_reqs: d = self._call_reqs.pop(msg.request)[0] if d: self._reject_future(d, 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)) elif isinstance(msg, message.Heartbeat): pass ## FIXME else: raise ProtocolError("Unexpected message {0}".format(msg.__class__))
def test_str(self): e = message.Goodbye(reason = u'wamp.error.system_shutdown', message = u'The host is shutting down now.') self.assertIsInstance(str(e), str)
def generate_test_messages(): """ List of WAMP test message used for serializers. Expand this if you add more options or messages. This list of WAMP message does not contain any binary app payloads! """ msgs = [ message.Hello(u"realm1", {u'subscriber': role.RoleSubscriberFeatures()}), message.Goodbye(), message.Yield(123456), message.Yield(123456, args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Yield(123456, args=[u'hello']), message.Yield(123456, progress=True), message.Interrupt(123456), message.Interrupt(123456, mode=message.Interrupt.KILL), message.Invocation(123456, 789123), message.Invocation(123456, 789123, args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Invocation(123456, 789123, timeout=10000), message.Result(123456), message.Result(123456, args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Result(123456, progress=True), message.Cancel(123456), message.Cancel(123456, mode=message.Cancel.KILL), message.Call(123456, u'com.myapp.procedure1'), message.Call(123456, u'com.myapp.procedure1', args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Call(123456, u'com.myapp.procedure1', timeout=10000), message.Unregistered(123456), message.Unregister(123456, 789123), message.Registered(123456, 789123), message.Register(123456, u'com.myapp.procedure1'), message.Register(123456, u'com.myapp.procedure1', match=u'prefix'), message.Register(123456, u'com.myapp.procedure1', invoke=u'roundrobin'), message.Event(123456, 789123), message.Event(123456, 789123, args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Event(123456, 789123, publisher=300), message.Published(123456, 789123), message.Publish(123456, u'com.myapp.topic1'), message.Publish(123456, u'com.myapp.topic1', args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Publish(123456, u'com.myapp.topic1', exclude_me=False, exclude=[300], eligible=[100, 200, 300]), message.Unsubscribed(123456), message.Unsubscribe(123456, 789123), message.Subscribed(123456, 789123), message.Subscribe(123456, u'com.myapp.topic1'), message.Subscribe(123456, u'com.myapp.topic1', match=message.Subscribe.MATCH_PREFIX), message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1'), message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1', args=[1, 2, 3], kwargs={ u'foo': 23, u'bar': u'hello' }), message.Call(123456, u'com.myapp.\u4f60\u597d\u4e16\u754c', args=[1, 2, 3]), message.Result(123456, args=[1, 2, 3], kwargs={ u'en': u'Hello World', u'jp': u'\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' }) ] return [(False, msg) for msg in msgs]
def onMessage(self, msg): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onMessage` """ if self._session_id is None: if not self._pending_session_id: self._pending_session_id = util.id() def welcome(realm, authid=None, authrole=None, authmethod=None, authprovider=None, authextra=None, custom=None): self._realm = realm self._session_id = self._pending_session_id self._pending_session_id = None self._goodbye_sent = False self._router = self._router_factory.get(realm) if not self._router: # should not arrive here raise Exception( "logic error (no realm at a stage were we should have one)" ) self._authid = authid self._authrole = authrole self._authmethod = authmethod self._authprovider = authprovider roles = self._router.attach(self) msg = message.Welcome(self._session_id, roles, realm=realm, authid=authid, authrole=authrole, authmethod=authmethod, authprovider=authprovider, authextra=authextra, custom=custom) self._transport.send(msg) self.onJoin( SessionDetails(self._realm, self._session_id, self._authid, self._authrole, self._authmethod, self._authprovider, self._authextra)) # the first message MUST be HELLO if isinstance(msg, message.Hello): self._session_roles = msg.roles details = types.HelloDetails( realm=msg.realm, authmethods=msg.authmethods, authid=msg.authid, authrole=msg.authrole, authextra=msg.authextra, session_roles=msg.roles, pending_session=self._pending_session_id) d = txaio.as_future(self.onHello, msg.realm, details) def success(res): msg = None if isinstance(res, types.Accept): custom = { # FIXME: # u'x_cb_node_id': self._router_factory._node_id u'x_cb_node_id': None } welcome(res.realm, res.authid, res.authrole, res.authmethod, res.authprovider, res.authextra, custom) elif isinstance(res, types.Challenge): msg = message.Challenge(res.method, res.extra) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) txaio.add_callbacks(d, success, self._swallow_error_and_abort) elif isinstance(msg, message.Authenticate): d = txaio.as_future(self.onAuthenticate, msg.signature, {}) def success(res): msg = None if isinstance(res, types.Accept): custom = { # FIXME: # u'x_cb_node_id': self._router_factory._node_id u'x_cb_node_id': None } welcome(res.realm, res.authid, res.authrole, res.authmethod, res.authprovider, res.authextra, custom) elif isinstance(res, types.Deny): msg = message.Abort(res.reason, res.message) else: pass if msg: self._transport.send(msg) txaio.add_callbacks(d, success, self._swallow_error_and_abort) elif isinstance(msg, message.Abort): # fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) self._session_id = None self._pending_session_id = None # self._transport.close() else: # raise ProtocolError(u"PReceived {0} message while session is not joined".format(msg.__class__)) # self.log.warn('Protocol state error - received {message} while session is not joined') # swallow all noise like still getting PUBLISH messages from log event forwarding - maybe FIXME pass else: if isinstance(msg, message.Hello): raise ProtocolError( u"HELLO message received, while session is already established" ) elif isinstance(msg, message.Goodbye): if not self._goodbye_sent: # The peer wants to close: answer with GOODBYE reply. # Note: We MUST NOT send any WAMP message _after_ GOODBYE reply = message.Goodbye() self._transport.send(reply) self._goodbye_sent = True else: # This is the peer's GOODBYE reply to our own earlier GOODBYE pass # We need to first detach the session from the router before # erasing the session ID below .. try: self._router.detach(self) except Exception: self.log.failure("Internal error") # In order to send wamp.session.on_leave properly # (i.e. *with* the proper session_id) we save it previous_session_id = self._session_id # At this point, we've either sent GOODBYE already earlier, # or we have just responded with GOODBYE. In any case, we MUST NOT # send any WAMP message from now on: # clear out session ID, so that anything that might be triggered # in the onLeave below is prohibited from sending WAMP stuff. # E.g. the client might have been subscribed to meta events like # wamp.session.on_leave - and we must not send that client's own # leave to itself! self._session_id = None self._pending_session_id = None # publish event, *after* self._session_id is None so # that we don't publish to ourselves as well (if this # session happens to be subscribed to wamp.session.on_leave) if self._service_session: self._service_session.publish( u'wamp.session.on_leave', previous_session_id, ) # fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) # don't close the transport, as WAMP allows to reattach a session # to the same or a different realm without closing the transport # self._transport.close() else: self._router.process(self, msg)
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): if not isinstance(signature, six.text_type): raise Exception('signature must be unicode') reply = message.Authenticate(signature) self._transport.send(reply) def error(err): self.onUserError(err, "Authentication failed") 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 or subscription.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, request.topic, 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: try: self.onUserError( txaio.create_failure(), "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 is not None: 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 = txaio.failure_message(err) try: self.onUserError(err, errmsg) except: pass formatted_tb = None if self.traceback_app: formatted_tb = txaio.failure_format_traceback( err) del self._invocations[msg.request] reply = self._message_from_exception( message.Invocation.MESSAGE_TYPE, msg.request, err.value, 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: # XXX can .cancel() return a Deferred/Future? try: self.onUserError( txaio.create_failure(), "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__))