From 7c264e7d852e58d52e389bf15a630c5f2757c956 Mon Sep 17 00:00:00 2001 From: Kasen IO Date: Mon, 15 Jun 2020 22:51:51 -0400 Subject: [PATCH] First pass at adding domain metadata exporter. --- .../resources/describe-settings.json | 26 +++++++++++++++- .../resources/metadata_exporter/index.html | 14 +++++++++ domain-server/src/DomainMetadata.cpp | 19 ++++++++++++ domain-server/src/DomainMetadata.h | 4 +++ domain-server/src/DomainServer.cpp | 31 +++++++++++++++++-- domain-server/src/DomainServer.h | 4 ++- libraries/networking/src/DomainHandler.h | 9 +++++- 7 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 domain-server/resources/metadata_exporter/index.html diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 284dd344e7..6dd8e64981 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -54,7 +54,23 @@ "default": true, "type": "checkbox", "advanced": true - } + }, + { + "name": "enable_metadata_exporter", + "label": "Enable Metadata HTTP Availability", + "help": "Allows your domain's metadata to be accessible on the public internet via direct HTTP connection to the domain server.", + "default": true, + "type": "checkbox", + "advanced": true + }, + { + "name": "metadata_exporter_port", + "label": "Metadata Exporter HTTP Port", + "help": "This is the port where the Metaverse exporter accepts connections. It listens both on IPv4 and IPv6 and can be accessed remotely, so you should make sure to restrict access with a firewall as needed.", + "default": "9704", + "type": "int", + "advanced": true + }, ] }, { @@ -210,6 +226,14 @@ "help": "Must match the password entered above for change to be saved.", "value-hidden": true }, + { + "name": "approved_safe_urls", + "label": "Approved Script and QML URLs", + "help": "These URLs will be sent to the Interface as safe URLs to allow through the whitelist if the Interface has this security option enabled.", + "placeholder": "0", + "default": "1", + "advanced": false + }, { "name": "maximum_user_capacity", "label": "Maximum User Capacity", diff --git a/domain-server/resources/metadata_exporter/index.html b/domain-server/resources/metadata_exporter/index.html new file mode 100644 index 0000000000..acc7aae23a --- /dev/null +++ b/domain-server/resources/metadata_exporter/index.html @@ -0,0 +1,14 @@ + + + Vircadia Metadata exporter + + + +

Vircadia Metadata exporter

+ +

If you can see this page, this means that your domain's metadata is available to be exported.

+

+ Metadata +

+ + diff --git a/domain-server/src/DomainMetadata.cpp b/domain-server/src/DomainMetadata.cpp index 2540858742..26dbc16184 100644 --- a/domain-server/src/DomainMetadata.cpp +++ b/domain-server/src/DomainMetadata.cpp @@ -4,6 +4,7 @@ // // Created by Zach Pomerantz on 5/25/2016. // Copyright 2016 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -14,10 +15,13 @@ #include #include #include +#include #include "DomainServer.h" #include "DomainServerNodeData.h" +Q_LOGGING_CATEGORY(domain_metadata_exporter, "hifi.domain_server.metadata_exporter") + const QString DomainMetadata::USERS = "users"; const QString DomainMetadata::Users::NUM_TOTAL = "num_users"; const QString DomainMetadata::Users::NUM_ANON = "num_anon_users"; @@ -215,3 +219,18 @@ void DomainMetadata::sendDescriptors() { #endif } } + +bool DomainMetadata::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { + const QString URI_METADATA = "/metadata"; + const QString EXPORTER_MIME_TYPE = "text/plain"; + + qCDebug(domain_metadata_exporter) << "Request on URL " << url; + + if (url.path() == URI_METADATA) { + QString domainMetadataJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(get(DESCRIPTORS)).toJson(QJsonDocument::Compact))); + connection->respond(HTTPConnection::StatusCode200, domainMetadataJSON.toUtf8(), qPrintable(EXPORTER_MIME_TYPE)); + return true; + } + + return false; +} diff --git a/domain-server/src/DomainMetadata.h b/domain-server/src/DomainMetadata.h index ed4e324464..85422692b9 100644 --- a/domain-server/src/DomainMetadata.h +++ b/domain-server/src/DomainMetadata.h @@ -15,6 +15,7 @@ #include #include +#include "HTTPManager.h" class DomainMetadata : public QObject { Q_OBJECT @@ -43,6 +44,9 @@ public: DomainMetadata(QObject* domainServer); DomainMetadata() = delete; + + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; + bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override; // Get cached metadata QJsonObject get(); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 49b319e31d..1f7df37fc6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -70,7 +70,6 @@ const QString DomainServer::REPLACEMENT_FILE_EXTENSION = ".replace"; const int MIN_PORT = 1; const int MAX_PORT = 65535; - int const DomainServer::EXIT_CODE_REBOOT = 234923; #if USE_STABLE_GLOBAL_SERVICES @@ -334,6 +333,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : _nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS); initializeExporter(); + initializeMetadataExporter(); } void DomainServer::parseCommandLine(int argc, char* argv[]) { @@ -427,6 +427,11 @@ DomainServer::~DomainServer() { _contentManager->aboutToFinish(); _contentManager->terminate(); } + + if (_httpMetadataExporterManager) { + _httpMetadataExporterManager->close(); + delete _httpMetadataExporterManager; + } if (_httpExporterManager) { _httpExporterManager->close(); @@ -3045,8 +3050,7 @@ void DomainServer::updateUpstreamNodes() { updateReplicationNodes(Upstream); } -void DomainServer::initializeExporter() -{ +void DomainServer::initializeExporter() { static const QString ENABLE_EXPORTER = "monitoring.enable_prometheus_exporter"; static const QString EXPORTER_PORT = "monitoring.prometheus_exporter_port"; @@ -3066,6 +3070,27 @@ void DomainServer::initializeExporter() } } +void DomainServer::initializeMetadataExporter() +{ + static const QString ENABLE_EXPORTER = "metaverse.enable_metadata_exporter"; + static const QString EXPORTER_PORT = "metaverse.metadata_exporter_port"; + + bool isMetadataExporterEnabled = _settingsManager.valueOrDefaultValueForKeyPath(ENABLE_EXPORTER).toBool(); + int metadataExporterPort = _settingsManager.valueOrDefaultValueForKeyPath(EXPORTER_PORT).toInt(); + + if (exporterPort < MIN_PORT || exporterPort > MAX_PORT) { + qCWarning(domain_server) << "Metadata exporter port " << metadataExporterPort << " is out of range."; + isMetadataExporterEnabled = false; + } + + qCDebug(domain_server) << "Setting up Metadata exporter."; + + if (isMetadataExporterEnabled && !_httpMetadataExporterManager) { + qCInfo(domain_server) << "Starting Metadata exporter on port " << metadataExporterPort; + _httpMetadataExporterManager = new HTTPManager(QHostAddress::Any, (quint16)metadataExporterPort, QString("%1/resources/metadata_exporter/").arg(QCoreApplication::applicationDirPath()), &_metadata); + } +} + void DomainServer::updateReplicatedNodes() { // Make sure we have downstream nodes in our list static const QString REPLICATED_USERS_KEY = "users"; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 7c0fa5fb15..0334404863 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -73,7 +73,6 @@ public: static int const EXIT_CODE_REBOOT; bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; - bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override; static const QString REPLACEMENT_FILE_EXTENSION; @@ -140,6 +139,7 @@ private slots: void updateDownstreamNodes(); void updateUpstreamNodes(); void initializeExporter(); + void initializeMetadataExporter(); void tokenGrantFinished(); void profileRequestFinished(); @@ -240,6 +240,8 @@ private: HTTPManager _httpManager; HTTPManager* _httpExporterManager { nullptr }; + HTTPManager* _httpMetadataExporterManager; + std::unique_ptr _httpsManager; QHash _allAssignments; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 178c56c34a..50ebc1edbc 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -72,7 +72,14 @@ const quint16 DOMAIN_SERVER_EXPORTER_PORT = .value("VIRCADIA_DOMAIN_SERVER_EXPORTER_PORT") .toUInt() : 9703; - + +const quint16 DOMAIN_SERVER_METADATA_EXPORTER_PORT = + QProcessEnvironment::systemEnvironment() + .contains("DOMAIN_SERVER_METADATA_EXPORTER_PORT") + ? QProcessEnvironment::systemEnvironment() + .value("DOMAIN_SERVER_METADATA_EXPORTER_PORT") + .toUInt() + : 9704; const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;