ashleysommer / sanic-plugin-toolkit

Easily create Plugins for Sanic!
MIT License
51 stars 9 forks source link

How to use with websocket blueprint? #8

Closed garyo closed 5 years ago

garyo commented 6 years ago

I'm trying to use the contextualize plugin to add a db engine to my app as in the example, and I have the plugin loading and registered using the before_server_start listener.

@contextualize.listener('before_server_start')
async def setup_db(app, loop, context):
    from sqlalchemy import create_engine
    shared_context = context.shared
    engine = create_engine(app.config.get('DB_URI'))
    shared_context['db'] = engine
    dbsessionmaker = sessionmaker(bind=engine)
    shared_context['dbsessionmaker'] = dbsessionmaker
    logger.debug(f'SPF: setup_db: db is {engine}, dbsession_factory is {dbsessionmaker}')

def register_spf(app): # called during app setup
    spf = SanicPluginsFramework(app)
    spf.register_plugin(contextualize)

I'm not clear on how to use contextualize with a websocket blueprint like this (in another file):

ws_bp = Blueprint('websocket_api', url_prefix='/websock/v1')

# later...
@ws_bp.websocket('/')
async def websock(request, ws):
    logger.info(f'Server got websock connection {ws}')
    socket = ClientSocket(ws)
    # ...
ashleysommer commented 6 years ago

Hi @garyo I think I see what you are asking, and yes it should be possible to do what you want. Quick question. Do you want to use the same contextualize context on the Blueprint as you are using on the Sanic App? Or a new/different context? Do you want to create a new dbsessionmaker for the blueprint, or use the same one you created in setup_db() when the app started?

garyo commented 6 years ago

I'd like to use the same contextualize context everywhere -- unless there's a good reason not to. The dbsessionmaker is global to the whole app, so it should be the same everywhere. I may create a dbsession (from the dbsessionmaker) on each request via middlewhere, but I haven't gotten that far yet. Still, that would be the same process for the blueprint as anywhere else.

ashleysommer commented 6 years ago

Ok. I see your issue. Unfortunately what seems like a pretty simple thing to do is actually not so simple.

There are three main problems here:

  1. The blueprint doesn't know which app it is registered to until after the sanic app has called register_blueprint().
  2. The sanic app that registers the blueprint may not even have SPF enabled and/or the contextualize plugin context registered. How would the blueprint access the apps contextualize shared context if the app doesn't have one?
  3. The blueprint may be registered against multiple sanic apps at the same time at runtime. How would the blueprint know which app's contextualize shared context to use?

It comes down to the fact that blueprints are reusable templates meant to be used on any sanic app and on multiple sanic apps. You can install SPF on the blueprint, and register the contextualize plugin on it, and use it the same as you would on a sanic app, but the shared context that you get will be a different shared context to the one your sanic app uses.

Do you have an example of how you would do this in Flask? I would think that Flask has some of these same limitations too?