基於 flask 結合 Redis 的簡單聊天室

pardon110發表於2019-06-29

skills清單

  • SSE工作方式
  • Redis釋出訂閱功能
  • flask框架

效果

基於flask結合redis的簡單聊天室

程式碼

import datetime
import flask
import redis

app = flask.Flask('sse-chat')

# session cookie金鑰
app.secret_key = 'pardon110'

# 連線redis資料庫,預設是零號庫,可隨便更改
rds = redis.StrictRedis(host='127.0.0.1', port=6379, db=1)

# 訊息生成器
def event_stream():
    # 從資料庫連線上獲取釋出訂閱管理物件例項
    pub = rds.pubsub()
    # 在管理訂閱(建立通道)頻道
    pub.subscribe('chat')
    # 監聽頻道資訊
    for message in pub.listen():
        # print(type(message['data']), type(message), message)
        # 只響應訊息的(位元組),非位元組的int狀態碼物件直接忽略
        if isinstance(message['data'], bytes):
            # 轉為utf8字串,傳送 SSE(Server Send Event)協議格式的資料
            yield 'data: %s\n\n' % message['data'].decode()

# 首次訪問需要登入
@app.route('/login', methods=['GET', 'POST'])
def login():
    if flask.request.method == 'POST':
        flask.session['user'] = flask.request.form['user']
        return flask.redirect('/')
    return '<form action="" method="post">user: <input name="user">'

# 接收js傳送過來的訊息
@app.route('/post', methods=['POST'])
def post():
    # 獲取表單提交內容
    message = flask.request.form['message']
    user = flask.session.get('user', 'anonymous')
    now = datetime.datetime.now().replace(microsecond=0).time()
    # 通過頻道釋出訊息
    rds.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message))
    return flask.Response(status=204)

# 定義事件流介面,返回一個response
@app.route('/stream')
def stream():
    return flask.Response(event_stream(), mimetype="text/event-stream")

@app.route('/')
def home():
    # 強制使用者登入
    if 'user' not in flask.session:
        return flask.redirect('/login')
    return u"""
     <!doctype html>
        <title>chat</title>
        <meta charset="utf-8">
        <script src="http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
        <style>body { max-width: 500px; margin: auto; padding: 1em; background: black; color: #fff; }</style>
        <p><b>hi, %s!</b></p>
        <p>Message: <input id="in" placeholder="回車傳送訊息"/></p>
        <pre id="out"></pre>
        <script>
            function sse() {
                var source = new EventSource('/stream');
                var out = document.getElementById('out');
                source.onmessage = function(e) {
                    // XSS in chat is fun
                    out.innerHTML =  e.data + '\\n' + out.innerHTML;
                };
            }
            $('#in').keyup(function(e){
                if (e.keyCode == 13) {
                    $.post('/post', {'message': $(this).val()});
                    $(this).val('');
                }
            });
            sse();
        </script>
        """ % flask.session['user']

if __name__ == '__main__':
    app.debug = True
    # falsk1.0.2預設多執行緒開啟,預設埠是5000
    app.run()

相關文章