class WAMPApplication: def __init__(self, app, config): self.app = app self.wamp_session = None self.wamp_comp = Component(transports=config['router'], realm=config['realm']) self.wamp_comp.on('join', self.initialize) self.wamp_comp.on('leave', self.uninitialize) @to_deferred async def initialize(self, session, details): logger.info("Connected to WAMP router") self.wamp_session = session await session.register(self.app.list_units, 'sjw.list_units') await session.register(self.app.query, 'sjw.query') await session.register(self.app.start, 'sjw.start') await session.register(self.app.stop, 'sjw.stop') await session.register(self.app.enable, 'sjw.enable') await session.register(self.app.disable, 'sjw.disable') def uninitialize(self, session, reason): logger.info("%s %s", session, reason) logger.info("Lost WAMP connection") self.wamp_session = None def on_unit_changed(self, unit, props): if not self.wamp_session: return self.wamp_session.publish('sjw.unit.' + unit, props) @to_deferred async def start(self, reactor=None): logger.info("Starting component") return (await self.wamp_comp.start(reactor))
def test_successful_connect(self, fake_sleep): endpoint = Mock() joins = [] def joined(session, details): joins.append((session, details)) return session.leave() directlyProvides(endpoint, IStreamClientEndpoint) component = Component( transports={ "type": "websocket", "url": "ws://127.0.0.1/ws", "endpoint": endpoint, }) component.on('join', joined) def connect(factory, **kw): proto = factory.buildProtocol('ws://localhost/') transport = FakeTransport() proto.makeConnection(transport) from autobahn.websocket.protocol import WebSocketProtocol from base64 import b64encode from hashlib import sha1 key = proto.websocket_key + WebSocketProtocol._WS_MAGIC proto.data = (b"HTTP/1.1 101 Switching Protocols\x0d\x0a" b"Upgrade: websocket\x0d\x0a" b"Connection: upgrade\x0d\x0a" b"Sec-Websocket-Protocol: wamp.2.json\x0d\x0a" b"Sec-Websocket-Accept: " + b64encode(sha1(key).digest()) + b"\x0d\x0a\x0d\x0a") proto.processHandshake() from autobahn.wamp import role features = role.RoleBrokerFeatures( publisher_identification=True, pattern_based_subscription=True, session_meta_api=True, subscription_meta_api=True, subscriber_blackwhite_listing=True, publisher_exclusion=True, subscription_revocation=True, payload_transparency=True, payload_encryption_cryptobox=True, ) msg = Welcome(123456, dict(broker=features), realm='realm') serializer = JsonSerializer() data, is_binary = serializer.serialize(msg) proto.onMessage(data, is_binary) msg = Goodbye() proto.onMessage(*serializer.serialize(msg)) proto.onClose(True, 100, "some old reason") return succeed(proto) endpoint.connect = connect # XXX it would actually be nicer if we *could* support # passing a reactor in here, but the _batched_timer = # make_batched_timer() stuff (slash txaio in general) # makes this "hard". reactor = Clock() with replace_loop(reactor): yield component.start(reactor=reactor) self.assertTrue(len(joins), 1) # make sure we fire all our time-outs reactor.advance(3600)
def test_successful_connect(self, fake_sleep): endpoint = Mock() joins = [] def joined(session, details): joins.append((session, details)) return session.leave() directlyProvides(endpoint, IStreamClientEndpoint) component = Component( transports={ "type": "websocket", "url": "ws://127.0.0.1/ws", "endpoint": endpoint, } ) component.on('join', joined) def connect(factory, **kw): proto = factory.buildProtocol('boom') proto.makeConnection(Mock()) from autobahn.websocket.protocol import WebSocketProtocol from base64 import b64encode from hashlib import sha1 key = proto.websocket_key + WebSocketProtocol._WS_MAGIC proto.data = ( b"HTTP/1.1 101 Switching Protocols\x0d\x0a" b"Upgrade: websocket\x0d\x0a" b"Connection: upgrade\x0d\x0a" b"Sec-Websocket-Protocol: wamp.2.json\x0d\x0a" b"Sec-Websocket-Accept: " + b64encode(sha1(key).digest()) + b"\x0d\x0a\x0d\x0a" ) proto.processHandshake() from autobahn.wamp import role features = role.RoleBrokerFeatures( publisher_identification=True, pattern_based_subscription=True, session_meta_api=True, subscription_meta_api=True, subscriber_blackwhite_listing=True, publisher_exclusion=True, subscription_revocation=True, payload_transparency=True, payload_encryption_cryptobox=True, ) msg = Welcome(123456, dict(broker=features), realm=u'realm') serializer = JsonSerializer() data, is_binary = serializer.serialize(msg) proto.onMessage(data, is_binary) msg = Goodbye() proto.onMessage(*serializer.serialize(msg)) proto.onClose(True, 100, "some old reason") return succeed(proto) endpoint.connect = connect # XXX it would actually be nicer if we *could* support # passing a reactor in here, but the _batched_timer = # make_batched_timer() stuff (slash txaio in general) # makes this "hard". reactor = Clock() with replace_loop(reactor): yield component.start(reactor=reactor) self.assertTrue(len(joins), 1) # make sure we fire all our time-outs reactor.advance(3600)
def test_roundrobin_proxy(request, reactor, virtualenv): """ Confirm that a proxy with two connections does connections to both backends. Two nodes each with a router-worker for 'realm1' Each node rlink-connects to the other. One node has a proxy """ tempdir = _create_temp(request) # burn in hard-coded keys so we can refer to the public parts in # configs more easily. node_keys = [ (node0_pubkey, node0_privkey), (node1_pubkey, node1_privkey), (node2_pubkey, node2_privkey), (node3_pubkey, node3_privkey), ] for node_num in range(4): node_dir = join(tempdir, "node{}".format(node_num)) os.mkdir(node_dir) pub, priv = node_keys[node_num] with open(join(node_dir, "key.pub"), "w") as f: f.write(pub) with open(join(node_dir, "key.priv"), "w") as f: f.write(priv) # we start the nodes in parallel because we don't know which one # will "win" and connect first node_setup = [ (node0_config, join(tempdir, "node0")), (node1_config, join(tempdir, "node1")), (node2_config, join(tempdir, "node2")), (node3_config, join(tempdir, "node3")), ] node_starts = [] for node_config, node_dir in node_setup: node_d = start_node(request, reactor, virtualenv, node_config, node_dir) node_starts.append(node_d) print("-" * 80) print(node_starts) results = yield DeferredList(node_starts) print("-" * 80) print(results) print("-" * 80) nodes = [] for ok, res in results: if not ok: raise res nodes.append(res) protocol0, protocol1, protocol2, protocol3 = nodes print("Started rlink'd nodes:") print(" 0: {}".format(protocol0)) print(" 1: {}".format(protocol1)) print(" 2: {}".format(protocol2)) print(" 3: {}".format(protocol3)) print("-" * 80) # we could wait to see text of each node successfully connecting # to the other .. or we just wait a bit. yield sleep(5) subscribed_d = Deferred() rpc_call_d = Deferred() print("start alice") # run alice first alice = Component( transports=[ {"url": "ws://localhost:7070/ws", "type": "websocket"}, # proxy0 ], realm="realm1", ) @alice.on_join @inlineCallbacks def alice_join(session, details): print("\n\nalice joined\n") def a_thing(*args, **kw): print("received: a_thing: args={} kw={}".format(args, kw)) reactor.callLater(3, session.leave) yield session.subscribe(a_thing, "test.a_thing") def rpc(*args, **kw): print("call: rpc: args={} kw={}".format(args, kw)) reactor.callLater(1, rpc_call_d.callback, None) return "rpc return" yield session.register(rpc, "test.rpc") # XXX we don't know when the rlink registration goes all the way through... reactor.callLater(2.0, subscribed_d.callback, None) alice_done = alice.start(reactor) # wait until Alice actually subscribes (and thus is also registered) before starting bob yield subscribed_d print("alice is subscribed + registered") print("start bob") bob = Component( transports=[{ "url": "ws://localhost:7070/ws", # node0 XXX should be node1 "type": "websocket", }], realm="realm1", ) @bob.on_join @inlineCallbacks def bob_join(session, details): print("bob joined: PID={x_cb_pid}".format(**details.authextra)) print("publishing 'test.a_thing'") p = yield session.publish("test.a_thing", 3, 2, 1, options=types.PublishOptions(acknowledge=True)) print("published {}".format(p)) res = yield session.call("test.rpc", 1, 2, 3) print("test.rpc returned: {}".format(res)) reactor.callLater(2, session.leave) bob_done = bob.start(reactor) print("bob is starting", bob_done, alice_done) yield rpc_call_d yield bob_done yield alice_done # do a bunch of pubs in different sessions to prove we're hitting # different proxies and different router processes. received = [] connects = [] carol = Component( transports=[{ "url": "ws://*****:*****@carol.subscribe("multiverse", types.SubscribeOptions(details=True)) def _(*args, **kwargs): print("SUB: {}".format(kwargs.get('details', None))) received.append((args, kwargs)) carol_ready = Deferred() carol.on('ready', carol_ready.callback) carol.start() yield sleep(3) yield carol_ready GROUPS = 10 CONNECTS = 5 for g in range(GROUPS): group = [] for m in range(CONNECTS): client = Component( transports=[{ "url": "ws://localhost:7070/ws", # proxy0 "type": "websocket", }], realm="realm1", ) @client.on_join @inlineCallbacks def _(session, details): connects.append(details) yield session.publish( u"multiverse", group=g, member=m, options=types.PublishOptions(acknowledge=True) ) yield session.leave() group.append(client.start()) res = yield DeferredList(group) for ok, value in res: if not ok: raise value print("-" * 80) print("Received {} events".format(len(received))) for r in received: print(r[1]['details']) # some client should get each publish() that we sent # FIXME: AssertionError: assert 49 == (10 * 5) assert len(received) == GROUPS * CONNECTS print("-" * 80) # figure out which nodes and proxies we've contacted workers = set() proxies = set() for c in connects: workers.add(c.authextra['x_cb_worker']) proxies.add(c.authextra['x_cb_proxy_worker']) print(c.authextra['x_cb_worker']) print("workers: {}".format(workers)) print("proxies: {}".format(proxies)) print("-" * 80) assert workers == set([ "node0_worker0", "node1_worker0", "node2_worker0", "node3_worker0", ]) assert proxies == set(["node0_proxy0"])