232 lines
8.7 KiB
C++
232 lines
8.7 KiB
C++
|
#include "config.h"
|
||
|
|
||
|
#include <c++utilities/conversion/stringconversion.h>
|
||
|
|
||
|
#include <QFile>
|
||
|
#include <QJsonDocument>
|
||
|
#include <QJsonObject>
|
||
|
#include <QJsonArray>
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace ApplicationUtilities;
|
||
|
using namespace ConversionUtilities;
|
||
|
|
||
|
namespace PackageManagement {
|
||
|
|
||
|
/*!
|
||
|
* \class Alpm::Config
|
||
|
* \brief The ConfigArgs class bundles the command line arguments for the application.
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* \brief Initializes the command line arguments for the configuration of the application.
|
||
|
*/
|
||
|
ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||
|
helpArg(parser),
|
||
|
serverArg("server", "s", "runs a websocket server providing the web interface with information"),
|
||
|
repoindexConfArg("repoindex-conf", "c", "specifies the path of the repo index config file (default is /etc/repoindex.conf"),
|
||
|
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
||
|
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
||
|
pacmanConfArg("pacman-conf", "p", "specifies the path of the pacman config file (default is /etc/pacman.conf"),
|
||
|
websocketAddrArg("addr", "a", "specifies the listening address for the websocket server, default is 127.0.0.1"),
|
||
|
websocketPortArg("port", "p", "specifies the listening port for the websocket server, default is 1234"),
|
||
|
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
||
|
keyFileArg("key-file", string(), "specifies the private SSL key"),
|
||
|
insecureArg("insecure", string(), "forces the server to run in insecure mode")
|
||
|
{
|
||
|
initializer_list<string> pathValueName = {"path"};
|
||
|
serverArg.setDenotesOperation(true);
|
||
|
repoindexConfArg.setCombinable(true);
|
||
|
repoindexConfArg.setValueNames(pathValueName);
|
||
|
repoindexConfArg.setRequiredValueCount(1);
|
||
|
rootdirArg.setCombinable(true);
|
||
|
rootdirArg.setValueNames({"directory"});
|
||
|
rootdirArg.setRequiredValueCount(1);
|
||
|
dbpathArg.setCombinable(true);
|
||
|
dbpathArg.setValueNames(pathValueName);
|
||
|
dbpathArg.setRequiredValueCount(1);
|
||
|
pacmanConfArg.setCombinable(true);
|
||
|
pacmanConfArg.setValueNames(pathValueName);
|
||
|
pacmanConfArg.setRequiredValueCount(1);
|
||
|
websocketAddrArg.setCombinable(true);
|
||
|
websocketAddrArg.setValueNames({"IP address"});
|
||
|
websocketAddrArg.setRequiredValueCount(1);
|
||
|
websocketPortArg.setCombinable(true);
|
||
|
websocketPortArg.setValueNames({"port number"});
|
||
|
websocketPortArg.setRequiredValueCount(1);
|
||
|
certFileArg.setCombinable(true);
|
||
|
certFileArg.setValueNames(pathValueName);
|
||
|
certFileArg.setRequiredValueCount(1);
|
||
|
keyFileArg.setCombinable(true);
|
||
|
keyFileArg.setValueNames(pathValueName);
|
||
|
keyFileArg.setRequiredValueCount(1);
|
||
|
insecureArg.setCombinable(true);
|
||
|
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &insecureArg});
|
||
|
parser.setMainArguments({&serverArg, &repoindexConfArg, &helpArg});
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \class Alpm::Config
|
||
|
* \brief The Config class represents the configuration for the application.
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* \brief Creates the default configuration for the application.
|
||
|
*/
|
||
|
Config::Config() :
|
||
|
m_alpmRootDir(QStringLiteral("/")),
|
||
|
m_alpmDbPath(QStringLiteral("/var/lib/pacman/")),
|
||
|
m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")),
|
||
|
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
||
|
m_websocketServerListeningPort(1234),
|
||
|
m_serverInsecure(false),
|
||
|
m_reposFromPacmanConf(false)
|
||
|
{}
|
||
|
|
||
|
/*!
|
||
|
* \cond
|
||
|
*/
|
||
|
|
||
|
inline void assign(quint16 &num, const QJsonValue &val)
|
||
|
{
|
||
|
if(!val.isUndefined()) {
|
||
|
auto n = val.toInt(-1);
|
||
|
if(n > 0 && n <= static_cast<quint16>(-1)) {
|
||
|
num = static_cast<quint16>(n);
|
||
|
} else {
|
||
|
cerr << "Error: The specified value \"" << n << "\" is not a number." << endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void assign(QHostAddress &addr, const QString &val)
|
||
|
{
|
||
|
if(!val.isEmpty() && !addr.setAddress(val)) {
|
||
|
cerr << "Error: Unable to parse the specified host address \"" << val.toStdString() << "\"." << endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void assign(QString &str, const Argument &arg)
|
||
|
{
|
||
|
if(arg.isPresent()) {
|
||
|
str = QString::fromLocal8Bit(arg.values().front().data(), arg.values().front().size());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void assign(quint16 &num, const Argument &arg)
|
||
|
{
|
||
|
if(arg.isPresent()) {
|
||
|
try {
|
||
|
num = stringToNumber<quint16>(arg.values().front());
|
||
|
} catch(const ConversionException &) {
|
||
|
cerr << "Error: The specified argument value \"" << arg.values().front() << "\" is not a number." << endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void assign(bool &num, const Argument &arg)
|
||
|
{
|
||
|
num |= arg.isPresent();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \endcond
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* \brief Loads the configuration from the specified configuration file.
|
||
|
*/
|
||
|
void Config::loadFromConfigFile(const QString &configFilePath)
|
||
|
{
|
||
|
QFile file(configFilePath);
|
||
|
if(file.open(QFile::ReadOnly)) {
|
||
|
QJsonParseError error;
|
||
|
auto doc = QJsonDocument::fromJson(file.readAll(), &error);
|
||
|
if(error.error == QJsonParseError::NoError) {
|
||
|
auto mainObj = doc.object();
|
||
|
auto alpmObj = mainObj.value(QStringLiteral("alpm")).toObject();
|
||
|
m_alpmRootDir = alpmObj.value(QStringLiteral("rootDir")).toString(m_alpmRootDir);
|
||
|
m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath);
|
||
|
m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile);
|
||
|
auto serverObj = mainObj.value(QStringLiteral("server")).toObject();
|
||
|
assign(m_websocketServerListeningAddr, serverObj.value(QStringLiteral("websocketListeningAddr")).toString());
|
||
|
assign(m_websocketServerListeningPort, serverObj.value(QStringLiteral("websocketListeningPort")));
|
||
|
m_serverCertFile = serverObj.value(QStringLiteral("certFile")).toString(m_serverCertFile);
|
||
|
m_serverKeyFile = serverObj.value(QStringLiteral("keyFile")).toString(m_serverKeyFile);
|
||
|
m_serverInsecure = serverObj.value(QStringLiteral("insecure")).toBool(m_serverInsecure);
|
||
|
auto reposObj = mainObj.value(QStringLiteral("repos")).toObject();
|
||
|
m_reposFromPacmanConf = serverObj.value(QStringLiteral("fromPacmanConfig")).toBool(m_reposFromPacmanConf);
|
||
|
for(const auto &repo : reposObj.value(QStringLiteral("add")).toArray()) {
|
||
|
m_repoEntries << RepoEntry();
|
||
|
m_repoEntries.back().load(repo);
|
||
|
}
|
||
|
} else {
|
||
|
cerr << "Error: Unable to parse config file \"" << configFilePath.toLocal8Bit().data() << "\": "
|
||
|
<< error.errorString().toLocal8Bit().data() << endl;
|
||
|
}
|
||
|
} else {
|
||
|
cerr << "Error: Unable to open config file \"" << configFilePath.toLocal8Bit().data() << "\"." << endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \brief Loads the configuration from the configuration file.
|
||
|
*
|
||
|
* The config file is obtained from the specified config args. If no such argument is present,
|
||
|
* some default locations are checked.
|
||
|
*/
|
||
|
void Config::loadFromConfigFile(const ConfigArgs &args)
|
||
|
{
|
||
|
if(args.repoindexConfArg.isPresent()) {
|
||
|
loadFromConfigFile(QString::fromLocal8Bit(args.repoindexConfArg.values().front().data()));
|
||
|
return;
|
||
|
} else {
|
||
|
for(const auto &defaultPath : {QStringLiteral("./repoindex.conf"), QStringLiteral("/etc/repoindex.conf")}) {
|
||
|
if(QFile::exists(defaultPath)) {
|
||
|
loadFromConfigFile(defaultPath);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \brief Loads the config from the specified configuration arguments.
|
||
|
*/
|
||
|
void Config::loadFromArgs(const ConfigArgs &args)
|
||
|
{
|
||
|
assign(m_alpmRootDir, args.rootdirArg);
|
||
|
assign(m_alpmDbPath, args.dbpathArg);
|
||
|
assign(m_pacmanConfFile, args.pacmanConfArg);
|
||
|
assign(m_websocketServerListeningPort, args.websocketPortArg);
|
||
|
assign(m_serverCertFile, args.certFileArg);
|
||
|
assign(m_serverKeyFile, args.keyFileArg);
|
||
|
assign(m_serverInsecure, args.insecureArg);
|
||
|
if(args.websocketAddrArg.isPresent()) {
|
||
|
assign(m_websocketServerListeningAddr, QString::fromLocal8Bit(args.websocketAddrArg.values().front().data(), args.websocketAddrArg.values().front().size()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \brief Loads the values from the specified JSON value.
|
||
|
*/
|
||
|
void RepoEntry::load(const QJsonValue &jsonValue)
|
||
|
{
|
||
|
auto obj = jsonValue.toObject();
|
||
|
m_name = obj.value(QStringLiteral("name")).toString(m_name);
|
||
|
m_dbPath = obj.value(QStringLiteral("dbpath")).toString(m_dbPath);
|
||
|
m_srcPath = obj.value(QStringLiteral("srcpath")).toString(m_srcPath);
|
||
|
m_pkgPath = obj.value(QStringLiteral("pkgpath")).toString(m_pkgPath);
|
||
|
for(const auto &server : obj.value(QStringLiteral("servers")).toArray()) {
|
||
|
auto str = server.toString();
|
||
|
if(!str.isEmpty()) {
|
||
|
m_servers << str;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace Alpm
|
||
|
|