2016-06-17 01:25:40 +02:00
|
|
|
#include <cassert>
|
|
|
|
#include <csignal>
|
|
|
|
#include <unistd.h>
|
2016-08-07 18:39:45 +02:00
|
|
|
|
|
|
|
#ifndef __APPLE__
|
|
|
|
/* prctl is Linux only */
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
2016-07-10 12:18:40 +02:00
|
|
|
#include <exception>
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QLocale>
|
|
|
|
#include <QFile>
|
2016-08-06 08:28:42 +02:00
|
|
|
#include <QString>
|
2016-09-17 00:40:29 +02:00
|
|
|
#include <QResource>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QStringList>
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
#include "HyperionConfig.h"
|
|
|
|
|
|
|
|
#include <utils/Logger.h>
|
2016-10-13 21:59:10 +02:00
|
|
|
#include <utils/FileUtils.h>
|
2016-06-20 23:41:07 +02:00
|
|
|
#include <webconfig/WebConfig.h>
|
2016-08-28 15:10:43 +02:00
|
|
|
#include <commandline/Parser.h>
|
|
|
|
#include <commandline/IntOption.h>
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
#include "hyperiond.h"
|
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
using namespace commandline;
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
void signal_handler(const int signum)
|
|
|
|
{
|
|
|
|
QCoreApplication::quit();
|
|
|
|
|
|
|
|
// reset signal handler to default (in case this handler is not capable of stopping)
|
|
|
|
signal(signum, SIG_DFL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void startNewHyperion(int parentPid, std::string hyperionFile, std::string configFile)
|
|
|
|
{
|
|
|
|
if ( fork() == 0 )
|
|
|
|
{
|
|
|
|
sleep(3);
|
|
|
|
execl(hyperionFile.c_str(), hyperionFile.c_str(), "--parent", QString::number(parentPid).toStdString().c_str(), configFile.c_str(), NULL);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2016-06-21 21:41:26 +02:00
|
|
|
// initialize main logger and set global log level
|
|
|
|
Logger* log = Logger::getInstance("MAIN");
|
2016-06-23 13:48:49 +02:00
|
|
|
Logger::setLogLevel(Logger::WARNING);
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
// Initialising QCoreApplication
|
|
|
|
QCoreApplication app(argc, argv);
|
|
|
|
|
|
|
|
signal(SIGINT, signal_handler);
|
|
|
|
signal(SIGTERM, signal_handler);
|
|
|
|
signal(SIGCHLD, signal_handler);
|
2016-07-18 09:23:55 +02:00
|
|
|
signal(SIGPIPE, signal_handler);
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
// force the locale
|
|
|
|
setlocale(LC_ALL, "C");
|
|
|
|
QLocale::setDefault(QLocale::c());
|
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
Parser parser("Hyperion Daemon");
|
|
|
|
parser.addHelpOption();
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-09-17 00:40:29 +02:00
|
|
|
BooleanOption & versionOption = parser.add<BooleanOption>(0x0, "version", "Show version information");
|
|
|
|
IntOption & parentOption = parser.add<IntOption> ('p', "parent", "pid of parent hyperiond"); // 2^22 is the max for Linux
|
|
|
|
BooleanOption & silentOption = parser.add<BooleanOption>('s', "silent", "do not print any outputs");
|
|
|
|
BooleanOption & verboseOption = parser.add<BooleanOption>('v', "verbose", "Increase verbosity");
|
|
|
|
BooleanOption & debugOption = parser.add<BooleanOption>('d', "debug", "Show debug messages");
|
|
|
|
Option & exportConfigOption = parser.add<Option> (0x0, "export-config", "export default config to file");
|
|
|
|
Option & exportEfxOption = parser.add<Option> (0x0, "export-effects", "export effects to given path");
|
|
|
|
|
2016-11-20 22:57:19 +01:00
|
|
|
parser.addPositionalArgument("config-files", QCoreApplication::translate("main", "Configuration file"), "config.file");
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
parser.process(app);
|
|
|
|
|
|
|
|
const QStringList configFiles = parser.positionalArguments();
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-06-23 13:48:49 +02:00
|
|
|
int logLevelCheck = 0;
|
2016-08-28 15:10:43 +02:00
|
|
|
if (parser.isSet(silentOption))
|
2016-06-23 13:48:49 +02:00
|
|
|
{
|
|
|
|
Logger::setLogLevel(Logger::OFF);
|
|
|
|
logLevelCheck++;
|
|
|
|
}
|
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
if (parser.isSet(verboseOption))
|
2016-06-23 13:48:49 +02:00
|
|
|
{
|
|
|
|
Logger::setLogLevel(Logger::INFO);
|
|
|
|
logLevelCheck++;
|
|
|
|
}
|
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
if (parser.isSet(debugOption))
|
2016-06-23 13:48:49 +02:00
|
|
|
{
|
|
|
|
Logger::setLogLevel(Logger::DEBUG);
|
|
|
|
logLevelCheck++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logLevelCheck > 1)
|
|
|
|
{
|
|
|
|
Error(log, "aborting, because options --silent --verbose --debug can't used together");
|
|
|
|
return 0;
|
|
|
|
}
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-08-28 15:10:43 +02:00
|
|
|
if (parser.isSet(versionOption))
|
2016-06-17 01:25:40 +02:00
|
|
|
{
|
|
|
|
std::cout
|
|
|
|
<< "Hyperion Ambilight Deamon (" << getpid() << ")" << std::endl
|
2016-06-24 23:22:31 +02:00
|
|
|
<< "\tVersion : " << HYPERION_VERSION << " (" << HYPERION_BUILD_ID << ")" << std::endl
|
2016-06-17 01:25:40 +02:00
|
|
|
<< "\tBuild Time: " << __DATE__ << " " << __TIME__ << std::endl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-17 00:40:29 +02:00
|
|
|
if (parser.isSet(exportEfxOption))
|
|
|
|
{
|
|
|
|
Q_INIT_RESOURCE(EffectEngine);
|
|
|
|
QDir directory(":/effects/");
|
|
|
|
QDir destDir(exportEfxOption.value(parser));
|
|
|
|
if (directory.exists() && destDir.exists())
|
|
|
|
{
|
|
|
|
std::cout << "extract to folder: " << std::endl;
|
2016-10-13 22:58:16 +02:00
|
|
|
QStringList filenames = directory.entryList(QStringList() << "*", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
2016-09-17 00:40:29 +02:00
|
|
|
foreach (const QString & filename, filenames)
|
|
|
|
{
|
|
|
|
if (QFile::exists(destDir.dirName()+"/"+filename))
|
|
|
|
{
|
|
|
|
QFile::remove(destDir.dirName()+"/"+filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "Extract: " << filename.toStdString() << " ... ";
|
|
|
|
if (QFile::copy(QString(":/effects/")+filename, destDir.dirName()+"/"+filename))
|
|
|
|
{
|
|
|
|
std::cout << "ok" << std::endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "error, aborting" << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Error(log, "can not export to %s",exportEfxOption.getCString(parser));
|
|
|
|
return 1;
|
|
|
|
}
|
2016-10-13 21:59:10 +02:00
|
|
|
|
2016-09-17 00:40:29 +02:00
|
|
|
|
2016-10-13 21:59:10 +02:00
|
|
|
bool exportDefaultConfig = false;
|
|
|
|
bool exitAfterexportDefaultConfig = false;
|
|
|
|
QString exportConfigFileTarget;
|
|
|
|
if (parser.isSet(exportConfigOption))
|
|
|
|
{
|
|
|
|
exportDefaultConfig = true;
|
|
|
|
exitAfterexportDefaultConfig = true;
|
|
|
|
exportConfigFileTarget = exportConfigOption.value(parser);
|
|
|
|
}
|
|
|
|
else if ( configFiles.size() > 0 && ! QFile::exists(configFiles[0]) )
|
|
|
|
{
|
|
|
|
exportDefaultConfig = true;
|
|
|
|
exportConfigFileTarget = configFiles[0];
|
|
|
|
Warning(log, "Your configuration file does not exist. hyperion writes default config");
|
|
|
|
}
|
2016-09-17 00:40:29 +02:00
|
|
|
|
2016-10-13 21:59:10 +02:00
|
|
|
if (exportDefaultConfig)
|
|
|
|
{
|
|
|
|
Q_INIT_RESOURCE(resource);
|
|
|
|
QDir().mkpath(FileUtils::getDirName(exportConfigFileTarget));
|
|
|
|
if (QFile::copy(":/hyperion_default.config",exportConfigFileTarget))
|
|
|
|
{
|
|
|
|
Info(log, "export complete.");
|
|
|
|
if (exitAfterexportDefaultConfig) return 0;
|
|
|
|
}
|
|
|
|
Error(log, "can not export to %s",exportConfigFileTarget.toLocal8Bit().constData());
|
|
|
|
if (exitAfterexportDefaultConfig) return 1;
|
|
|
|
}
|
|
|
|
|
2016-06-17 01:25:40 +02:00
|
|
|
if (configFiles.size() == 0)
|
|
|
|
{
|
2016-10-13 21:59:10 +02:00
|
|
|
Error(log, "Missing required configuration file. Usage: hyperiond <options ...> config.file");
|
2016-11-20 22:57:19 +01:00
|
|
|
parser.showHelp(0);
|
2016-06-17 01:25:40 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2016-10-13 21:59:10 +02:00
|
|
|
if (configFiles.size() > 1)
|
|
|
|
{
|
|
|
|
Warning(log, "You provided more than one config file. Hyperion will use only the first one");
|
|
|
|
}
|
2016-08-28 15:10:43 +02:00
|
|
|
|
|
|
|
int parentPid = parser.value(parentOption).toInt();
|
|
|
|
if (parentPid > 0 )
|
2016-06-17 01:25:40 +02:00
|
|
|
{
|
2016-08-28 15:10:43 +02:00
|
|
|
Info(log, "hyperiond client, parent is pid %d", parentPid);
|
2016-08-07 18:39:45 +02:00
|
|
|
#ifndef __APPLE__
|
2016-06-17 01:25:40 +02:00
|
|
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
2016-08-07 18:39:45 +02:00
|
|
|
#endif
|
2016-06-17 01:25:40 +02:00
|
|
|
}
|
2016-08-28 15:10:43 +02:00
|
|
|
|
2016-06-20 23:41:07 +02:00
|
|
|
HyperionDaemon* hyperiond = nullptr;
|
|
|
|
try
|
|
|
|
{
|
2016-10-13 21:59:10 +02:00
|
|
|
hyperiond = new HyperionDaemon(configFiles[0], &app);
|
2016-06-20 23:41:07 +02:00
|
|
|
hyperiond->run();
|
|
|
|
}
|
2016-07-10 12:18:40 +02:00
|
|
|
catch (std::exception& e)
|
2016-06-20 23:41:07 +02:00
|
|
|
{
|
2016-07-10 12:18:40 +02:00
|
|
|
Error(log, "Hyperion Daemon aborted:\n %s", e.what());
|
2016-06-20 23:41:07 +02:00
|
|
|
}
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-07-10 12:18:40 +02:00
|
|
|
int rc = 1;
|
|
|
|
WebConfig* webConfig = nullptr;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
webConfig = new WebConfig(&app);
|
|
|
|
// run the application
|
|
|
|
rc = app.exec();
|
|
|
|
Info(log, "INFO: Application closed with code %d", rc);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
Error(log, "Hyperion aborted:\n %s", e.what());
|
|
|
|
}
|
2016-06-17 01:25:40 +02:00
|
|
|
|
2016-06-21 21:41:26 +02:00
|
|
|
// delete components
|
2016-06-20 23:41:07 +02:00
|
|
|
delete webConfig;
|
2016-06-19 00:56:47 +02:00
|
|
|
delete hyperiond;
|
2016-06-21 21:41:26 +02:00
|
|
|
Logger::deleteInstance();
|
2016-06-17 01:25:40 +02:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|