LoginSignup
4
12

More than 3 years have passed since last update.

Flaskでwebsocketチャット

Posted at

https://github.com/zeekay/flask-uwsgi-websocket/tree/master/examples/chat-gevent
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/flexible/websockets
から書き直してみた。

GIF.gif

ファイルツリー

chat/
    ├ static/
    |    js/
    |      └ main.js
    ├ templates/
    |      └ index.html
    ├ chat.py    
    └ requirements.txt

ファイル

main.js
(function () {

    function showMessage(message) {
        $('#messages').append('<li>' + message)
    }

    if (!window.WebSocket) {
        if (window.MozWebSocket) {
            window.WebSocket = window.MozWebSocket;
        } else {
            showMessage("Your browser doesn't support WebSockets")
        }
    }

    let scheme = window.location.protocol === "https:" ? 'wss://' : 'ws://';
    let webSocketUri = scheme
        + window.location.hostname
        + (location.port ? ':' + location.port : '')
        + $SCRIPT_ROOT + '/websocket';
    let ws = new WebSocket(webSocketUri);

    ws.onopen = function (evt) {
        showMessage('Connected to chat.')
    }

    ws.onmessage = function (evt) {
        showMessage(evt.data)
    }

    ws.onclose = function (evt) {
        $('#messages').append('<li>WebSocket connection closed.</li>');
    }

    $('#send-message').on("submit", function () {
        let message = $('#name').val() + ": " + $('#message').val();
        showMessage(message)
        ws.send(message);
        $('#message').val('').trigger('focus');
        return false;
    });
}());
index.html
<!doctype html>
<head>
    <meta charset="utf-8"/>
    <title>WebSocket Chat Example</title>
    <style>
        li {
            list-style: none;
        }
    </style>
    <script type=text/javascript>
        $SCRIPT_ROOT =
        {{ request.script_root|tojson|safe }}
    </script>
</head>
<body>
<h2>WebSocket Chat Example</h2>
<form id="send-message">
    <input id="name" type="text" value="name">
    <input id="message" type="text" value="message"/>
    <input type="submit" value="Send"/>
</form>
<div id="messages"></div>
</body>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</html>
chat.py
import os
from collections import deque
from flask import Flask, render_template, url_for
from flask_uwsgi_websocket import GeventWebSocket

app = Flask(__name__)
ws = GeventWebSocket(app)
users = {}
backlog = deque(maxlen=10)


@app.context_processor
def override_url_for():
    return dict(url_for=dated_url_for)


def dated_url_for(endpoint, **values):
    if endpoint == 'static':
        filename = values.get('filename', None)
        if filename:
            file_path = os.path.join(app.root_path,
                                     endpoint, filename)
            values['q'] = int(os.stat(file_path).st_mtime)
    return url_for(endpoint, **values)


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


@ws.route('/websocket')
def chat(ws):
    users[ws.id] = ws

    for msg in backlog:
        ws.send(msg)

    while True:
        msg = ws.receive()
        if msg is None:
            break
        if msg == b"":
            continue

        backlog.append(msg)
        for id in users:
            if id != ws.id:
                users[id].send(msg)

    del users[ws.id]
    return


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8080, gevent=100)
requirements.txt
click==7.1.2
Flask==1.1.2
Flask-uWSGI-WebSocket==0.6.1
gevent==20.6.2
greenlet==0.4.16
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
uWSGI==2.0.19.1
Werkzeug==1.0.1
zope.event==4.4
zope.interface==5.1.0

インストール

$ python3 -m venv venv
$ source venv/bin/activate
$ pip install requirements.txt

実行

$ python chat.py
4
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
12