jQuery and perl: progress bar based on state of “p

2019-05-23 06:12发布

I would like to build a small pipeline that allows the user to choose a file and then runs several scripts using this file as an input. As some of these scripts run for several minutes (exact time depends on the input file's size) I would like to show a progress bar that is based on how many scripts of this pipeline have been finished.

The problem is that I don't know how to update this progress bar based on the status of the pipeline and would appreciate some help with that. I show the files I use first and then explain the problem in more detail.

My html form:

<form action="main.pl" method="post" enctype="multipart/form-data">
        <input type="file" name="fileName" />
        <input type="submit" value="Analyze" />
</form>

The pipeline script main.pl:

#!/usr/bin/perl
use CGI;
use strict;
#use warnings;
my $q = CGI->new;

my $fileName = $q->param('fileName');

my $progressPerc = 0;
my $numJobs = 3; #in actual script much more
my $count = 1;

system('perl', './file1.pl', $fileName);
$progressPerc = $count/$numJobs*100;
#here I want to pass $progressPerc to the progress bar
$count += 1;

system('perl', './file2.pl', $fileName);
$progressPerc = $count/$numJobs*100;
#here I want to pass $progressPerc to the progress bar
$count += 1;

system('perl', './file3.pl', $fileName);
$progressPerc = $count/$numJobs*100;
#here I want to pass $progressPerc to the progress bar

I found a good working progress bar on http://jqueryui.com/progressbar/#label which looks as follows (I post the entire file although I would only need the .js-part):

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>http://jqueryui.com/progressbar/#label</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
    <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
    <script src="http://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>

    <style>
    .ui-progressbar {
        position: relative;
    }
    .progress-label {
         position: absolute;
         left: 50%;
         top: 4px;
         font-weight: bold;
         text-shadow: 1px 1px 0 #fff;
     }
     </style>
     <script>
     $(function() {
         var progressbar = $( "#progressbar" ),
         progressLabel = $( ".progress-label" );
         progressbar.progressbar({
         value: false,
         change: function() {
            progressLabel.text( progressbar.progressbar( "value" ) + "%" );
        },
        complete: function() {
             progressLabel.text( "Complete!" );
        }
     });
     function progress() {
         var val = progressbar.progressbar( "value" )  || 0;
         progressbar.progressbar( "value", val + 10 );
         if ( val < 99 ) {
             setTimeout( progress, 800 );
         }
     }
     setTimeout( progress, 2000 );
 });
 </script>
 </head>
 <body>
 <div id="progressbar"><div class="progress-label">Loading...</div></div>
 </body>
 </html>

Is there any easy way to pass $progressPerc from main.pl to the function progress() every time it changes its value? If there was only one call, this could be done using ajax, however, I don't know how to use ajax for several calls i.e. dynamically; by 'dynamic' I mean that once a perl script in main.pl is finished, this should be reported to the progress bar which is then updated.

If there is no easy way to do this: Can one somehow introduce an if clause that checks every x minutes (using setTimeout) whether the output files produced by these perl scripts in main.pl exist and if so, the progress bar is updated and if not one waits for longer? And if so, how would it be implemented?

1条回答
放我归山
2楼-- · 2019-05-23 06:24

Almost a month has passed since I asked this question but an answer did not appear. Therefore, I now post my one which is based on ThisSuitIsBlackNot's comment.

Although not that elaborated, it might serve as a minimal example on how one can connect Perl, HTML, Javascript/Ajax and JSON. Maybe it helps someone to get started with that topic.

If you want to run this code, just copy index.html file to your html directory (e.g. /var/www/html) and the perl scripts to your cgi-bin directory (e.g. /var/www/cgi-bin). Make sure to make these perl scripts executable! In my code below, the cgi directory is in /var/www/cgi-bin/ajax/stackCGI - please change that accordingly.

The status of the pipeline is written to a file which is then read in in 1 second intervals, the progress bar is updated and a message about the current status is displayed. The duration that the single steps in the pipeline take, is represented by the Perl's sleep function.

The files are given below.

Any comments and improvements are welcome!

index.html:

<!DOCTYPE html>
 <html>
    <head>
        <title>Test</title> 
        <meta charset='utf-8' />
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="http://code.jquery.com/ui/1.11.3/jquery-ui.js"></script>
        <style>
           .ui-progressbar {
               position: relative;
           }
           .progress-label {
              position: absolute;
              left: 50%;

              font-weight: bold;
              text-shadow: 1px 1px 0 #fff;
           }
        </style>
<script>
        var progressVal = 0;

        function get_progress() //get_progress();
        {   

            $.ajax({
                    type: 'POST',
                    url: '/cgi-bin/ajax/stackCGI/readFromFileJson.pl',

                    success: function( res ) {

                                                $('#progressPerc').append(' ' + res.progressSummary.progress);
                                                $('#progressMessage').html('status of pipeline: ' + res.progressSummary.progressMessage);
                                                $('.progress-label').html(res.progressSummary.progress + '%');
                                                progressVal = parseFloat(res.progressSummary.progress);
                                                $( "#progressbar" ).progressbar({
                                                    value: progressVal

                                                });

                                            }
            }); 
            if (progressVal < 100){ //pipeline has not finished yet
                setTimeout(get_progress, 1000); //call the function each second every second to get a status update
            }
            else { //pipeline has finished
                $('.progress-label').html('100%');
                alert("pipeline has finished! your results can be found in path/to/files. an e-mail has been sent to user@provider.com");
            }

        }
        function start_pipeline()
        {
            $.ajax({
                    type: 'POST',
                    url: '/cgi-bin/ajax/stackCGI/pipeline.pl',
                    data: { 'fileAnalysis': $('#myFile').val() },
                    success: function(res) {
                                                //add your success function here

                                            },
                    error: function() {alert("pipeline has not started!");}
            });


        }

    </script>
</head>
<body>

    file name: <input type='text' id='myFile'/>
    <button onclick='start_pipeline();get_progress();' >Analyze now</button>
    <div id="progressbar"><div class="progress-label"></div></div>
    <div id="progressMessage"></div>
    <div id="progressPerc">status of pipeline in percent (in this example the function get_progress is called every second): </div>

</body>

pipeline.pl:

#!/usr/bin/perl

use strict;
use warnings;

use CGI;
my $q = new CGI;

print $q->header('text/plain'); #needed! otherwise the ajax call in start_pipeline returns the error message

my $fileForAnalysis = $q -> param('fileAnalysis'); 

#create a file where the progress is reported to
#make sure you have the appropriate permissions to do this
my $filename = '/var/www/cgi-bin/ajax/stackCGI/progressReport.txt'; #change the directory!
my $fh; #file handler
my $number; #progress of pipeline in percent
my $message; #progress of pipeline

$number = 0;
$message = 'pipeline has startet successfully! Your file '.$fileForAnalysis.' is now processed.';
open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh $number."\t".$message;
close $fh;

sleep(3); #first program is running
$number = 10; #progress of pipeline in percent. as we have 4 programs in this pipeline it could also be 25 or whatever
$message = 'first program has finished';
open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh $number."\t".$message;
close $fh;

sleep(5); #second program is running
$number = 20;
$message = 'second program has finished';
open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh $number."\t".$message;
close $fh;

sleep(5); #third program is running
$number = 42;
$message = 'third program has finished';
open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh $number."\t".$message;
close $fh;

sleep(5); #fourth program is running
$number = 100;
$message = 'pipeline has finished';
open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh $number."\t".$message;
close $fh;

readFromFileJson.pl:

#!/usr/bin/perl

use strict;
use warnings;

use JSON;
use CGI;
my $q = new CGI;

#create a file where the progress is reported to
#make sure you have the appropriate permissions to do this 
my $filename = '/var/www/cgi-bin/ajax/stackCGI/progressReport.txt'; #change the directory!
open(my $fh, '<:encoding(UTF-8)', $filename) or die "Could not open file '$filename' $!";

print $q->header('application/json;charset=UTF-8'); #output will be returned in JSON format

my @progressReport = split(/\t/,<$fh>); #file is tab separated
my %progressHash;
$progressHash{"progress"} = $progressReport[0]; 
$progressHash{"progressMessage"} = $progressReport[1];

#convert hash to JSON format
my $op = JSON -> new -> utf8 -> pretty(1);
my $output = $op -> encode({
    progressSummary => \%progressHash
});
print $output;
查看更多
登录 后发表回答