crossbario / crossbar

Crossbar.io - WAMP application router
https://crossbar.io/
Other
2.05k stars 274 forks source link

Document mixing Twisted and asyncio in one app #1537

Open oberstet opened 5 years ago

oberstet commented 5 years ago

There are scenarios where one might want to run a mix of native asyncio-only libraries and Twisted-only features in one application - while using Autobahn.

In principle, there are 2 ways:

The latter doesn't exist as far as we know, but the former does, and it involves interop in 2 dimensions:

@meejah has an awesome blog post about this here https://meejah.ca/blog/python3-twisted-and-asyncio and @oddjobz wrote the following example - which also uses uvloop and scenic:

#!/usr/bin/env python3

import txaio
import asyncio
import uvloop
from twisted.internet import ssl, asyncioreactor
from autobahn.twisted.component import Component, run
from autobahn.wamp.types import RegisterOptions
from autobahn.twisted.websocket import WampWebSocketClientFactory
from sanic import Sanic
from sanic.response import json

loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
asyncioreactor.install(eventloop=loop)
from twisted.internet import reactor
txaio.config.loop = reactor

txaio.start_logging(level='info')
#
#   Ok, this was the bit that gave me a little trouble ...
#
WampWebSocketClientFactory.contextFactory = ssl.ClientContextFactory()

REALM = 'realm1'
TRANSPORT=[{
    'type' : 'websocket',
    'url': 'wss://xbr-fx-1.eu-west-2.crossbar.io/ws',
    'proxy': {
        'host' : '5.83.125.116',
        'port' : 8080
    },
}]

class Crossbar:

    _session = None
    _log = txaio.make_logger()

    @property
    def session(self):
        return self._session

    @property
    def crossbar(self):
        return self._crossbar

    def __init__(self):
        self._counter = 0
        self._crossbar = Component(transports=TRANSPORT, realm=REALM)
        self._crossbar.on("join", self.on_join)

    def on_join(self, session, details):
        self._log.info(f'Connected to Crossbar with authid "{details.authid}" on realm "{details.realm}"')
        self._session = session
        session.register(self.greeting, 'com.example.greeting', options=RegisterOptions(details_arg='details'))

    def greeting(self, name, details=None):
        self._counter += 1
        return {
            'name': name,
            'message': 'Hello, "{}"! (counter={})'.format(name, self._counter)
        }

app = Sanic()

@app.route('/')
async def test(request):
    return json({'hello': 'world'})

crossbar = Crossbar()
server = app.create_server(host="0.0.0.0", port=8087, return_asyncio_server=True)
asyncio.ensure_future(server)
run([crossbar.crossbar])
meejah commented 5 years ago

p.s. that can be RegisterOptions(details=True) now, which is the "preferred" way right?

meejah commented 5 years ago

Also, if we're going to put that example in the docs, the "proxy" stuff should be removed because it's not correct and there's bugs in autobahn using TLS with it, apparently.

oberstet commented 5 years ago
oddjobz commented 5 years ago

Re; RegisterOptions, yeah I was aware, it was a cut/paste. sorry .. Re; proxy / tls .. would be better (imo) to fix the AB/Component bug and leave the SSL in, minus my hack line ..

oberstet commented 5 years ago

@oddjobz re: RegisterOptions => fixed yesterday .. released on AB v19.3.2

meejah commented 5 years ago

the proxy bug is fixed here https://github.com/crossbario/autobahn-python/pull/1149 (but still, it might be more-clear to leave out the proxy stuff from an example?)