如何在线程的一堆函数中使用socketio.emit

时间:2019-02-17 20:51:49

标签: flask flask-socketio

我正在尝试使用Flask做某种状态机。当我的应用启动时,我启动一个后台任务,该任务以“ state_0()”函数开头,并依次跳转到其他函数“ state_1()”,然后依次跳转到“ state_2()”,然后返回到“ state_0()”。

此s0-> s1-> s2-> s0-> s1-> ...从一开始就一直在运行Web应用程序,并且我想做的事情一直是“ socketio.emit('refresh' ,状态)”,以便可以相应地更新FrontEnd。

为此,我使用了一个带有@ app.before_first_request的线程,该线程基本上是使用应用程序上下文运行“ state_0()”的。

问题是发射仅适用于state_0()函数。

我当前的代码可以简化如下:

myapp.py

nums=re.findall('[0-8]+',updatedStr)

myindex.html

from flask import Flask, render_template, current_app
from flask_socketio import SocketIO, emit
import threading
import time, json


DATA = {'state': '0'}
N = 5 # Fake pooling

# initialize Flask
app = Flask(__name__)
socketio = SocketIO(app)

def state_0():

    # Update DATA
    global DATA
    DATA['state'] = '0'

    socketio.emit('refresh', json.dumps(DATA), broadcast=True)

    print("State " + DATA['state'] + "!")
    # Dummy pooling simulation
    i = 0
    while i < N:
        print("Dummy workload " + DATA['state'] + "...")
        time.sleep(3)
        i += 1

    state_1()

def state_1():

    # Update DATA
    global DATA
    DATA['state'] = '1'

    socketio.emit('refresh', json.dumps(DATA), broadcast=True)

    print("State " + DATA['state'] + "!")
    # Dummy pooling simulation
    i = 0
    while i < N:
        print("Dummy workload " + DATA['state'] + "...")
        time.sleep(3)
        i += 1

    print("Alarm(s) detected!")
    state_2()


def state_2():
    # Update DATA
    global DATA
    DATA['state'] = '2'

    socketio.emit('refresh', json.dumps(DATA), broadcast=True)

    print("State " + DATA['state'] + "!")
    # Dummy pooling simulation
    i = 0
    while i < N:
        print("Dummy workload " + DATA['state'] + "...")
        time.sleep(3)
        i += 1

    state_0()


@app.before_first_request
def activate_job():
    def run_job():
        with app.app_context():
            state_0()

    thread = threading.Thread(target=run_job)
    thread.start()


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

# Every time Client refresh the web, we broadcast the current DATA
@socketio.on('connect')
def on_connect():
    print("[Server.on_connect]: A new connection!")
    emit('refresh', json.dumps(DATA), broadcast=True)


if __name__ == '__main__':
    socketio.run(app, debug=True)

我也尝试这样做:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>State Machine</title>
</head>

<body>
    <p>State machine...</p>

    <form action="">
        <input id ="s0" type="radio" name="state0"> State 0<br>
        <input id ="s1" type="radio" name="state1"> State 1<br>
        <input id ="s2" type="radio" name="state2"> State 2<br>
    </form>


    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

    <script type="text/javascript" charset="utf-8">

        var socket = io.connect('http://' + document.domain + ':' + location.port);
        // verify our websocket connection is established
        socket.on('connect', function () {
            console.log('Websocket connected!');
        });

        socket.on('refresh', function (DATA) {
            var DATA = JSON.parse(DATA);
            console.log('[refresh] Frontend has updated info! Now we are in state ' + DATA.state);
            console.log('[refresh] All variables are:'); 
            console.log(DATA);

            switch (DATA.state) {
                case '0':
                    document.getElementById('s2').checked = ""
                    document.getElementById('s0').checked = "checked"
                    break;
                case '1':
                    document.getElementById('s0').checked = ""
                    document.getElementById('s1').checked = "checked"
                    break;
                case '2':
                    document.getElementById('s1').checked = ""
                    document.getElementById('s2').checked = "checked"
                    break;
                default:
                // code block
            }

        });

    </script>

</body>

</html>

我曾在各处尝试过与app.app_context()一起使用,但仅与state_0()函数一起使用。

我希望我的问题清楚。请注意,我想使事情尽可能简单(这就是为什么我使用全局变量来保持状态,以及为什么不使用Celery运行后台任务的原因)。这不是用于生产。

希望有人可以提供帮助!

注意:要在ubuntu中测试此示例,请创建一个“ virtualenv env”,然后“ pip3 install flask flask-socketio eventlet”并运行“ python3 myapp.py”

0 个答案:

没有答案