implement hyperion restart via webui (#242)

* first try

* implement hyperion restart. core function is good, but needs a beeter structuring- something for next refactoring session ;-)

* several fixes (including osx)
merge with upstream
some refactoring

* add some eye candy to webui
This commit is contained in:
redPanther 2016-09-15 20:42:58 +02:00 committed by GitHub
parent a04f34eab7
commit eeb9b0f7da
33 changed files with 197 additions and 71 deletions

View File

@ -8,7 +8,7 @@
<hr> <hr>
<div class="col-lg-12"> <div class="col-lg-12">
<div id='editor_container'></div> <div id='editor_container'></div>
<button id='btn_submit'>Submit (console.log)</button> <button id='btn_submit' class="btn btn-danger">Submit - currently will destroy your config!</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -61,3 +61,7 @@ table.borderless td,table.borderless th{border: none !important;}
top: 0; top: 0;
z-index:99999; z-index:99999;
} }
#page-content {
padding-bottom:50px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -36,6 +36,11 @@
<script src="js/lib/jquery-lang.js" charset="utf-8" type="text/javascript"></script> <script src="js/lib/jquery-lang.js" charset="utf-8" type="text/javascript"></script>
<script src="js/lib/js.cookie.js"></script> <script src="js/lib/js.cookie.js"></script>
<!-- jquery ui -->
<link href="css/jquery-ui/jquery-ui.min.css" rel="stylesheet">
<link href="css/jquery-ui/jquery-ui.structure.min.css" rel="stylesheet">
<link href="css/jquery-ui/jquery-ui.theme.min.css" rel="stylesheet">
<script type="text/javascript"> <script type="text/javascript">
// Create language switcher instance // Create language switcher instance
var lang = new Lang(); var lang = new Lang();
@ -195,7 +200,7 @@
</ul> </ul>
<!-- /.navbar-top-left --> <!-- /.navbar-top-left -->
<div class="navbar-default sidebar" role="navigation"> <div id="main-nav" class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse"> <div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu"> <ul class="nav" id="side-menu">
<li> <a class="active" id="load_dashboard"><i class="fa fa-dashboard fa-fw"></i><span lang="en" data-lang-token="main_menu_dashboard_token">Dashboard</span></a> </li> <li> <a class="active" id="load_dashboard"><i class="fa fa-dashboard fa-fw"></i><span lang="en" data-lang-token="main_menu_dashboard_token">Dashboard</span></a> </li>
@ -225,10 +230,10 @@
<!-- Page Content --> <!-- Page Content -->
<div id="page-wrapper" style="padding-top:10px"> <div id="page-wrapper" style="padding-top:10px">
<div id="hyperion_restart_notify" class="alert alert-warning" style="display:none;padding:10px;margin:0"> <div id="hyperion_reload_notify" class="alert alert-warning" style="display:none;padding:10px;margin:0">
<div class="panel-danger" style="text-align:right"> <div class="panel-danger" style="text-align:right">
<div style="float:left">Hyperion Configuration is modified. To make it active, restart Hyperion.</div> <div style="float:left">Hyperion Configuration is modified. To make it active, restart Hyperion.</div>
<button id="btn_hyperion_restart" class="btn btn-danger">Restart Hyperion</button> <button id="btn_hyperion_reload" class="btn btn-danger">Restart Hyperion</button>
</div> </div>
</div> </div>
@ -264,6 +269,7 @@
<!-- Custom Theme JavaScript --> <!-- Custom Theme JavaScript -->
<script src="/js/lib/sb-admin-2.js"></script> <script src="/js/lib/sb-admin-2.js"></script>
<script src="/js/lib/jquery-ui.min.js"></script>
<script src="/js/content_index.js"></script> <script src="/js/content_index.js"></script>
</body> </body>

View File

@ -50,19 +50,19 @@ $(hyperion).one("cmd-config-getschema", function(event) {
schema: { schema: {
title:'', title:'',
properties: { properties: {
/*blackborderdetector, blackborderdetector,
color, color,
effects, effects,
forwarder, forwarder,
initialEffect, initialEffect,
kodiVideoChecker, kodiVideoChecker,
smoothing,*/ smoothing,
logger//, logger,
/*jsonServer, jsonServer,
protoServer, protoServer,
boblightServer, boblightServer,
udpListener, udpListener,
webConfig*/ webConfig
} }
} }
}); });
@ -74,10 +74,10 @@ $(hyperion).one("cmd-config-getschema", function(event) {
$('#editor_container h3').first().remove(); $('#editor_container h3').first().remove();
//Called everytime a Input Field is changed = No need for save button //Called everytime a Input Field is changed = No need for save button
general_conf_editor.off().on('change',function() { // general_conf_editor.off().on('change',function() {
console.log(JSON.stringify(general_conf_editor.getValue())); // console.log(JSON.stringify(general_conf_editor.getValue()));
requestWriteConfig(general_conf_editor.getValue()); // requestWriteConfig(general_conf_editor.getValue());
}); // });
//Alternative Function with submit button to get Values //Alternative Function with submit button to get Values
$('btn_submit').off().on('click',function() { $('btn_submit').off().on('click',function() {

View File

@ -1,4 +1,6 @@
$(document).ready( function() { $(document).ready( function() {
$("#main-nav").hide();
$("#page-content").hide();
$("#loading_overlay").addClass("overlay"); $("#loading_overlay").addClass("overlay");
loadContentTo("#container_connection_lost","connection_lost"); loadContentTo("#container_connection_lost","connection_lost");
initWebSocket(); initWebSocket();
@ -22,9 +24,9 @@ $(document).ready( function() {
cleanCurrentVersion = currentVersion.replace(/\./g, ''); cleanCurrentVersion = currentVersion.replace(/\./g, '');
if (parsedServerInfoJSON.info.hyperion[0].config_modified) if (parsedServerInfoJSON.info.hyperion[0].config_modified)
$("#hyperion_restart_notify").fadeIn("fast"); $("#hyperion_reload_notify").fadeIn("fast");
else else
$("#hyperion_restart_notify").fadeOut("fast"); $("#hyperion_reload_notify").fadeOut("fast");
// get active led device // get active led device
var leddevice = parsedServerInfoJSON.info.ledDevices.active; var leddevice = parsedServerInfoJSON.info.ledDevices.active;
@ -59,6 +61,9 @@ $(document).ready( function() {
} }
}); });
$("#loading_overlay").removeClass("overlay"); $("#loading_overlay").removeClass("overlay");
$("#main-nav").show('slide', {direction: 'left'}, 1000);
$("#page-content").show('slide', {direction: 'down'}, 2000);
}); // end cmd-serverinfo }); // end cmd-serverinfo
$(hyperion).one("cmd-config-getschema", function(event) { $(hyperion).one("cmd-config-getschema", function(event) {
@ -75,6 +80,13 @@ $(document).ready( function() {
requestServerInfo(); requestServerInfo();
}); });
$("#btn_hyperion_reload").on("click", function(){
$(hyperion).off();
requestServerConfigReload();
watchdog = 1;
$("#wrapper").fadeOut("slow");
cron();
});
}); });
$(function(){ $(function(){

View File

@ -0,0 +1 @@

View File

@ -1,6 +1,21 @@
var ledsCustomCfgInitialized = false; var ledsCustomCfgInitialized = false;
function get_hue_lights(){
$.ajax({
type: "GET",
url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/lights',
processData: false,
contentType: 'application/json',
success: function(r) {
for(var lightid in r){
//console.log(r[lightid].name);
$('#hue_lights').append('ID: '+lightid+' Name: '+r[lightid].name+'<br />');
}
}
});
}
$(document).ready(function() { $(document).ready(function() {
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -157,7 +172,7 @@ $(document).ready(function() {
if (isCurrentDevice) if (isCurrentDevice)
{ {
specificOptions_val = grabber_conf_editor.getEditor("root.specificOptions").getValue() specificOptions_val = grabber_conf_editor.getEditor("root.specificOptions").getValue()
for(var key in grabber_conf_editor.getEditor("root.specificOptions").getValue()){ for(var key in specificOptions_val){
values_specific[key] = (key in parsedConfJSON.device) ? parsedConfJSON.device[key] : specificOptions_val[key]; values_specific[key] = (key in parsedConfJSON.device) ? parsedConfJSON.device[key] : specificOptions_val[key];
}; };

View File

@ -155,6 +155,10 @@ function requestServerConfig() {
websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"getconfig"}'); websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"getconfig"}');
} }
function requestServerConfigReload() {
websocket.send('{"command":"config", "tan":'+wsTan+',"subcommand":"reload"}');
}
function requestLedColorsStart() { function requestLedColorsStart() {
ledStreamActive=true; ledStreamActive=true;
websocket.send('{"command":"ledcolors", "tan":'+wsTan+',"subcommand":"ledstream-start"}'); websocket.send('{"command":"ledcolors", "tan":'+wsTan+',"subcommand":"ledstream-start"}');
@ -197,18 +201,3 @@ function requestWriteConfig(config, create, overwrite)
var overwrite = (typeof overwrite !== 'undefined') ? overwrite : false; var overwrite = (typeof overwrite !== 'undefined') ? overwrite : false;
websocket.send('{"command":"config","subcommand":"setconfig", "tan":'+wsTan+', "config":'+JSON.stringify(config)+',"create":'+create+', "overwrite":'+overwrite+'}'); websocket.send('{"command":"config","subcommand":"setconfig", "tan":'+wsTan+', "config":'+JSON.stringify(config)+',"create":'+create+', "overwrite":'+overwrite+'}');
} }
function get_hue_lights(){
$.ajax({
type: "GET",
url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/lights',
processData: false,
contentType: 'application/json',
success: function(r) {
for(var lightid in r){
//console.log(r[lightid].name);
$('#hue_lights').append('ID: '+lightid+' Name: '+r[lightid].name+'<br />');
}
}
});
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@ function bindNavToContent(containerId, fileName, loadNow)
}); });
if (loadNow) if (loadNow)
{ {
$("#page-content").load("/content/"+fileName+".html"); $(containerId).trigger("click");
} }
} }

View File

@ -3,6 +3,6 @@
namespace FileUtils { namespace FileUtils {
std::string getBaseName( std::string sourceFile); std::string getBaseName( std::string sourceFile);
std::string command_exec(const char* cmd);
}; };

8
include/utils/Process.h Normal file
View File

@ -0,0 +1,8 @@
#include <string>
namespace Process {
void restartHyperion(bool asNewProcess=false);
std::string command_exec(const char* cmd);
};

View File

@ -657,24 +657,26 @@ unsigned Hyperion::getLedCount() const
bool Hyperion::configModified() bool Hyperion::configModified()
{ {
bool isModified = false;
QFile f(_configFile.c_str()); QFile f(_configFile.c_str());
if (f.open(QFile::ReadOnly)) if (f.open(QFile::ReadOnly))
{ {
QCryptographicHash hash(QCryptographicHash::Sha1); QCryptographicHash hash(QCryptographicHash::Sha1);
if (hash.addData(&f)) if (hash.addData(&f))
{
if (_configHash.size() == 0)
{ {
if (_configHash.size() == 0) _configHash = hash.result();
{
_configHash = hash.result();
qDebug(_configHash.toHex());
return false;
}
return _configHash != hash.result();
} }
else
{
isModified = _configHash != hash.result();
}
}
} }
f.close(); f.close();
return false; return isModified;
} }
void Hyperion::registerPriority(const std::string name, const int priority) void Hyperion::registerPriority(const std::string name, const int priority)

View File

@ -1057,7 +1057,15 @@
{ {
"paths" : "paths" :
{ {
"type" : "array" "type" : "array",
"title" : "List of folders to additional effects",
"propertyOrder" : 1
},
"disable" :
{
"type" : "array",
"title" : "List of disabled effects",
"propertyOrder" : 2
} }
}, },
"additionalProperties" : false "additionalProperties" : false

View File

@ -2,6 +2,7 @@
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#include <iomanip> #include <iomanip>
#include <unistd.h>
// stl includes // stl includes
#include <iostream> #include <iostream>
@ -15,6 +16,7 @@
#include <QHostInfo> #include <QHostInfo>
#include <QString> #include <QString>
#include <QFile> #include <QFile>
#include <QCoreApplication>
// hyperion util includes // hyperion util includes
#include <hyperion/ImageProcessorFactory.h> #include <hyperion/ImageProcessorFactory.h>
@ -27,6 +29,7 @@
#include <leddevice/LedDevice.h> #include <leddevice/LedDevice.h>
#include <HyperionConfig.h> #include <HyperionConfig.h>
#include <utils/jsonschema/JsonFactory.h> #include <utils/jsonschema/JsonFactory.h>
#include <utils/Process.h>
// project includes // project includes
#include "JsonClientConnection.h" #include "JsonClientConnection.h"
@ -883,6 +886,12 @@ void JsonClientConnection::handleConfigCommand(const Json::Value & message, cons
{ {
handleConfigSetCommand(message, full_command, tan); handleConfigSetCommand(message, full_command, tan);
} }
else if (subcommand == "reload")
{
// restart hyperion, this code must be put in some own class ...
Process::restartHyperion();
sendErrorReply("failed to restart hyperion", full_command, tan);
}
else else
{ {
sendErrorReply("unknown or missing subcommand", full_command, tan); sendErrorReply("unknown or missing subcommand", full_command, tan);

View File

@ -10,7 +10,7 @@
"subcommand": { "subcommand": {
"type" : "string", "type" : "string",
"required" : true, "required" : true,
"enum" : ["getconfig","setconfig","getschema"] "enum" : ["getconfig","setconfig","getschema","reload"]
}, },
"tan" : { "tan" : {
"type" : "integer" "type" : "integer"

View File

@ -54,6 +54,9 @@
"type" : "array", "type" : "array",
"propertyOrder" : 9, "propertyOrder" : 9,
"default" : [1.0,1.0,1.0], "default" : [1.0,1.0,1.0],
"maxItems" : 3,
"minItems" : 3,
"format" : "table",
"items" : { "items" : {
"type" : "number", "type" : "number",
"minimum" : 0.0, "minimum" : 0.0,

View File

@ -21,6 +21,8 @@ add_library(hyperion-utils
${CURRENT_HEADER_DIR}/Sleep.h ${CURRENT_HEADER_DIR}/Sleep.h
${CURRENT_HEADER_DIR}/FileUtils.h ${CURRENT_HEADER_DIR}/FileUtils.h
${CURRENT_SOURCE_DIR}/FileUtils.cpp ${CURRENT_SOURCE_DIR}/FileUtils.cpp
${CURRENT_HEADER_DIR}/Process.h
${CURRENT_SOURCE_DIR}/Process.cpp
${CURRENT_HEADER_DIR}/Logger.h ${CURRENT_HEADER_DIR}/Logger.h
${CURRENT_SOURCE_DIR}/Logger.cpp ${CURRENT_SOURCE_DIR}/Logger.cpp

View File

@ -1,10 +1,5 @@
#include <utils/FileUtils.h> #include <utils/FileUtils.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <QFileInfo> #include <QFileInfo>
namespace FileUtils { namespace FileUtils {
@ -15,21 +10,5 @@ std::string getBaseName( std::string sourceFile)
return fi.fileName().toStdString(); return fi.fileName().toStdString();
} }
std::string command_exec(const char* cmd)
{
char buffer[128];
std::string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (pipe)
{
while (!feof(pipe.get()))
{
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
}
return result;
}
}; };

57
libsrc/utils/Process.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <utils/Process.h>
#include <utils/Logger.h>
#include <QCoreApplication>
#include <QStringList>
#include <unistd.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
namespace Process {
void restartHyperion(bool asNewProcess)
{
Logger* log = Logger::getInstance("Process");
std::cout << std::endl
<< " *******************************************" << std::endl
<< " * hyperion will restart now *" << std::endl
<< " *******************************************" << std::endl << std::endl;
QStringList qargs = QCoreApplication::arguments();
int size = qargs.size();
char *args[size+1];
args[size] = nullptr;
for(int i=0; i<size; i++)
{
int str_size = qargs[i].toLocal8Bit().size();
args[i] = new char[str_size+1];
strncpy(args[i], qargs[i].toLocal8Bit().constData(),str_size );
args[i][str_size] = '\0';
}
execv(args[0],args);
Error(log, "error while restarting hyperion");
}
std::string command_exec(const char* cmd)
{
char buffer[128];
std::string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (pipe)
{
while (!feof(pipe.get()))
{
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
}
return result;
}
};

View File

@ -6,6 +6,7 @@
#include "CgiHandler.h" #include "CgiHandler.h"
#include "QtHttpHeader.h" #include "QtHttpHeader.h"
#include <utils/FileUtils.h> #include <utils/FileUtils.h>
#include <utils/Process.h>
CgiHandler::CgiHandler (Hyperion * hyperion, QString baseUrl, QObject * parent) CgiHandler::CgiHandler (Hyperion * hyperion, QString baseUrl, QObject * parent)
: QObject(parent) : QObject(parent)
@ -96,7 +97,7 @@ void CgiHandler::cmd_runscript(const QStringList & args, QtHttpReply * reply)
if (QFile::exists(scriptFilePath) && !interpreter.isEmpty()) if (QFile::exists(scriptFilePath) && !interpreter.isEmpty())
{ {
QByteArray data = FileUtils::command_exec(QString(interpreter + " " + scriptFilePath).toUtf8().constData()).c_str(); QByteArray data = Process::command_exec(QString(interpreter + " " + scriptFilePath).toUtf8().constData()).c_str();
reply->addHeader ("Content-Type", "text/plain"); reply->addHeader ("Content-Type", "text/plain");
reply->appendRawData (data); reply->appendRawData (data);

View File

@ -6,12 +6,12 @@
WebConfig::WebConfig(QObject * parent) WebConfig::WebConfig(QObject * parent)
: QObject(parent) : QObject(parent)
, _hyperion(Hyperion::getInstance()) , _hyperion(Hyperion::getInstance())
, _port(WEBCONFIG_DEFAULT_PORT)
, _server(nullptr) , _server(nullptr)
{ {
_baseUrl = WEBCONFIG_DEFAULT_PATH;
const Json::Value &config = _hyperion->getJsonConfig();
Logger* log = Logger::getInstance("WEBSERVER"); Logger* log = Logger::getInstance("WEBSERVER");
_port = WEBCONFIG_DEFAULT_PORT;
_baseUrl = WEBCONFIG_DEFAULT_PATH;
const Json::Value &config = _hyperion->getJsonConfig();
bool webconfigEnable = true; bool webconfigEnable = true;
@ -19,7 +19,7 @@ WebConfig::WebConfig(QObject * parent)
{ {
const Json::Value & webconfigConfig = config["webConfig"]; const Json::Value & webconfigConfig = config["webConfig"];
webconfigEnable = webconfigConfig.get("enable", true).asBool(); webconfigEnable = webconfigConfig.get("enable", true).asBool();
_port = webconfigConfig.get("port", WEBCONFIG_DEFAULT_PORT).asUInt(); _port = webconfigConfig.get("port", _port).asUInt();
_baseUrl = QString::fromStdString( webconfigConfig.get("document_root", _baseUrl.toStdString()).asString() ); _baseUrl = QString::fromStdString( webconfigConfig.get("document_root", _baseUrl.toStdString()).asString() );
} }