繁体   English   中英

如何在 flask 通过 socketIO 执行任务时用一些更新更新 HTML 页面

[英]How to update the HTML page with some updates while flask is performing a task via socketIO

我有一个基本的 flask 脚本,它通过子进程在用户输入的 IP 上运行一个简单的 ping 命令。 然而 ping 持续了 3 个数据包,有没有办法让用户知道在他通过 flask 上的 socketIO 功能等待时进程正在进行?

现在为了让用户知道后台正在发生某些事情,我设置了setTimeout function 以按设定的时间间隔更改按钮文本。

问题是用来自服务器的内容更新此按钮文本,例如“正在处理... .. 运行 ping 到 $IP.. 通过 socketIO 收到了 $NUMBER 个数据包” ,这可能吗?

from flask import Flask,render_template,request,redirect,session
import subprocess
from flask_socketio import SocketIO
async_mode = None
app = Flask(__name__)
socket_ = SocketIO(app, async_mode=async_mode)


app.secret_key = "sdfwq34qweds"

@app.route('/')
@app.route('/home')
def home():
    return render_template('home.html',sync_mode=socket_.async_mode)

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

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

@app.route('/result' ,methods=['POST','GET'])
def result():
    if request.method == "POST":
        ip1=request.form.get('ip')
        ticket=request.form.get('tic')
        starttime=request.form.get('stime')
        endtime=request.form.get('etime')
        session["ip2"]=request.form.get('ip')
        session["ticket2"]=request.form.get('tic')
        session["starttime2"]=request.form.get('stime')
        session["endtime2"]=request.form.get('etime')
        output=subprocess.Popen(["/usr/bin/python3.8 /u0/sn/dev_scripts/process.py -i "+str(ip1)+" -t "+str(ticket)+" -f "+str(starttime)+" -e "+(endtime)],shell=True,stdout=subprocess.PIPE)
        output.wait()
        out=output.communicate()[0]
        ec=output.returncode
        return render_template('result.html',sync_mode=socket_.async_mode,out=out.decode())

if __name__ == '__main__':
    socket_.run(app,host='0.0.0.0',port=8080,debug=True)

我的主页.html页面

root@prod-nexus-app01:/u0/sn/dev_nexus# cat templates/home.html
{% extends 'architecture.html' %}
{% block title %}
<title>LaunchPad</title>
{% endblock %}

<body>
  {% block head %}
  <h1 class="display-1" style="text-align: center;">PING TESTER</h1>
  <blockquote class="blockquote">
  </blockquote>
  <figure style="text-align:center;">
    
  </figure>
  {% endblock %}

  {% block content %}
  <form id="nexus"  action="/result"  method="POST">
  <div class="form-floating mb-3 animate__animated animate__fadeInDown">
    <input type="integer"  name="ip" id='ipadd'  placeholder="8.8.8.8"  class="form-control" >
    <label for="ip">Machine IP</label>
  </div>
  <div class="form-group form-floating mb-3 animate__animated animate__fadeInDown">
    <input  class="form-control input-lg" type="datetimepicker"  required="required" placeholder="YYYY/MM/dd-hh:mm" id="fromdatetime"  name="stime" autocomplete="off">
    <label for="stime">Start Time</label>
    <script src="../static/js/flatpickr"></script>
    <script>
        $('#fromdatetime').flatpickr({
       //step:1,
        //format: 'Y/m/d-H:i',
        //maxTime: "now" ,
        //maxDate: "today",
        //minDate: new Date().setDate(new Date().getDate() - 2),
                    //defaultTime: '00:00',
       //altInput:true,
  enableTime: true,
        //showAlways: true,
        time_24hr: true,
        dateFormat: "d/m/Y/H:i",
        allowInput: true,
        //maxDate:"today",
       minuteIncrement:30,
       // minDate:new Date().setDate(new Date().getDate() - 2),
       });
 </script>
</div>

<div class="form-group form-floating mb-3 animate__animated animate__fadeInDown">
    <input  class="form-control input-lg" type="datetimepicker"  required="required" placeholder="YYYY/MM/dd-hh:mm" title="Ending Time-frame"   id="endtime"  name="etime" autocomplete="off">
  <label for="etime">End Time</label>
    <script type='text/JavaScript'>
              $('#endtime').flatpickr({
       //step:1,
        //format: 'Y/m/d-H:i',
        //maxTime: "now" ,
        //maxDate: "today",
        //minDate: new Date().setDate(new Date().getDate() - 2),
                    //defaultTime: '00:00',
        enableTime: true,
        showAlways: true,
        time_24hr: true,
        dateFormat: "d/m/Y/H:i",
        allowInput: true,
        //maxDate:"today",
        minuteIncrement:30,
      //  minDate:new Date().setDate(new Date().getDate() - 2),
       });
     </script>
  </div>
  <input  id= "submit_lead"   onClick = "changeText()"  type="submit" class="btn inputdisabled btn-dark animate__animated animate__fadeInDown" value="Execute ...">
<script>

### FOR NOW THIS WILL JUST UPDATE THE BUTTON TEXT ACCORDING TO TIME ELAPSED ###

 $(document).ready(function(e) {
  $('#nexus').submit(function() {
    var txt = $('#submit_lead');
    txt.val("Fetching logs...");
          setTimeout(function(){txt.val("Taking longer than 60s..")},60000)
    setTimeout(function(){txt.val("100 Secs elapsed, this may take a while ....")},100000)
          setTimeout(function(){txt.val("200s elapsed,This is taking longer than we thought ... ")},200000)
      setTimeout(function(){txt.val("300s elapsed,but we are still on it!")},300000)
      setTimeout(function(){txt.val("400s elapsed,hang tight!... ")},400000)
      setTimeout(function(){txt.val("500s elapsed,Either Slow speeds or large file size!... ")},500000)
      setTimeout(function(){txt.val("600s elapsed,Logs exceeding several Gigs")},600000)
      setTimeout(function(){txt.val("700s elapsed,likely an overloaded GHost")},700000)
      setTimeout(function(){txt.val("800s elapsed...Hold on")},800000)
      setTimeout(function(){txt.val("900s elapsed....")},900000)
  });
});
</script>
    </form>

  {% endblock %}

  </body>

要实时更新,您需要两件事:

  • 一种从子流程中增量获取信息的方法
  • 一种在子进程在服务器上继续时将更新推送到浏览器的方法

第一个要求可以通过打开子进程并使用迭代器从其标准输出读取而不是等待进程完成来实现。

第二个要求可以通过 websocket 来实现,它从服务器发出更新并在浏览器上捕获它们。

这是一个更简单的例子,但希望能给出一个想法。

服务器端代码:

from flask import Flask, render_template
from flask_socketio import SocketIO, emit, disconnect

import subprocess

async_mode = None

app = Flask(__name__)

socket_ = SocketIO(app, async_mode=async_mode)

@app.route('/')
def index():
    return render_template('index.html',
                           sync_mode=socket_.async_mode)

@socket_.on('do_task', namespace='/test')
def run_lengthy_task(data):
    try:
        proc = subprocess.Popen(['ping', '127.0.0.1', '-c', data['count']], bufsize=0, stdout=subprocess.PIPE)
        for line in iter(proc.stdout.readline, b''):
            emit('task_update', { 'data': line.decode('utf-8')[:-1] })
        proc.stdout.close()
        proc.wait()
        result = proc.returncode
        emit('task_done', {'result': result})
        disconnect()
    except Exception as ex:
        print(ex)

if __name__ == '__main__':
    socket_.run(app, host='0.0.0.0', port=80, debug=True)

客户端代码:

<!DOCTYPE HTML>
<html>
<head>
    <title>Long task</title>
    <script src="https://code.jquery.com/jquery-3.6.3.js"></script>
    <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
    <script type="text/javascript" charset="utf-8">
         $(document).on('click', '.widget input', function (event) {
            namespace = '/test';
            var socket = io(namespace);

            socket.on('connect', function() {
                $('#messages').append('<br/>' + $('<div/>').text('Requesting task to run').html());
                socket.emit('do_task', {count: '10'});
            });
            socket.on('task_update', function(msg, cb) {
                $('#messages').append('<br/>' + $('<div/>').text(msg.data).html());
                if (cb)
                    cb();
            });
            socket.on('task_done', function(msg, cb) {
                $('#messages').append('<br/>Result' + $('<div/>').text(msg.result).html());
                if (cb)
                    cb();
            });
            event.preventDefault();
        });
    </script>
</head>
<body>
    <div class="widget">
        <input type="submit" value="Click me" />
    </div>
    <h3>Messages</h3>
    <div id="messages" ></div>
</body>
</html>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM