Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

meinheld websocket

こんにちわ、しのまりファンことmopemopeです。
meinheld 0.3よりwebsocketをサポートする予定です。

websocketはmiddleware経由で取得できます。
WebSocketMiddlewareを使うとenvironからwebsocketを取得できます。

シンプルなチャットはこんな感じ。
meinheld/websocket_chat_simple.py at dev · mopemope/meinheld · GitHub

import os
from meinheld import server, middleware, websocket

participants = set()

"""
@websocket.WebSocketWSGI
def handle(ws):
    participants.add(ws)
    try:
        while True:
            print "ws.wait()..."
            m = ws.wait()
            print "recv msg %s" % m
            if m is None:
                break
            for p in participants:
                print "send message %s" % m
                a = p.send(m)
                print "%s" % a
    finally:
        participants.remove(ws)
"""

def websocket_handle(environ, start_response):
    ws = environ.get('wsgi.websocket')
    participants.add(ws)
    try:
        while True:
            print "ws.wait()..."
            m = ws.wait()
            print "recv msg %s" % m
            if m is None:
                break
            for p in participants:
                print "send message %s" % m
                p.send(m)
    finally:
        participants.remove(ws)
    return [""]

def dispatch(environ, start_response):
    """Resolves to the web page or the websocket depending on the path."""
    if environ['PATH_INFO'] == '/chat':
        return websocket_handle(environ, start_response)
    else:
        print "/"
        start_response('200 OK', [('Content-Type', 'text/html'), ('Content-Length', '814')])
        ret = [open(os.path.join(
                     os.path.dirname(__file__), 
                     'templates/websocket_chat.html')).read()]
        return ret
        
if __name__ == "__main__":
    server.listen(("0.0.0.0", 8000))
    server.run(middleware.WebSocketMiddleware(dispatch))

chromeでしかテストしてないですが動作します。
eventletではdecoratorで指定するのですが、environに埋めたほうが使い勝手がよいだろうということでこうしています。

flask版
meinheld/websocket_chat.py at dev · mopemope/meinheld · GitHub

from flask import Flask, render_template, request
from meinheld import server, middleware

SECRET_KEY = 'development key'
DEBUG=True

app = Flask(__name__)
app.config.from_object(__name__)

participants = set()

@app.route('/')
def index():
    return render_template('websocket_chat.html')

@app.route('/chat')
def chat():
    print request.environ
    ws = request.environ.get('wsgi.websocket')
    participants.add(ws)
    try:
        while True:
            print "ws.wait()..."
            m = ws.wait()
            print "recv msg %s" % m
            if m is None:
                break
            for p in participants:
                print "send message %s" % m
                p.send(m)
    finally:
        participants.remove(ws)
    return ""

        
if __name__ == "__main__":
    server.listen(("0.0.0.0", 8000))
    server.run(middleware.WebSocketMiddleware(app))

非常にシンプルに書けますね。
既存のフレームワークにも簡単に組み込めるので便利です。