mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
add a CL + JSON settings reader
This commit is contained in:
parent
080b0d7221
commit
c2ff438182
4 changed files with 181 additions and 134 deletions
|
@ -17,6 +17,7 @@
|
|||
#include <gnutls/dtls.h>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <HTTPConnection.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -47,7 +48,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
setApplicationName("domain-server");
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
_argumentList = arguments();
|
||||
_argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
if (optionallySetupDTLS()) {
|
||||
// we either read a certificate and private key or were not passed one, good to load assignments
|
||||
|
@ -132,14 +133,14 @@ bool DomainServer::optionallySetupDTLS() {
|
|||
}
|
||||
|
||||
bool DomainServer::readX509KeyAndCertificate() {
|
||||
const QString X509_CERTIFICATE_OPTION = "--cert";
|
||||
const QString X509_PRIVATE_KEY_OPTION = "--key";
|
||||
const QString X509_CERTIFICATE_OPTION = "cert";
|
||||
const QString X509_PRIVATE_KEY_OPTION = "key";
|
||||
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
|
||||
|
||||
int certIndex = _argumentList.indexOf(X509_CERTIFICATE_OPTION);
|
||||
int keyIndex = _argumentList.indexOf(X509_PRIVATE_KEY_OPTION);
|
||||
QString certPath = _argumentVariantMap.value(X509_CERTIFICATE_OPTION).toString();
|
||||
QString keyPath = _argumentVariantMap.value(X509_PRIVATE_KEY_OPTION).toString();
|
||||
|
||||
if (certIndex != -1 && keyIndex != -1) {
|
||||
if (!certPath.isEmpty() && !keyPath.isEmpty()) {
|
||||
// the user wants to use DTLS to encrypt communication with nodes
|
||||
// let's make sure we can load the key and certificate
|
||||
_x509Credentials = new gnutls_certificate_credentials_t;
|
||||
|
@ -148,8 +149,8 @@ bool DomainServer::readX509KeyAndCertificate() {
|
|||
QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
|
||||
|
||||
int gnutlsReturn = gnutls_certificate_set_x509_key_file2(*_x509Credentials,
|
||||
_argumentList[certIndex + 1].toLocal8Bit().constData(),
|
||||
_argumentList[keyIndex + 1].toLocal8Bit().constData(),
|
||||
certPath.toLocal8Bit().constData(),
|
||||
keyPath.toLocal8Bit().constData(),
|
||||
GNUTLS_X509_FMT_PEM,
|
||||
keyPassphraseString.toLocal8Bit().constData(),
|
||||
0);
|
||||
|
@ -162,7 +163,7 @@ bool DomainServer::readX509KeyAndCertificate() {
|
|||
|
||||
qDebug() << "Successfully read certificate and private key.";
|
||||
|
||||
} else if (certIndex != -1 || keyIndex != -1) {
|
||||
} else if (!certPath.isEmpty() || !keyPath.isEmpty()) {
|
||||
qDebug() << "Missing certificate or private key. domain-server will now quit.";
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
return false;
|
||||
|
@ -193,13 +194,11 @@ void DomainServer::processCreateResponseFromDataServer(const QJsonObject& jsonOb
|
|||
|
||||
void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||
|
||||
int argumentIndex = 0;
|
||||
|
||||
const QString CUSTOM_PORT_OPTION = "-p";
|
||||
const QString CUSTOM_PORT_OPTION = "port";
|
||||
unsigned short domainServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
|
||||
if ((argumentIndex = _argumentList.indexOf(CUSTOM_PORT_OPTION)) != -1) {
|
||||
domainServerPort = _argumentList.value(argumentIndex + 1).toUShort();
|
||||
if (_argumentVariantMap.contains(CUSTOM_PORT_OPTION)) {
|
||||
domainServerPort = (unsigned short) _argumentVariantMap.value(CUSTOM_PORT_OPTION).toUInt();
|
||||
}
|
||||
|
||||
unsigned short domainServerDTLSPort = 0;
|
||||
|
@ -207,21 +206,15 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
if (_isUsingDTLS) {
|
||||
domainServerDTLSPort = DEFAULT_DOMAIN_SERVER_DTLS_PORT;
|
||||
|
||||
const QString CUSTOM_DTLS_PORT_OPTION = "--dtlsPort";
|
||||
const QString CUSTOM_DTLS_PORT_OPTION = "dtls-port";
|
||||
|
||||
if ((argumentIndex = _argumentList.indexOf(CUSTOM_DTLS_PORT_OPTION)) != -1) {
|
||||
domainServerDTLSPort = _argumentList.value(argumentIndex + 1).toUShort();
|
||||
if (_argumentVariantMap.contains(CUSTOM_DTLS_PORT_OPTION)) {
|
||||
domainServerDTLSPort = (unsigned short) _argumentVariantMap.value(CUSTOM_DTLS_PORT_OPTION).toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
QSet<Assignment::Type> parsedTypes(QSet<Assignment::Type>() << Assignment::AgentType);
|
||||
parseCommandLineTypeConfigs(_argumentList, parsedTypes);
|
||||
|
||||
const QString CONFIG_FILE_OPTION = "--configFile";
|
||||
if ((argumentIndex = _argumentList.indexOf(CONFIG_FILE_OPTION)) != -1) {
|
||||
QString configFilePath = _argumentList.value(argumentIndex + 1);
|
||||
readConfigFile(configFilePath, parsedTypes);
|
||||
}
|
||||
parseAssignmentConfigs(parsedTypes);
|
||||
|
||||
populateDefaultStaticAssignmentsExcludingTypes(parsedTypes);
|
||||
|
||||
|
@ -240,130 +233,75 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
addStaticAssignmentsToQueue();
|
||||
}
|
||||
|
||||
void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes) {
|
||||
void DomainServer::parseAssignmentConfigs(QSet<Assignment::Type>& excludedTypes) {
|
||||
// check for configs from the command line, these take precedence
|
||||
const QString CONFIG_TYPE_OPTION = "--configType";
|
||||
int clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION);
|
||||
const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)";
|
||||
QRegExp assignmentConfigRegex(ASSIGNMENT_CONFIG_REGEX_STRING);
|
||||
|
||||
// enumerate all CL config overrides and parse them to files
|
||||
while (clConfigIndex != -1) {
|
||||
int clConfigType = argumentList.value(clConfigIndex + 1).toInt();
|
||||
if (clConfigType < Assignment::AllTypes && !excludedTypes.contains((Assignment::Type) clConfigIndex)) {
|
||||
Assignment::Type assignmentType = (Assignment::Type) clConfigType;
|
||||
createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType,
|
||||
argumentList.value(clConfigIndex + 2));
|
||||
excludedTypes.insert(assignmentType);
|
||||
// scan for assignment config keys
|
||||
QStringList variantMapKeys = _argumentVariantMap.keys();
|
||||
int configIndex = variantMapKeys.indexOf(assignmentConfigRegex);
|
||||
|
||||
while (configIndex != -1) {
|
||||
// figure out which assignment type this matches
|
||||
Assignment::Type assignmentType = (Assignment::Type) assignmentConfigRegex.cap().toInt();
|
||||
|
||||
QVariant mapValue = _argumentVariantMap[variantMapKeys[configIndex]];
|
||||
|
||||
if (mapValue.type() == QVariant::String) {
|
||||
QJsonDocument deserializedDocument = QJsonDocument::fromJson(mapValue.toString().toUtf8());
|
||||
createStaticAssignmentsForType(assignmentType, deserializedDocument.array());
|
||||
} else {
|
||||
createStaticAssignmentsForType(assignmentType, mapValue.toJsonArray());
|
||||
}
|
||||
|
||||
clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to read configuration from specified path
|
||||
// returns true on success, false otherwise
|
||||
void DomainServer::readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes) {
|
||||
if (path.isEmpty()) {
|
||||
// config file not specified
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QFile::exists(path)) {
|
||||
qWarning("Specified configuration file does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
QFile configFile(path);
|
||||
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning("Can't open specified configuration file!");
|
||||
return;
|
||||
} else {
|
||||
qDebug() << "Reading configuration from" << path;
|
||||
}
|
||||
|
||||
QTextStream configStream(&configFile);
|
||||
QByteArray configStringByteArray = configStream.readAll().toUtf8();
|
||||
QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object();
|
||||
configFile.close();
|
||||
|
||||
QSet<Assignment::Type> appendedExcludedTypes = excludedTypes;
|
||||
|
||||
foreach (const QString& rootStringValue, configDocObject.keys()) {
|
||||
int possibleConfigType = rootStringValue.toInt();
|
||||
excludedTypes.insert(assignmentType);
|
||||
|
||||
if (possibleConfigType < Assignment::AllTypes
|
||||
&& !excludedTypes.contains((Assignment::Type) possibleConfigType)) {
|
||||
// this is an appropriate config type and isn't already in our excluded types
|
||||
// we are good to parse it
|
||||
Assignment::Type assignmentType = (Assignment::Type) possibleConfigType;
|
||||
QString configString = readServerAssignmentConfig(configDocObject, rootStringValue);
|
||||
createStaticAssignmentsForTypeGivenConfigString(assignmentType, configString);
|
||||
|
||||
excludedTypes.insert(assignmentType);
|
||||
}
|
||||
configIndex = variantMapKeys.indexOf(assignmentConfigRegex);
|
||||
}
|
||||
}
|
||||
|
||||
// find assignment configurations on the specified node name and json object
|
||||
// returns a string in the form of its equivalent cmd line params
|
||||
QString DomainServer::readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName) {
|
||||
QJsonArray nodeArray = jsonObject[nodeName].toArray();
|
||||
|
||||
QStringList serverConfig;
|
||||
foreach (const QJsonValue& childValue, nodeArray) {
|
||||
QString cmdParams;
|
||||
QJsonObject childObject = childValue.toObject();
|
||||
QStringList keys = childObject.keys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
QString key = keys[i];
|
||||
QString value = childObject[key].toString();
|
||||
// both cmd line params and json keys are the same
|
||||
cmdParams += QString("--%1 %2 ").arg(key, value);
|
||||
}
|
||||
serverConfig << cmdParams;
|
||||
}
|
||||
|
||||
// according to split() calls from DomainServer::prepopulateStaticAssignmentFile
|
||||
// we shold simply join them with semicolons
|
||||
return serverConfig.join(';');
|
||||
}
|
||||
|
||||
void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment) {
|
||||
qDebug() << "Inserting assignment" << *newAssignment << "to static assignment hash.";
|
||||
_staticAssignmentHash.insert(newAssignment->getUUID(), SharedAssignmentPointer(newAssignment));
|
||||
}
|
||||
|
||||
void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString) {
|
||||
void DomainServer::createStaticAssignmentsForType(Assignment::Type type, const QJsonArray& configArray) {
|
||||
// we have a string for config for this type
|
||||
qDebug() << "Parsing command line config for assignment type" << type;
|
||||
|
||||
QStringList multiConfigList = configString.split(";", QString::SkipEmptyParts);
|
||||
int configCounter = 0;
|
||||
|
||||
const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*([\\w-]+)";
|
||||
QRegExp poolRegex(ASSIGNMENT_CONFIG_POOL_REGEX);
|
||||
|
||||
// read each config to a payload for this type of assignment
|
||||
for (int i = 0; i < multiConfigList.size(); i++) {
|
||||
QString config = multiConfigList.at(i);
|
||||
|
||||
// check the config string for a pool
|
||||
QString assignmentPool;
|
||||
|
||||
int poolIndex = poolRegex.indexIn(config);
|
||||
|
||||
if (poolIndex != -1) {
|
||||
assignmentPool = poolRegex.cap(1);
|
||||
foreach(const QJsonValue& jsonValue, configArray) {
|
||||
if (jsonValue.isObject()) {
|
||||
QJsonObject jsonObject = jsonValue.toObject();
|
||||
|
||||
// remove the pool from the config string, the assigned node doesn't need it
|
||||
config.remove(poolIndex, poolRegex.matchedLength());
|
||||
// check the config string for a pool
|
||||
const QString ASSIGNMENT_POOL_KEY = "pool";
|
||||
QString assignmentPool;
|
||||
|
||||
QJsonValue poolValue = jsonObject[ASSIGNMENT_POOL_KEY];
|
||||
if (!poolValue.isUndefined()) {
|
||||
assignmentPool = poolValue.toString();
|
||||
|
||||
jsonObject.remove(ASSIGNMENT_POOL_KEY);
|
||||
}
|
||||
|
||||
++configCounter;
|
||||
qDebug() << "Type" << type << "config" << configCounter << "=" << jsonObject;
|
||||
|
||||
Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool);
|
||||
|
||||
// setup the payload as a semi-colon separated list of key = value
|
||||
QStringList payloadStringList;
|
||||
foreach(const QString& payloadKey, jsonObject.keys()) {
|
||||
payloadStringList << QString("%1=%2").arg(payloadKey).arg(jsonObject[payloadKey].toString());
|
||||
}
|
||||
|
||||
configAssignment->setPayload(payloadStringList.join(';').toUtf8());
|
||||
|
||||
addStaticAssignmentToAssignmentHash(configAssignment);
|
||||
}
|
||||
|
||||
qDebug("Type %d config[%d] = %s", type, i, config.toLocal8Bit().constData());
|
||||
|
||||
Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool);
|
||||
|
||||
configAssignment->setPayload(config.toUtf8());
|
||||
|
||||
addStaticAssignmentToAssignmentHash(configAssignment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,11 +64,9 @@ private:
|
|||
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr,
|
||||
const NodeSet& nodeInterestList);
|
||||
|
||||
void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes);
|
||||
void readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes);
|
||||
QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName);
|
||||
void parseAssignmentConfigs(QSet<Assignment::Type>& excludedTypes);
|
||||
void addStaticAssignmentToAssignmentHash(Assignment* newAssignment);
|
||||
void createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString);
|
||||
void createStaticAssignmentsForType(Assignment::Type type, const QJsonArray& configArray);
|
||||
void populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes);
|
||||
|
||||
SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType);
|
||||
|
@ -85,7 +83,7 @@ private:
|
|||
QHash<QUuid, SharedAssignmentPointer> _staticAssignmentHash;
|
||||
QQueue<SharedAssignmentPointer> _assignmentQueue;
|
||||
|
||||
QStringList _argumentList;
|
||||
QVariantMap _argumentVariantMap;
|
||||
|
||||
bool _isUsingDTLS;
|
||||
gnutls_certificate_credentials_t* _x509Credentials;
|
||||
|
|
92
libraries/shared/src/HifiConfigVariantMap.cpp
Normal file
92
libraries/shared/src/HifiConfigVariantMap.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// HifiConfigVariantMap.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-04-08.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include "HifiConfigVariantMap.h"
|
||||
|
||||
QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) {
|
||||
|
||||
QVariantMap mergedMap;
|
||||
|
||||
// Add anything in the CL parameter list to the variant map.
|
||||
// Take anything with a dash in it as a key, and the values after it as the value.
|
||||
|
||||
const QString DASHED_KEY_REGEX_STRING = "(^-{1,2})([\\w-]+)";
|
||||
QRegExp dashedKeyRegex(DASHED_KEY_REGEX_STRING);
|
||||
|
||||
int keyIndex = argumentList.indexOf(dashedKeyRegex);
|
||||
int nextKeyIndex = 0;
|
||||
|
||||
// check if there is a config file to read where we can pull config info not passed on command line
|
||||
const QString CONFIG_FILE_OPTION = "--config";
|
||||
|
||||
while (keyIndex != -1) {
|
||||
if (argumentList[keyIndex] != CONFIG_FILE_OPTION) {
|
||||
// we have a key - look forward to see how many values associate to it
|
||||
QString key = dashedKeyRegex.cap(2);
|
||||
|
||||
nextKeyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1);
|
||||
|
||||
if (nextKeyIndex == keyIndex + 1) {
|
||||
// there's no value associated with this option, it's a boolean
|
||||
// so add it to the variant map with NULL as value
|
||||
mergedMap.insertMulti(key, QVariant());
|
||||
} else {
|
||||
int maxIndex = (nextKeyIndex == -1) ? argumentList.size() : nextKeyIndex;
|
||||
|
||||
// there's at least one value associated with the option
|
||||
// pull the first value to start
|
||||
QString value = argumentList[keyIndex + 1];
|
||||
|
||||
// for any extra values, append them, with a space, to the value string
|
||||
for (int i = keyIndex + 2; i < maxIndex; i++) {
|
||||
value += " " + argumentList[i];
|
||||
}
|
||||
|
||||
// add the finalized value to the merged map
|
||||
mergedMap.insert(key, value);
|
||||
}
|
||||
|
||||
keyIndex = nextKeyIndex;
|
||||
} else {
|
||||
keyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int configIndex = argumentList.indexOf(CONFIG_FILE_OPTION);
|
||||
|
||||
if (configIndex != -1) {
|
||||
// we have a config file - try and read it
|
||||
QString configFilePath = argumentList[configIndex + 1];
|
||||
QFile configFile(configFilePath);
|
||||
|
||||
if (configFile.exists()) {
|
||||
configFile.open(QIODevice::ReadOnly);
|
||||
|
||||
QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll());
|
||||
QJsonObject rootObject = configDocument.object();
|
||||
|
||||
// enumerate the keys of the configDocument object
|
||||
foreach(const QString& key, rootObject.keys()) {
|
||||
|
||||
if (!mergedMap.contains(key)) {
|
||||
// no match in existing list, add it
|
||||
mergedMap.insert(key, QVariant(rootObject[key]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mergedMap;
|
||||
}
|
19
libraries/shared/src/HifiConfigVariantMap.h
Normal file
19
libraries/shared/src/HifiConfigVariantMap.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// HifiConfigVariantMap.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-04-08.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__HifiConfigVariantMap__
|
||||
#define __hifi__HifiConfigVariantMap__
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
class HifiConfigVariantMap {
|
||||
public:
|
||||
static QVariantMap mergeCLParametersWithJSONConfig(const QStringList& argumentList);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__HifiConfigVariantMap__) */
|
Loading…
Reference in a new issue