diff options
author | nachoparker <nacho@ownyourbits.com> | 2017-08-24 11:31:18 +0300 |
---|---|---|
committer | nachoparker <nacho@ownyourbits.com> | 2017-08-24 22:35:17 +0300 |
commit | f044c6d6b22885393b2f46477c88317fdf688994 (patch) | |
tree | f44901f1afa1a586233975b86137865aec528667 /ncp-web | |
parent | edccf4a7e196762dd973f3701e217c5f7d743eb3 (diff) |
ncp-web: use SSE to display process output in real time. Exit status green/redv0.24.2
Diffstat (limited to 'ncp-web')
-rw-r--r-- | ncp-web/green-circle.svg | 34 | ||||
-rw-r--r-- | ncp-web/index.php | 5 | ||||
-rw-r--r-- | ncp-web/ncp-launcher.php | 7 | ||||
-rw-r--r-- | ncp-web/ncp-output.php | 93 | ||||
-rw-r--r-- | ncp-web/ncp.css | 12 | ||||
-rw-r--r-- | ncp-web/ncp.js | 35 | ||||
-rw-r--r-- | ncp-web/red-circle.svg | 33 |
7 files changed, 213 insertions, 6 deletions
diff --git a/ncp-web/green-circle.svg b/ncp-web/green-circle.svg new file mode 100644 index 00000000..e82ffe38 --- /dev/null +++ b/ncp-web/green-circle.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + height="11.457627" + width="11.288136" + viewbox="0 0 599 599" + id="Green circle" + version="1.1"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <ellipse + ry="5.7288136" + rx="5.6440678" + cy="5.7288136" + cx="5.6440678" + style="fill:#339933;stroke-width:1.42157066" + id="green_circle" /> +</svg> diff --git a/ncp-web/index.php b/ncp-web/index.php index 65ceff78..7ddbed87 100644 --- a/ncp-web/index.php +++ b/ncp-web/index.php @@ -1,5 +1,5 @@ <!-- - NextcloudPi Web Panel javascript library + NextcloudPi Web Panel frontend Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> GPL licensed (see end of file) * Use at your own risk! @@ -20,7 +20,7 @@ session_start(); // security headers - header("Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';"); + header("Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; object-src 'self';"); header("X-XSS-Protection: 1; mode=block"); header("X-Content-Type-Options: nosniff"); header("X-Robots-Tag: none"); @@ -117,6 +117,7 @@ <div id="config-button-wrapper"> <button id="config-button">Run</button> <img id="loading-gif" src="loading-small.gif"> + <div id="circle-retstatus" class="icon-red-circle"></div> </div> </form> <textarea readonly id="details-box" rows="25" cols="60"></textarea> diff --git a/ncp-web/ncp-launcher.php b/ncp-web/ncp-launcher.php index 032b01ef..efb24761 100644 --- a/ncp-web/ncp-launcher.php +++ b/ncp-web/ncp-launcher.php @@ -11,6 +11,7 @@ include ('csrf.php'); session_start(); +ignore_user_abort( true ); if ( $_POST['action'] == "cfgreq" ) { @@ -97,9 +98,11 @@ else if ( $_POST['action'] == "launch" && $_POST['config'] ) // Get new token echo '{ "token": "' . getCSRFToken() . '",'; - echo ' "output": '; + echo ' "output": "" , '; + echo ' "ret": '; - echo json_encode( shell_exec( 'bash -c "sudo /home/www/ncp-launcher.sh ' . $file . '"' ) ) . ' }'; + exec( 'bash -c "sudo /home/www/ncp-launcher.sh ' . $file . '"' , $output , $ret ); + echo '"' . $ret . '" }'; } else if ( $_POST['action'] == "poweroff" ) diff --git a/ncp-web/ncp-output.php b/ncp-web/ncp-output.php new file mode 100644 index 00000000..750c71c6 --- /dev/null +++ b/ncp-web/ncp-output.php @@ -0,0 +1,93 @@ +<?php +/// +// Dispatcher of SSE events with the contents of the NCP log +// +// Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> +// GPL licensed (see end of file) * Use at your own risk! +// +// More at https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/ +/// + +header('Content-Type: text/event-stream; charset=utf-8'); +header('Cache-Control: no-cache'); // recommended to prevent caching of event data. + + +/** + * Constructs the SSE data format and flushes that data to the client. + * ( from html5rocks.com ) + * + * @param string $id Timestamp/id of this connection. + * @param string $msg Line of text that should be transmitted. + */ +function sendMsg($id, $msg) +{ + echo "id: $id" . PHP_EOL; + echo "data: $msg" . PHP_EOL; + echo PHP_EOL; + ob_flush(); + flush(); +} + +/** + * Pings the client-browser to force detection of closed socket + */ +function pingClient() +{ + echo ' '; + ob_flush(); + flush(); +} + +/** + * Imitates 'tail --follow' functionality, and sends lines as SSE events + * , while pinging browser to detect closed tab. + * ( based on stack overflow ) + */ +function follow($file) +{ + $size = 0; + while (true) + { + clearstatcache(); + $currentSize = filesize($file); + if ($size == $currentSize) + { + usleep(200000); // 0.2s + // if the user refreshes the tab >5 times, it won't load because it doesn't detect closed socket + // , and all workers are in use + pingClient(); + continue; + } + + $fh = fopen($file, "r"); + fseek($fh, $size); + + while ($line = fgets($fh)) + sendMsg( 'output' , $line ); + + fclose($fh); + $size = $currentSize; + } +} + +session_write_close(); +echo str_pad('',1024*1024*4); // make sure the browser buffer becomes full +follow( '/run/ncp.log' ); + +// License +// +// This script is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This script is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this script; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place, Suite 330, +// Boston, MA 02111-1307 USA +?> diff --git a/ncp-web/ncp.css b/ncp-web/ncp.css index 012721dc..b829eea7 100644 --- a/ncp-web/ncp.css +++ b/ncp-web/ncp.css @@ -1113,6 +1113,18 @@ select { background-image: url('poweroff.svg'); } +.icon-red-circle { + background-image: url('red-circle.svg'); + padding: 8px; + display: none; +} + +.icon-green-circle { + background-image: url('green-circle.svg'); + padding: 8px; +} + + #expand #expandDisplayName { padding: 8px; opacity: 0.6; diff --git a/ncp-web/ncp.js b/ncp-web/ncp.js index b200c8b0..707c2f6d 100644 --- a/ncp-web/ncp.js +++ b/ncp-web/ncp.js @@ -19,6 +19,25 @@ function errorMsg() $(function() { + // Event source to receive process output in real time + if (!!window.EventSource) + var source = new EventSource('ncp-output.php'); + else + $('#config-box-title').fill( "Browser not supported" ); + + source.addEventListener('message', function(e) + { + if ( e.origin != 'https://' + window.location.hostname + ':4443') + { + $('#details-box').fill( "Invalid origin" ); + return; + } + + var textarea = $('#details-box'); + textarea.fill( textarea.text() + e.data + '\n' ); + textarea[0].scrollTop = textarea[0].scrollHeight; + }, false); + // Show selected option configuration box $( 'li' , '#app-navigation' ).on('click', function(e) { @@ -38,6 +57,7 @@ $(function() var ret = $.parseJSON( result ); if ( ret.token ) $('#csrf-token').set( { value: ret.token } ); + $('#circle-retstatus').hide(); $('#config-box').ht( ret.output ); $('#config-box-title').fill( $( 'input' , '#' + selectedID ).get( '.value' ) ); $('#config-box-wrapper').show(); @@ -64,6 +84,11 @@ $(function() cfg[item.name] = item.value; } ); + // reset box + $('#details-box').fill(); + $('#details-box').show(); + $('#circle-retstatus').hide(); + // request $.request('post', 'ncp-launcher.php', { action:'launch', ref:selectedID , @@ -74,8 +99,14 @@ $(function() var ret = $.parseJSON( result ); if ( ret.token ) $('#csrf-token').set( { value: ret.token } ); - $('#details-box').fill(ret.output); - $('#details-box').show(); + if ( ret.ret ) // means that the process was launched + { + if ( ret.ret == '0' ) $('#circle-retstatus').set( '+icon-green-circle' ); + else $('#circle-retstatus').set( '-icon-green-circle' ); + $('#circle-retstatus').show(); + } + else // print error from server instead + $('#details-box').fill(ret.output); $('#config-button').set('@disabled',null); $('#loading-gif').hide(); confLock = false; diff --git a/ncp-web/red-circle.svg b/ncp-web/red-circle.svg new file mode 100644 index 00000000..acf7f898 --- /dev/null +++ b/ncp-web/red-circle.svg @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + height="11.118644" + width="11.118644" + viewbox="0 0 0 0" + id="Red circle" + version="1.1"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <circle + r="5.5593219" + cy="5.5593219" + cx="5.5593219" + style="fill:#ff0000;stroke-width:1.38983047" + id="red_circle" /> +</svg> |