【问题标题】:Flask-SocketIO how to bridge communication of user with spawned process in event handlerFlask-SocketIO 如何在事件处理程序中桥接用户与衍生进程的通信
【发布时间】:2018-05-26 09:26:41
【问题描述】:

我的目标是在用户单击网页上的按钮后使用另一个 python 脚本(需要一些 shell 交互来输入身份验证代码)生成进程。

register.py 脚本有两种可能的 shell 结果,如果用户未通过身份验证,它会要求输入身份验证代码,或者只是以没有返回消息结束,表明用户已经通过身份验证。

到目前为止,我能够触发这个 register.py 文件,如果脚本是否要求验证码,则通过 socketio 发出返回状态并将其显示给用户,但我不知道,我应该如何接受用户在网页上输入的身份验证代码并再次将其加载到注册函数中,以防用户尚未通过身份验证?

代码:

Flask 应用文件 - 代码是稍微调整的 Flask-SocketIO 示例

from threading import Lock
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit, disconnect

import pexpect


async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()


def register(username, phone):
    child = pexpect.spawn('python3 register.py -u ' + username + ' -p ' + phone )
    i = child.expect(['Please enter the code .*', pexpect.EOF])
    socketio.emit('my_response', {'data': 'pexpect result ' + str(i) + ' ' + child.after.decode(), 'count': 55555}, namespace='/test')


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


@socketio.on("authenticate", namespace="/test")
def authenticate(message):
    global thread
    with thread_lock:
        if thread is None:
            thread = socketio.start_background_task(target=lambda: register("radicz", "+999999000999"))

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

HTML 文件

    <!DOCTYPE HTML>
<html>
<head>
    <title>Flask-SocketIO Test</title>
        <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

    <script type="text/javascript" charset="utf-8">
        $(document).ready(function() {
            // Use a "/test" namespace.
            // An application can open a connection on multiple namespaces, and
            // Socket.IO will multiplex all those connections on a single
            // physical channel. If you don't care about multiple channels, you
            // can set the namespace to an empty string.
            namespace = '/test';

            // Connect to the Socket.IO server.
            // The connection URL has the following format:
            //     http[s]://<domain>:<port>[/<namespace>]
            var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);


            // Event handler for new connections.
            // The callback function is invoked when a connection with the
            // server is established.
            socket.on('connect', function() {
                socket.emit('my_event', {data: 'I\'m connected!'});
            });

            $("#register").on("click", function(){
                socket.emit("authenticate", {data: "cislo + jmeno"})
                console.log("register fired!");
            });

            // Event handler for server sent data.
            // The callback function is invoked whenever the server emits data
            // to the client. The data is then displayed in the "Received"
            // section of the page.
            socket.on('my_response', function(msg) {
                $('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
            });


            // Handlers for the different forms in the page.
            // These accept data from the user and send it to the server in a
            // variety of ways
            $('form#emit').submit(function(event) {
                socket.emit('my_event', {data: $('#emit_data').val()});
                return false;
            });
            $('form#disconnect').submit(function(event) {
                socket.emit('disconnect_request');
                return false;
            });
        });
    </script>
</head>
<body>
    <h1>Flask-SocketIO Test</h1>
    <button id="register">register</button>
    <h2>Send:</h2>
    <form id="emit" method="POST" action='#'>
        <input type="text" name="emit_data" id="emit_data" placeholder="Message">
        <input type="submit" value="Echo">
    </form>
    <form id="disconnect" method="POST" action="#">
        <input type="submit" value="Disconnect">
    </form>
    <h2>Receive:</h2>
    <div id="log"></div>
</body>
</html>

所以问题是,如何获取用户提供的验证码并将其加载到注册函数中?我想我可以使用一些让步技术,比如如果需要从服务器端进行身份验证则发出,然后从客户端发出事件,这会再次触发后端的注册函数,但该函数将从上次产生的点继续,但我不知道如何正确地做到这一点,或者它是否可行的方法,或者我完全不知道,还有其他一些技术可以更容易地做到这一点?

编辑:或者this 是正确的方法?

【问题讨论】:

    标签: python-3.x flask flask-socketio


    【解决方案1】:

    我没有很好地测试它,但似乎在注册函数中添加另一个 socketio 事件处理程序有助于我的目的。

    def register(username, phone):
        child = pexpect.spawn('python3 register.py -u ' + username + ' -p ' + phone )
        i = child.expect(['Please enter the code .*', pexpect.EOF])
        socketio.emit('my_response', {'data': 'pexpect result ' + str(i) + ' ' + child.after.decode(), 'count': 55555}, namespace='/test')
    
        @socketio.on("another_event", namespace="/test")
        def another_callback(message):
            # actual code that I wanted to run
    

    【讨论】:

    • (请在单独的问题帖子中提出其他问题,谢谢。)
    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2022-12-16
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    相关资源
    最近更新 更多