From 783c61500e895b0d223754de28301314d0c1c2c1 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 24 Jul 2019 12:52:06 -0700 Subject: [PATCH 01/32] BUGZ-829 DEV-168 - domain backup/content management improvements BUGZ-829 - improve error reporting during restore of content DEV-168 - show last installed archive information --- .../resources/describe-settings.json | 23 ++++++ .../resources/web/content/js/content.js | 49 +++++++++++- .../resources/web/js/domain-server.js | 6 +- domain-server/resources/web/js/shared.js | 3 +- domain-server/src/AssetsBackupHandler.cpp | 32 +++++--- domain-server/src/AssetsBackupHandler.h | 2 +- domain-server/src/BackupHandler.h | 2 +- .../src/ContentSettingsBackupHandler.cpp | 54 ++++++++++--- .../src/ContentSettingsBackupHandler.h | 2 +- .../src/DomainContentBackupManager.cpp | 78 ++++++++++++++++--- .../src/DomainContentBackupManager.h | 8 +- domain-server/src/DomainServer.cpp | 27 +++---- domain-server/src/DomainServer.h | 1 + .../src/DomainServerSettingsManager.h | 3 + domain-server/src/EntitiesBackupHandler.cpp | 29 ++++--- domain-server/src/EntitiesBackupHandler.h | 2 +- 16 files changed, 251 insertions(+), 70 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 488b2091f3..cbbcdb399e 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1788,6 +1788,29 @@ "default": false } ] + }, + { + "name": "installed_archive", + "label": "Installed Archive", + "hidden": true, + "settings": [ + { + "name": "filename", + "content_setting": true, + "default": "" + }, + { + "name": "install_time", + "type": "int", + "content_setting": true, + "default": 0 + }, + { + "name": "installed_by", + "content_setting": true, + "default": "" + } + ] } ] } diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 85bd9e68b3..13cd9c8e29 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -4,8 +4,13 @@ $(document).ready(function(){ var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file'; var UPLOAD_CONTENT_ALLOWED_DIV_ID = 'upload-content-allowed'; var UPLOAD_CONTENT_RECOVERING_DIV_ID = 'upload-content-recovering'; + var INSTALLED_ARCHIVE_NAME_ID = 'installed-archive-name'; + var INSTALLED_ARCHIVE_CREATED_ID = 'installed-archive-created'; + var INSTALLED_ARCHIVE_INSTALLED_ID = 'installed-archive-installed'; + var INSTALLED_ARCHIVE_INSTALLED_BY_ID = 'installed-archive-installed-by'; var isRestoring = false; + var restoreErrorShown = false; function progressBarHTML(extraClass, label) { var html = "
"; @@ -103,10 +108,23 @@ $(document).ready(function(){ html += "Restore in progress"; html += progressBarHTML('recovery', 'Restoring'); html += "
"; - $('#' + Settings.UPLOAD_CONTENT_BACKUP_PANEL_ID + ' .panel-body').html(html); } + function setupInstalledContentInfo() { + var html = ""; + html += ""; + html += ""; + html += ""; + //html += ""; + html += ""; + html += "
NameCreatedInstalledInstalled By
"; + html += ""; + html += ""; + //html += "
"; + $('#' + Settings.INSTALLED_ARCHIVE_INFO + ' .panel-body').html(html); + } + // handle content archive or entity file upload // when the selected file is changed, enable the button if there's a selected file @@ -135,6 +153,7 @@ $(document).ready(function(){ var GENERATE_ARCHIVE_BUTTON_ID = 'generate-archive-button'; var CONTENT_ARCHIVES_NORMAL_ID = 'content-archives-success'; + var CONTENT_ARCHIVES_CONTENT_INFO_ID = 'content-archives-content-info'; var CONTENT_ARCHIVES_ERROR_ID = 'content-archives-error'; var AUTOMATIC_ARCHIVES_TABLE_ID = 'automatic-archives-table'; var AUTOMATIC_ARCHIVES_TBODY_ID = 'automatic-archives-tbody'; @@ -230,13 +249,28 @@ $(document).ready(function(){ url: '/api/backups', cache: false }).done(function(data) { - +console.log(data); // split the returned data into manual and automatic manual backups var splitBackups = _.partition(data.backups, function(value, index) { return value.isManualBackup; }); - - if (isRestoring && !data.status.isRecovering) { + if (data.status.recoveryError && !restoreErrorShown) { + restoreErrorShown = true; + swal({ + title: "Error", + text: "There was a problem restoring domain content.\n" + + data.status.recoveryError, + type: "error", + showCancelButton: false, + confirmButtonText: "Restart", + closeOnConfirm: true, + }, + function() { + $.get("/restart"); + showRestartModal(); + }); + } + if (isRestoring && !data.status.isRecovering && !data.status.recoveryError) { // we were recovering and we finished - the DS is going to restart so show the restart modal showRestartModal(); return; @@ -327,6 +361,12 @@ $(document).ready(function(){ $('#' + UPLOAD_CONTENT_ALLOWED_DIV_ID).toggle(!data.status.isRecovering); $('#' + UPLOAD_CONTENT_RECOVERING_DIV_ID).toggle(data.status.isRecovering); + + $('#' + INSTALLED_ARCHIVE_NAME_ID).text(data.installed_archive.name); + $('#' + INSTALLED_ARCHIVE_CREATED_ID).text(moment(data.installed_archive.creation_time).format('lll')); + $('#' + INSTALLED_ARCHIVE_INSTALLED_ID).text(moment(data.installed_archive.install_time).format('lll')); + //$('#' + INSTALLED_ARCHIVE_INSTALLED_BY_ID).text(data.current_archive.installed_by); + // update the progress bars for current restore status if (data.status.isRecovering) { updateProgressBars($('.recovery.progress-bar'), data.status.recoveryProgress * 100); @@ -514,6 +554,7 @@ $(document).ready(function(){ Settings.afterReloadActions = function() { setupBackupUpload(); setupContentArchives(); + setupInstalledContentInfo(); // load the latest backups immediately reloadBackupInformation(); diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index 2c12e2683a..180bc2b6ca 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -57,10 +57,14 @@ $(document).ready(function(){ // define extra groups to add to setting panels, with their splice index Settings.extraContentGroupsAtIndex = { 0: { + html_id: Settings.INSTALLED_ARCHIVE_INFO, + label: 'Installed Archive' + }, + 1: { html_id: Settings.CONTENT_ARCHIVES_PANEL_ID, label: 'Content Archives' }, - 1: { + 2: { html_id: Settings.UPLOAD_CONTENT_BACKUP_PANEL_ID, label: 'Upload Content' } diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index cdfcc40eab..f3d4b3a2d5 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -44,7 +44,8 @@ $.extend(Settings, { INVALID_ROW_CLASS: 'invalid-input', DATA_ROW_INDEX: 'data-row-index', CONTENT_ARCHIVES_PANEL_ID: 'content_archives', - UPLOAD_CONTENT_BACKUP_PANEL_ID: 'upload_content' + UPLOAD_CONTENT_BACKUP_PANEL_ID: 'upload_content', + INSTALLED_ARCHIVE_INFO: 'installed_archive_info' }); var URLs = { diff --git a/domain-server/src/AssetsBackupHandler.cpp b/domain-server/src/AssetsBackupHandler.cpp index 0f63817d80..2beb057e07 100644 --- a/domain-server/src/AssetsBackupHandler.cpp +++ b/domain-server/src/AssetsBackupHandler.cpp @@ -240,12 +240,12 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { Q_ASSERT(QThread::currentThread() == thread()); if (operationInProgress()) { - qCWarning(asset_backup) << "There is already an operation in progress."; + qCWarning(asset_backup) << "There is already an operation in progress. Please wait."; return; } if (_assetServerEnabled && _lastMappingsRefresh.time_since_epoch().count() == 0) { - qCWarning(asset_backup) << "Current mappings not yet loaded."; + qCWarning(asset_backup) << "Current mappings not yet loaded. Please wait."; _backups.emplace_back(backupName, AssetUtils::Mappings(), true); return; } @@ -278,17 +278,19 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { _backups.emplace_back(backupName, mappings, false); } -void AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { Q_ASSERT(QThread::currentThread() == thread()); if (operationInProgress()) { - qCWarning(asset_backup) << "There is already a backup/restore in progress."; - return; + QString errorStr ("There is already a backup/restore in progress. Please wait."); + qWarning() << errorStr; + return { false, errorStr }; } if (_lastMappingsRefresh.time_since_epoch().count() == 0) { - qCWarning(asset_backup) << "Current mappings not yet loaded."; - return; + QString errorStr ("Current mappings not yet loaded. Please wait."); + qWarning() << errorStr; + return { false, errorStr }; } if ((p_high_resolution_clock::now() - _lastMappingsRefresh) > MAX_REFRESH_TIME) { @@ -301,6 +303,16 @@ void AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) if (it == end(_backups)) { loadBackup(backupName, zip); + auto emplaced_backup = find_if(begin(_backups), end(_backups), [&](const AssetServerBackup& backup) { + return backup.name == backupName; + }); + + if(emplaced_backup->corruptedBackup) { + QString errorStr ("Current mappings file is corrupted."); + qWarning() << errorStr; + return { false, errorStr }; + } + QuaZipDir zipDir { &zip, ZIP_ASSETS_FOLDER }; auto assetNames = zipDir.entryList(QDir::Files); @@ -330,8 +342,9 @@ void AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) }); if (it == end(_backups)) { - qCCritical(asset_backup) << "Failed to recover backup:" << backupName; - return; + QString errorStr ("Failed to recover backup: " + backupName); + qWarning() << errorStr; + return { false, errorStr }; } } @@ -339,6 +352,7 @@ void AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) computeServerStateDifference(_currentMappings, newMappings); restoreAllAssets(); + return { true, QString() }; } void AssetsBackupHandler::deleteBackup(const QString& backupName) { diff --git a/domain-server/src/AssetsBackupHandler.h b/domain-server/src/AssetsBackupHandler.h index 427dc6831a..1b1f6201cd 100644 --- a/domain-server/src/AssetsBackupHandler.h +++ b/domain-server/src/AssetsBackupHandler.h @@ -38,7 +38,7 @@ public: void loadBackup(const QString& backupName, QuaZip& zip) override; void loadingComplete() override; void createBackup(const QString& backupName, QuaZip& zip) override; - void recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; void deleteBackup(const QString& backupName) override; void consolidateBackup(const QString& backupName, QuaZip& zip) override; bool isCorruptedBackup(const QString& backupName) override; diff --git a/domain-server/src/BackupHandler.h b/domain-server/src/BackupHandler.h index 547339e01b..adde6f999a 100644 --- a/domain-server/src/BackupHandler.h +++ b/domain-server/src/BackupHandler.h @@ -30,7 +30,7 @@ public: virtual void loadBackup(const QString& backupName, QuaZip& zip) = 0; virtual void loadingComplete() = 0; virtual void createBackup(const QString& backupName, QuaZip& zip) = 0; - virtual void recoverBackup(const QString& backupName, QuaZip& zip) = 0; + virtual std::pair recoverBackup(const QString& backupName, QuaZip& zip) = 0; virtual void deleteBackup(const QString& backupName) = 0; virtual void consolidateBackup(const QString& backupName, QuaZip& zip) = 0; virtual bool isCorruptedBackup(const QString& backupName) = 0; diff --git a/domain-server/src/ContentSettingsBackupHandler.cpp b/domain-server/src/ContentSettingsBackupHandler.cpp index de7669b6a5..8fc8c9b51d 100644 --- a/domain-server/src/ContentSettingsBackupHandler.cpp +++ b/domain-server/src/ContentSettingsBackupHandler.cpp @@ -24,6 +24,7 @@ #pragma GCC diagnostic pop #endif +static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" }; ContentSettingsBackupHandler::ContentSettingsBackupHandler(DomainServerSettingsManager& domainServerSettingsManager) : _settingsManager(domainServerSettingsManager) @@ -31,6 +32,10 @@ ContentSettingsBackupHandler::ContentSettingsBackupHandler(DomainServerSettingsM } static const QString CONTENT_SETTINGS_BACKUP_FILENAME = "content-settings.json"; +static const QString INSTALLED_ARCHIVE = "installed_archive"; +static const QString INSTALLED_ARCHIVE_FILENAME = "filename"; +static const QString INSTALLED_ARCHIVE_INSTALL_TIME = "install_time"; +static const QString INSTALLED_ARCHIVE_INSTALLED_BY = "installed_by"; void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { @@ -42,6 +47,15 @@ void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZi DomainServerSettingsManager::ForBackup ); + // save the filename internally as it's used to determine the name/creation time + // of the archive, and we don't want that to change if the actual file is renamed + // after download. + QJsonObject installed_archive { + { INSTALLED_ARCHIVE_FILENAME, backupName }, + }; + + contentSettingsJSON.insert(INSTALLED_ARCHIVE, installed_archive); + // make a QJsonDocument using the object QJsonDocument contentSettingsDocument { contentSettingsJSON }; @@ -62,24 +76,46 @@ void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZi } } -void ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { if (!zip.setCurrentFile(CONTENT_SETTINGS_BACKUP_FILENAME)) { - qWarning() << "Failed to find" << CONTENT_SETTINGS_BACKUP_FILENAME << "while recovering backup"; - return; + QString errorStr("Failed to find " + CONTENT_SETTINGS_BACKUP_FILENAME + " while recovering backup"); + qWarning() << errorStr; + return { false, errorStr }; } QuaZipFile zipFile { &zip }; if (!zipFile.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open" << CONTENT_SETTINGS_BACKUP_FILENAME << "in backup"; - return; + QString errorStr("Failed to open " + CONTENT_SETTINGS_BACKUP_FILENAME + " in backup"); + qCritical() << errorStr; + return { false, errorStr }; } auto rawData = zipFile.readAll(); zipFile.close(); - QJsonDocument jsonDocument = QJsonDocument::fromJson(rawData); - - if (!_settingsManager.restoreSettingsFromObject(jsonDocument.object(), ContentSettings)) { - qCritical() << "Failed to restore settings from" << CONTENT_SETTINGS_BACKUP_FILENAME << "in content archive"; + if (zipFile.getZipError() != UNZ_OK) { + QString errorStr("Failed to unzip " + CONTENT_SETTINGS_BACKUP_FILENAME + ": " + zipFile.getZipError()); + qCritical() << errorStr; + return { false, errorStr }; } + + QJsonDocument jsonDocument = QJsonDocument::fromJson(rawData); + QJsonObject jsonObject = jsonDocument.object(); + + auto archiveJson = jsonObject.find(INSTALLED_ARCHIVE)->toObject(); + + QJsonObject installed_archive { + { INSTALLED_ARCHIVE_FILENAME, archiveJson[INSTALLED_ARCHIVE_FILENAME]}, + { INSTALLED_ARCHIVE_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() }, + { INSTALLED_ARCHIVE_INSTALLED_BY, ""} + }; + + jsonObject.insert(INSTALLED_ARCHIVE, installed_archive); + + if (!_settingsManager.restoreSettingsFromObject(jsonObject, ContentSettings)) { + QString errorStr("Failed to restore settings from " + CONTENT_SETTINGS_BACKUP_FILENAME + " in content archive"); + qCritical() << errorStr; + return { false, errorStr }; + } + return { true, QString() }; } diff --git a/domain-server/src/ContentSettingsBackupHandler.h b/domain-server/src/ContentSettingsBackupHandler.h index 8454de0786..39ba752221 100644 --- a/domain-server/src/ContentSettingsBackupHandler.h +++ b/domain-server/src/ContentSettingsBackupHandler.h @@ -28,7 +28,7 @@ public: void createBackup(const QString& backupName, QuaZip& zip) override; - void recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; void deleteBackup(const QString& backupName) override {} diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp index 52bc7d679f..4f4490ebee 100644 --- a/domain-server/src/DomainContentBackupManager.cpp +++ b/domain-server/src/DomainContentBackupManager.cpp @@ -45,6 +45,7 @@ static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" }; static const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" }; static const QString AUTOMATIC_BACKUP_PREFIX { "autobackup-" }; static const QString MANUAL_BACKUP_PREFIX { "backup-" }; +static const QString PRE_UPLOAD_SUFFIX{ "pre_upload" }; static const QString MANUAL_BACKUP_NAME_RE { "[a-zA-Z0-9\\-_ ]+" }; void DomainContentBackupManager::addBackupHandler(BackupHandlerPointer handler) { @@ -52,9 +53,10 @@ void DomainContentBackupManager::addBackupHandler(BackupHandlerPointer handler) } DomainContentBackupManager::DomainContentBackupManager(const QString& backupDirectory, - const QVariantList& backupRules, + DomainServerSettingsManager& domainServerSettingsManager, std::chrono::milliseconds persistInterval, bool debugTimestampNow) : + _settingsManager(domainServerSettingsManager), _consolidatedBackupDirectory(PathUtils::generateTemporaryDir()), _backupDirectory(backupDirectory), _persistInterval(persistInterval), _lastCheck(p_high_resolution_clock::now()) { @@ -63,7 +65,8 @@ DomainContentBackupManager::DomainContentBackupManager(const QString& backupDire // Make sure the backup directory exists. QDir(_backupDirectory).mkpath("."); - parseBackupRules(backupRules); + static const QString BACKUP_RULES_KEYPATH = AUTOMATIC_CONTENT_ARCHIVES_GROUP + ".backup_rules"; + parseBackupRules(_settingsManager.valueOrDefaultValueForKeyPath(BACKUP_RULES_KEYPATH).toList()); constexpr int CONSOLIDATED_BACKUP_CLEANER_INTERVAL_MSECS = 30 * 1000; _consolidatedBackupCleanupTimer.setInterval(CONSOLIDATED_BACKUP_CLEANER_INTERVAL_MSECS); @@ -170,7 +173,7 @@ bool DomainContentBackupManager::process() { return handler->getRecoveryStatus().first; }); - if (!isStillRecovering) { + if (!isStillRecovering && _recoveryError.isEmpty()) { _isRecovering = false; _recoveryFilename = ""; emit recoveryCompleted(); @@ -277,7 +280,7 @@ void DomainContentBackupManager::deleteBackup(MiniPromise::Promise promise, cons }); } -bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip) { +bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip, bool rollingBack) { if (!zip.open(QuaZip::Mode::mdUnzip)) { qWarning() << "Failed to unzip file: " << backupName; return false; @@ -286,7 +289,15 @@ bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, _recoveryFilename = backupName; for (auto& handler : _backupHandlers) { - handler->recoverBackup(backupName, zip); + bool success; + QString errorStr; + std::tie(success, errorStr) = handler->recoverBackup(backupName, zip); + if (!success) { + if (!rollingBack) { + _recoveryError = errorStr; + } + return false; + } } qDebug() << "Successfully started recovering from " << backupName; @@ -309,7 +320,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, } qDebug() << "Recovering from" << backupName; - + _recoveryError = ""; bool success { false }; QDir backupDir { _backupDirectory }; auto backupFilePath { backupDir.filePath(backupName) }; @@ -360,14 +371,36 @@ void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise pr } qDebug() << "Recovering from uploaded file -" << uploadedFilename; + bool success; + QString path; + std::tie(success, path) = createBackup(AUTOMATIC_BACKUP_PREFIX, PRE_UPLOAD_SUFFIX); + if(!success) { + _recoveryError = "Failed to create backup for " + PRE_UPLOAD_SUFFIX + " at " + path; + qCWarning(domain_server) << _recoveryError; + } else { + QFile uploadedFile(uploadedFilename); + QuaZip uploadedZip { &uploadedFile }; - QFile uploadedFile(uploadedFilename); - QuaZip uploadedZip { &uploadedFile }; + QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; - QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; + bool success = recoverFromBackupZip(backupName, uploadedZip); - bool success = recoverFromBackupZip(backupName, uploadedZip); + if (!success) { + // attempt to rollback to + QString filename; + QDateTime filetime; + if (getMostRecentBackup(PRE_UPLOAD_SUFFIX, filename, filetime)) { + QFile uploadedFile(uploadedFilename); + QuaZip uploadedZip { &uploadedFile }; + + QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; + recoverFromBackupZip(backupName, uploadedZip, true); + + } + } + + } promise->resolve({ { "success", success } }); @@ -455,9 +488,32 @@ void DomainContentBackupManager::getAllBackupsAndStatus(MiniPromise::Promise pro { "recoveryProgress", recoveryProgress } }; + if(!_recoveryError.isEmpty()) { + status["recoveryError"] = _recoveryError; + } + + QVariantMap currentArchive; + + QString fileName = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_FILENAME).toString(); + QString prefixFormat = "(" + QRegExp::escape(AUTOMATIC_BACKUP_PREFIX) + "|" + QRegExp::escape(MANUAL_BACKUP_PREFIX) + ")"; + QString nameFormat = "(.+)"; + QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")"; + QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" }; + if (backupNameFormat.exactMatch(fileName)) { + auto type = backupNameFormat.cap(1); + auto name = backupNameFormat.cap(2); + auto dateTime = backupNameFormat.cap(3); + auto createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT); + currentArchive["name"] = name; + currentArchive["creation_time"] = createdAt.toMSecsSinceEpoch(); + currentArchive["install_time"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_INSTALL_TIME).toULongLong(); + currentArchive["installed_by"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_INSTALLED_BY).toString(); + } + QVariantMap info { { "backups", variantBackups }, - { "status", status } + { "status", status }, + { "installed_archive", currentArchive } }; promise->resolve(info); diff --git a/domain-server/src/DomainContentBackupManager.h b/domain-server/src/DomainContentBackupManager.h index 4af3ae5bfd..6e562b1773 100644 --- a/domain-server/src/DomainContentBackupManager.h +++ b/domain-server/src/DomainContentBackupManager.h @@ -28,6 +28,7 @@ #include #include "BackupHandler.h" +#include "DomainServerSettingsManager.h" #include @@ -71,7 +72,7 @@ public: static const std::chrono::seconds DEFAULT_PERSIST_INTERVAL; DomainContentBackupManager(const QString& rootBackupDirectory, - const QVariantList& settings, + DomainServerSettingsManager& domainServerSettingsManager, std::chrono::milliseconds persistInterval = DEFAULT_PERSIST_INTERVAL, bool debugTimestampNow = false); @@ -108,13 +109,15 @@ protected: std::pair createBackup(const QString& prefix, const QString& name); - bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip); + bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip, bool rollingBack = false); private slots: void removeOldConsolidatedBackups(); void consolidateBackupInternal(QString fileName); private: + DomainServerSettingsManager& _settingsManager; + QTimer _consolidatedBackupCleanupTimer; const QString _consolidatedBackupDirectory; @@ -126,6 +129,7 @@ private: std::unordered_map _consolidatedBackups; std::atomic _isRecovering { false }; + QString _recoveryError; QString _recoveryFilename { }; p_high_resolution_clock::time_point _lastCheck; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b7c723ab48..d20ddb186e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -307,11 +307,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : } maybeHandleReplacementEntityFile(); - - static const QString BACKUP_RULES_KEYPATH = AUTOMATIC_CONTENT_ARCHIVES_GROUP + ".backup_rules"; - auto backupRulesVariant = _settingsManager.valueOrDefaultValueForKeyPath(BACKUP_RULES_KEYPATH); - - _contentManager.reset(new DomainContentBackupManager(getContentBackupDir(), backupRulesVariant.toList())); + _contentManager.reset(new DomainContentBackupManager(getContentBackupDir(), _settingsManager)); connect(_contentManager.get(), &DomainContentBackupManager::started, _contentManager.get(), [this](){ _contentManager->addBackupHandler(BackupHandlerPointer(new EntitiesBackupHandler(getEntitiesFilePath(), getEntitiesReplacementFilePath()))); @@ -2333,8 +2329,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url QJsonObject rootJSON; auto success = result["success"].toBool(); - rootJSON["success"] = success; - QJsonDocument docJSON(rootJSON); + QJsonDocument docJSON(QJsonObject::fromVariantMap(result)); connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); @@ -2362,8 +2357,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url QJsonObject rootJSON; auto success = result["success"].toBool(); - rootJSON["success"] = success; - QJsonDocument docJSON(rootJSON); + QJsonDocument docJSON(QJsonObject::fromVariantMap(result)); connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); @@ -2467,8 +2461,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url QJsonObject rootJSON; auto success = result["success"].toBool(); - rootJSON["success"] = success; - QJsonDocument docJSON(rootJSON); + QJsonDocument docJSON(QJsonObject::fromVariantMap(result)); connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(), JSON_MIME_TYPE.toUtf8()); }); @@ -2687,11 +2680,12 @@ void DomainServer::profileRequestFinished() { bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url) { - const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie"; - const QString ADMIN_USERS_CONFIG_KEY = "admin-users"; - const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles"; - const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username"; - const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password"; + static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie"; + static const QString ADMIN_USERS_CONFIG_KEY = "admin-users"; + static const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles"; + static const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username"; + static const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password"; + const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)"; const QByteArray UNAUTHENTICATED_BODY = "You do not have permission to access this domain-server."; @@ -2702,7 +2696,6 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl && (adminUsersVariant.isValid() || adminRolesVariant.isValid())) { QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY); - const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)"; QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); QUuid cookieUUID; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 54b7fbe466..6abae7e619 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -194,6 +194,7 @@ private: QUrl oauthRedirectURL(); QUrl oauthAuthorizationURL(const QUuid& stateUUID = QUuid::createUuid()); + QString getWebSessionUsername(HTTPConnection* connection); bool isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url); QNetworkReply* profileRequestGivenTokenReply(QNetworkReply* tokenReply); diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 2020561205..a053001f0c 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -35,6 +35,9 @@ const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_finger const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions"; const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens"; const QString AUTOMATIC_CONTENT_ARCHIVES_GROUP = "automatic_content_archives"; +const QString CONTENT_SETTINGS_ARCHIVE_FILENAME = "installed_archive.filename"; +const QString CONTENT_SETTINGS_ARCHIVE_INSTALL_TIME = "installed_archive.install_time"; +const QString CONTENT_SETTINGS_ARCHIVE_INSTALLED_BY = "installed_archive.installed_by"; using GroupByUUIDKey = QPair; // groupID, rankID diff --git a/domain-server/src/EntitiesBackupHandler.cpp b/domain-server/src/EntitiesBackupHandler.cpp index 90a066036d..f306e9680e 100644 --- a/domain-server/src/EntitiesBackupHandler.cpp +++ b/domain-server/src/EntitiesBackupHandler.cpp @@ -57,36 +57,41 @@ void EntitiesBackupHandler::createBackup(const QString& backupName, QuaZip& zip) } } -void EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { if (!zip.setCurrentFile(ENTITIES_BACKUP_FILENAME)) { - qWarning() << "Failed to find" << ENTITIES_BACKUP_FILENAME << "while recovering backup"; - return; + QString errorStr("Failed to find " + ENTITIES_BACKUP_FILENAME + " while recovering backup"); + qWarning() << errorStr; + return { false, errorStr }; } QuaZipFile zipFile { &zip }; if (!zipFile.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open" << ENTITIES_BACKUP_FILENAME << "in backup"; - return; + QString errorStr("Failed to open " + ENTITIES_BACKUP_FILENAME + " in backup"); + qCritical() << errorStr; + return { false, errorStr }; } auto rawData = zipFile.readAll(); zipFile.close(); + if (zipFile.getZipError() != UNZ_OK) { + QString errorStr("Failed to unzip " + ENTITIES_BACKUP_FILENAME + ": " + zipFile.getZipError()); + qCritical() << errorStr; + return { false, errorStr }; + } + OctreeUtils::RawEntityData data; if (!data.readOctreeDataInfoFromData(rawData)) { - qCritical() << "Unable to parse octree data during backup recovery"; - return; + QString errorStr("Unable to parse octree data during backup recovery"); + qCritical() << errorStr; + return { false, errorStr }; } data.resetIdAndVersion(); - if (zipFile.getZipError() != UNZ_OK) { - qCritical().nospace() << "Failed to unzip " << ENTITIES_BACKUP_FILENAME << ": " << zipFile.getZipError(); - return; - } - QFile entitiesFile { _entitiesReplacementFilePath }; if (entitiesFile.open(QIODevice::WriteOnly)) { entitiesFile.write(data.toGzippedByteArray()); } + return { true, QString() }; } diff --git a/domain-server/src/EntitiesBackupHandler.h b/domain-server/src/EntitiesBackupHandler.h index d95ad695a8..4dd6462974 100644 --- a/domain-server/src/EntitiesBackupHandler.h +++ b/domain-server/src/EntitiesBackupHandler.h @@ -29,7 +29,7 @@ public: void createBackup(const QString& backupName, QuaZip& zip) override; // Recover from a full backup - void recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; // Delete a skeleton backup void deleteBackup(const QString& backupName) override {} From fe4334d6c407fe1598155009a4d756dbd3e0f8b7 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 24 Jul 2019 15:33:13 -0700 Subject: [PATCH 02/32] BUGZ-829 fix a few nits --- domain-server/resources/web/content/js/content.js | 3 +-- domain-server/src/AssetsBackupHandler.cpp | 4 ++-- domain-server/src/DomainContentBackupManager.cpp | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 13cd9c8e29..3e2b10e3f3 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -249,7 +249,6 @@ $(document).ready(function(){ url: '/api/backups', cache: false }).done(function(data) { -console.log(data); // split the returned data into manual and automatic manual backups var splitBackups = _.partition(data.backups, function(value, index) { return value.isManualBackup; @@ -265,7 +264,7 @@ console.log(data); confirmButtonText: "Restart", closeOnConfirm: true, }, - function() { + function () { $.get("/restart"); showRestartModal(); }); diff --git a/domain-server/src/AssetsBackupHandler.cpp b/domain-server/src/AssetsBackupHandler.cpp index 2beb057e07..36bd00718e 100644 --- a/domain-server/src/AssetsBackupHandler.cpp +++ b/domain-server/src/AssetsBackupHandler.cpp @@ -240,12 +240,12 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { Q_ASSERT(QThread::currentThread() == thread()); if (operationInProgress()) { - qCWarning(asset_backup) << "There is already an operation in progress. Please wait."; + qCWarning(asset_backup) << "There is already an operation in progress."; return; } if (_assetServerEnabled && _lastMappingsRefresh.time_since_epoch().count() == 0) { - qCWarning(asset_backup) << "Current mappings not yet loaded. Please wait."; + qCWarning(asset_backup) << "Current mappings not yet loaded."; _backups.emplace_back(backupName, AssetUtils::Mappings(), true); return; } diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp index 4f4490ebee..67a53cd1d4 100644 --- a/domain-server/src/DomainContentBackupManager.cpp +++ b/domain-server/src/DomainContentBackupManager.cpp @@ -173,6 +173,8 @@ bool DomainContentBackupManager::process() { return handler->getRecoveryStatus().first; }); + // if an error occurred, don't restart the server so that the user + // can be notified of the error and take action. if (!isStillRecovering && _recoveryError.isEmpty()) { _isRecovering = false; _recoveryFilename = ""; From 5afae43051d7673f99341d70c3c4ab71f904ef99 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 24 Jul 2019 16:05:34 -0700 Subject: [PATCH 03/32] CR fix --- domain-server/src/DomainServer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 6abae7e619..54b7fbe466 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -194,7 +194,6 @@ private: QUrl oauthRedirectURL(); QUrl oauthAuthorizationURL(const QUuid& stateUUID = QUuid::createUuid()); - QString getWebSessionUsername(HTTPConnection* connection); bool isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url); QNetworkReply* profileRequestGivenTokenReply(QNetworkReply* tokenReply); From 9d93a2f502b2004635987914dcac7aef85300c8e Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 24 Jul 2019 16:27:24 -0700 Subject: [PATCH 04/32] Fix simplifiedUI stuck on wrong LOD value --- interface/src/LODManager.h | 8 ++++++++ scripts/simplifiedUI/ui/simplifiedUI.js | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 77cb1a0d39..94e5ae2a3c 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -62,6 +62,8 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged) + Q_PROPERTY(float octreeSizeScale READ getOctreeSizeScale WRITE setOctreeSizeScale) + Q_PROPERTY(bool automaticLODAdjust READ getAutomaticLODAdjust WRITE setAutomaticLODAdjust NOTIFY autoLODChanged) Q_PROPERTY(float presentTime READ getPresentTime) @@ -150,6 +152,12 @@ public: */ Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; } + /**jsdoc + * @function LODManager.getDefaultOctreeSizeScale + * @param {number} sizeScale + */ + Q_INVOKABLE float getDefaultOctreeSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } + /**jsdoc * @function LODManager.setBoundaryLevelAdjust * @param {number} boundaryLevelAdjust diff --git a/scripts/simplifiedUI/ui/simplifiedUI.js b/scripts/simplifiedUI/ui/simplifiedUI.js index 50c626b594..80c0a6a61d 100644 --- a/scripts/simplifiedUI/ui/simplifiedUI.js +++ b/scripts/simplifiedUI/ui/simplifiedUI.js @@ -531,21 +531,21 @@ function maybeUpdateOutputDeviceMutedOverlay() { var oldAutomaticLODAdjust; -var oldLODLevel; +var oldOctreeSizeScale; var DEFAULT_AUTO_LOD_ADJUST = false; -var DEFAULT_LOD_LEVEL = 0.5; +var DEFAULT_OCTREE_SIZE_SCALE = LODManager.getDefaultOctreeSizeScale(); function modifyLODSettings() { oldAutomaticLODAdjust = LODManager.automaticLODAdjust; - oldLODLevel = LODManager.lodQualityLevel; + oldOctreeSizeScale = LODManager.octreeSizeScale; LODManager.automaticLODAdjust = DEFAULT_AUTO_LOD_ADJUST; - LODManager.lodQualityLevel = DEFAULT_LOD_LEVEL; + LODManager.octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; } function restoreLODSettings() { LODManager.automaticLODAdjust = oldAutomaticLODAdjust; - LODManager.lodQualityLevel = oldLODLevel; + LODManager.octreeSizeScale = oldOctreeSizeScale; } From 772eb578984837449c95db7c1254267a9ead6515 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 24 Jul 2019 16:43:51 -0700 Subject: [PATCH 05/32] Remove broken/undocumented LODManager script features --- interface/src/LODManager.cpp | 9 --------- interface/src/LODManager.h | 12 ------------ 2 files changed, 21 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 0c9587d3ae..2cba5f9b1b 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -425,12 +425,3 @@ float LODManager::getWorldDetailQuality() const { return HIGH; } - - -void LODManager::setLODQualityLevel(float quality) { - _lodQualityLevel = quality; -} - -float LODManager::getLODQualityLevel() const { - return _lodQualityLevel; -} diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 94e5ae2a3c..62efb639a8 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -47,11 +47,6 @@ class AABox; * @property {number} presentTime Read-only. * @property {number} engineRunTime Read-only. * @property {number} gpuTime Read-only. - * @property {number} avgRenderTime Read-only. - * @property {number} fps Read-only. - * @property {number} lodLevel Read-only. - * @property {number} lodDecreaseFPS Read-only. - * @property {number} lodIncreaseFPS Read-only. */ class LODManager : public QObject, public Dependency { @@ -60,8 +55,6 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality NOTIFY worldDetailQualityChanged) - Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged) - Q_PROPERTY(float octreeSizeScale READ getOctreeSizeScale WRITE setOctreeSizeScale) Q_PROPERTY(bool automaticLODAdjust READ getAutomaticLODAdjust WRITE setAutomaticLODAdjust NOTIFY autoLODChanged) @@ -202,9 +195,6 @@ public: void setWorldDetailQuality(float quality); float getWorldDetailQuality() const; - void setLODQualityLevel(float quality); - float getLODQualityLevel() const; - float getLODAngleDeg() const; void setLODAngleDeg(float lodAngle); float getLODAngleHalfTan() const; @@ -259,8 +249,6 @@ private: float _smoothScale{ 10.0f }; // smooth is evaluated over 10 times longer than now float _smoothRenderTime{ 0.0f }; // msec - float _lodQualityLevel{ LOD_DEFAULT_QUALITY_LEVEL }; - float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS }; float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS }; From 3a4ce446338664dcc3bbdb86f238f914a57df8fc Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 24 Jul 2019 17:30:08 -0700 Subject: [PATCH 06/32] On second thought, do not expose default octree size scale --- interface/src/LODManager.h | 6 ------ scripts/simplifiedUI/ui/simplifiedUI.js | 8 ++++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 62efb639a8..c0a7797561 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -145,12 +145,6 @@ public: */ Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; } - /**jsdoc - * @function LODManager.getDefaultOctreeSizeScale - * @param {number} sizeScale - */ - Q_INVOKABLE float getDefaultOctreeSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } - /**jsdoc * @function LODManager.setBoundaryLevelAdjust * @param {number} boundaryLevelAdjust diff --git a/scripts/simplifiedUI/ui/simplifiedUI.js b/scripts/simplifiedUI/ui/simplifiedUI.js index 80c0a6a61d..e9f49587aa 100644 --- a/scripts/simplifiedUI/ui/simplifiedUI.js +++ b/scripts/simplifiedUI/ui/simplifiedUI.js @@ -532,14 +532,14 @@ function maybeUpdateOutputDeviceMutedOverlay() { var oldAutomaticLODAdjust; var oldOctreeSizeScale; -var DEFAULT_AUTO_LOD_ADJUST = false; -var DEFAULT_OCTREE_SIZE_SCALE = LODManager.getDefaultOctreeSizeScale(); +var SIMPLIFIED_UI_AUTO_LOD_ADJUST = false; +var SIMPLIFIED_UI_OCTREE_SIZE_SCALE = 32768 * 916; // Octree cell size in meters (constant) * distance in meters at which we want a 1 meter cube to be visible function modifyLODSettings() { oldAutomaticLODAdjust = LODManager.automaticLODAdjust; oldOctreeSizeScale = LODManager.octreeSizeScale; - LODManager.automaticLODAdjust = DEFAULT_AUTO_LOD_ADJUST; - LODManager.octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; + LODManager.automaticLODAdjust = SIMPLIFIED_UI_AUTO_LOD_ADJUST; + LODManager.octreeSizeScale = SIMPLIFIED_UI_OCTREE_SIZE_SCALE; } From 22e71115ddf28896e99443461875c0f518e9398d Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 25 Jul 2019 11:46:05 -0700 Subject: [PATCH 07/32] DEV-168 - add filename reporting for installed/restored backup content --- .../resources/describe-settings.json | 14 +++- .../resources/web/content/js/content.js | 31 +++++---- .../resources/web/js/domain-server.js | 4 +- domain-server/resources/web/js/shared.js | 2 +- domain-server/src/AssetsBackupHandler.cpp | 2 +- domain-server/src/AssetsBackupHandler.h | 2 +- domain-server/src/BackupHandler.h | 2 +- .../src/ContentSettingsBackupHandler.cpp | 50 +++++++++----- .../src/ContentSettingsBackupHandler.h | 2 +- .../src/DomainContentBackupManager.cpp | 65 +++++++++++-------- .../src/DomainContentBackupManager.h | 8 ++- domain-server/src/DomainServer.cpp | 2 +- .../src/DomainServerSettingsManager.h | 8 ++- domain-server/src/EntitiesBackupHandler.cpp | 2 +- domain-server/src/EntitiesBackupHandler.h | 2 +- 15 files changed, 120 insertions(+), 76 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index cbbcdb399e..9cb4c2cab9 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1790,8 +1790,8 @@ ] }, { - "name": "installed_archive", - "label": "Installed Archive", + "name": "installed_content", + "label": "Installed Content", "hidden": true, "settings": [ { @@ -1799,6 +1799,16 @@ "content_setting": true, "default": "" }, + { + "name": "name", + "content_setting": true, + "default": "" + }, + { + "name": "creation_time", + "content_setting": true, + "default": 0 + }, { "name": "install_time", "type": "int", diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 3e2b10e3f3..ae9dc23536 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -4,10 +4,11 @@ $(document).ready(function(){ var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file'; var UPLOAD_CONTENT_ALLOWED_DIV_ID = 'upload-content-allowed'; var UPLOAD_CONTENT_RECOVERING_DIV_ID = 'upload-content-recovering'; - var INSTALLED_ARCHIVE_NAME_ID = 'installed-archive-name'; - var INSTALLED_ARCHIVE_CREATED_ID = 'installed-archive-created'; - var INSTALLED_ARCHIVE_INSTALLED_ID = 'installed-archive-installed'; - var INSTALLED_ARCHIVE_INSTALLED_BY_ID = 'installed-archive-installed-by'; + var INSTALLED_CONTENT_FILENAME_ID = 'installed-content-filename'; + var INSTALLED_CONTENT_NAME_ID = 'installed-content-name'; + var INSTALLED_CONTENT_CREATED_ID = 'installed-content-created'; + var INSTALLED_CONTENT_INSTALLED_ID = 'installed-content-installed'; + var INSTALLED_CONTENT_INSTALLED_BY_ID = 'installed-content-installed-by'; var isRestoring = false; var restoreErrorShown = false; @@ -114,15 +115,17 @@ $(document).ready(function(){ function setupInstalledContentInfo() { var html = ""; html += ""; + html += ""; html += ""; html += ""; //html += ""; - html += ""; + html += ""; html += "
NameFile NameCreatedInstalledInstalled By
"; - html += ""; - html += ""; - //html += "
"; + html += ""; + html += ""; + html += ""; + //html += "
"; - $('#' + Settings.INSTALLED_ARCHIVE_INFO + ' .panel-body').html(html); + $('#' + Settings.INSTALLED_CONTENT + ' .panel-body').html(html); } // handle content archive or entity file upload @@ -360,11 +363,11 @@ $(document).ready(function(){ $('#' + UPLOAD_CONTENT_ALLOWED_DIV_ID).toggle(!data.status.isRecovering); $('#' + UPLOAD_CONTENT_RECOVERING_DIV_ID).toggle(data.status.isRecovering); - - $('#' + INSTALLED_ARCHIVE_NAME_ID).text(data.installed_archive.name); - $('#' + INSTALLED_ARCHIVE_CREATED_ID).text(moment(data.installed_archive.creation_time).format('lll')); - $('#' + INSTALLED_ARCHIVE_INSTALLED_ID).text(moment(data.installed_archive.install_time).format('lll')); - //$('#' + INSTALLED_ARCHIVE_INSTALLED_BY_ID).text(data.current_archive.installed_by); + $('#' + INSTALLED_CONTENT_NAME_ID).text(data.installed_content.name); + $('#' + INSTALLED_CONTENT_FILENAME_ID).text(data.installed_content.filename); + $('#' + INSTALLED_CONTENT_CREATED_ID).text(data.installed_content.creation_time ? moment(data.installed_content.creation_time).format('lll') : ""); + $('#' + INSTALLED_CONTENT_INSTALLED_ID).text(data.installed_content.install_time ? moment(data.installed_content.install_time).format('lll') : ""); + //$('#' + INSTALLED_CONTENT_INSTALLED_BY_ID).text(data.installed_content.installed_by); // update the progress bars for current restore status if (data.status.isRecovering) { diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index 180bc2b6ca..a8b7267b88 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -57,8 +57,8 @@ $(document).ready(function(){ // define extra groups to add to setting panels, with their splice index Settings.extraContentGroupsAtIndex = { 0: { - html_id: Settings.INSTALLED_ARCHIVE_INFO, - label: 'Installed Archive' + html_id: Settings.INSTALLED_CONTENT, + label: 'Installed Content' }, 1: { html_id: Settings.CONTENT_ARCHIVES_PANEL_ID, diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index f3d4b3a2d5..abcb2cb9eb 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -45,7 +45,7 @@ $.extend(Settings, { DATA_ROW_INDEX: 'data-row-index', CONTENT_ARCHIVES_PANEL_ID: 'content_archives', UPLOAD_CONTENT_BACKUP_PANEL_ID: 'upload_content', - INSTALLED_ARCHIVE_INFO: 'installed_archive_info' + INSTALLED_CONTENT: 'installed_content' }); var URLs = { diff --git a/domain-server/src/AssetsBackupHandler.cpp b/domain-server/src/AssetsBackupHandler.cpp index 36bd00718e..d978e4ea56 100644 --- a/domain-server/src/AssetsBackupHandler.cpp +++ b/domain-server/src/AssetsBackupHandler.cpp @@ -278,7 +278,7 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { _backups.emplace_back(backupName, mappings, false); } -std::pair AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) { Q_ASSERT(QThread::currentThread() == thread()); if (operationInProgress()) { diff --git a/domain-server/src/AssetsBackupHandler.h b/domain-server/src/AssetsBackupHandler.h index 1b1f6201cd..c8f20ab965 100644 --- a/domain-server/src/AssetsBackupHandler.h +++ b/domain-server/src/AssetsBackupHandler.h @@ -38,7 +38,7 @@ public: void loadBackup(const QString& backupName, QuaZip& zip) override; void loadingComplete() override; void createBackup(const QString& backupName, QuaZip& zip) override; - std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override; void deleteBackup(const QString& backupName) override; void consolidateBackup(const QString& backupName, QuaZip& zip) override; bool isCorruptedBackup(const QString& backupName) override; diff --git a/domain-server/src/BackupHandler.h b/domain-server/src/BackupHandler.h index adde6f999a..278d43ade3 100644 --- a/domain-server/src/BackupHandler.h +++ b/domain-server/src/BackupHandler.h @@ -30,7 +30,7 @@ public: virtual void loadBackup(const QString& backupName, QuaZip& zip) = 0; virtual void loadingComplete() = 0; virtual void createBackup(const QString& backupName, QuaZip& zip) = 0; - virtual std::pair recoverBackup(const QString& backupName, QuaZip& zip) = 0; + virtual std::pair recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) = 0; virtual void deleteBackup(const QString& backupName) = 0; virtual void consolidateBackup(const QString& backupName, QuaZip& zip) = 0; virtual bool isCorruptedBackup(const QString& backupName) = 0; diff --git a/domain-server/src/ContentSettingsBackupHandler.cpp b/domain-server/src/ContentSettingsBackupHandler.cpp index 8fc8c9b51d..a905a0bc03 100644 --- a/domain-server/src/ContentSettingsBackupHandler.cpp +++ b/domain-server/src/ContentSettingsBackupHandler.cpp @@ -10,6 +10,7 @@ // #include "ContentSettingsBackupHandler.h" +#include "DomainContentBackupManager.h" #if !defined(__clang__) && defined(__GNUC__) #pragma GCC diagnostic push @@ -32,10 +33,12 @@ ContentSettingsBackupHandler::ContentSettingsBackupHandler(DomainServerSettingsM } static const QString CONTENT_SETTINGS_BACKUP_FILENAME = "content-settings.json"; -static const QString INSTALLED_ARCHIVE = "installed_archive"; -static const QString INSTALLED_ARCHIVE_FILENAME = "filename"; -static const QString INSTALLED_ARCHIVE_INSTALL_TIME = "install_time"; -static const QString INSTALLED_ARCHIVE_INSTALLED_BY = "installed_by"; +static const QString INSTALLED_CONTENT = "installed_content"; +static const QString INSTALLED_CONTENT_FILENAME = "filename"; +static const QString INSTALLED_CONTENT_NAME = "name"; +static const QString INSTALLED_CONTENT_CREATION_TIME = "creation_time"; +static const QString INSTALLED_CONTENT_INSTALL_TIME = "install_time"; +static const QString INSTALLED_CONTENT_INSTALLED_BY = "installed_by"; void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { @@ -46,15 +49,26 @@ void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZi DomainServerSettingsManager::IncludeContentSettings, DomainServerSettingsManager::NoDefaultSettings, DomainServerSettingsManager::ForBackup ); + QString prefixFormat = "(" + QRegExp::escape(AUTOMATIC_BACKUP_PREFIX) + "|" + QRegExp::escape(MANUAL_BACKUP_PREFIX) + ")"; + QString nameFormat = "(.+)"; + QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")"; + QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" }; - // save the filename internally as it's used to determine the name/creation time - // of the archive, and we don't want that to change if the actual file is renamed - // after download. - QJsonObject installed_archive { - { INSTALLED_ARCHIVE_FILENAME, backupName }, + QString name{ "" }; + QDateTime createdAt; + + if (backupNameFormat.exactMatch(backupName)) { + name = backupNameFormat.cap(2); + auto dateTime = backupNameFormat.cap(3); + createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT); + } + + QJsonObject installed_content { + { INSTALLED_CONTENT_NAME, name}, + { INSTALLED_CONTENT_CREATION_TIME, createdAt.currentMSecsSinceEpoch()} }; - contentSettingsJSON.insert(INSTALLED_ARCHIVE, installed_archive); + contentSettingsJSON.insert(INSTALLED_CONTENT, installed_content); // make a QJsonDocument using the object QJsonDocument contentSettingsDocument { contentSettingsJSON }; @@ -76,7 +90,7 @@ void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZi } } -std::pair ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) { if (!zip.setCurrentFile(CONTENT_SETTINGS_BACKUP_FILENAME)) { QString errorStr("Failed to find " + CONTENT_SETTINGS_BACKUP_FILENAME + " while recovering backup"); qWarning() << errorStr; @@ -102,15 +116,17 @@ std::pair ContentSettingsBackupHandler::recoverBackup(const QStri QJsonDocument jsonDocument = QJsonDocument::fromJson(rawData); QJsonObject jsonObject = jsonDocument.object(); - auto archiveJson = jsonObject.find(INSTALLED_ARCHIVE)->toObject(); + auto archiveJson = jsonObject.find(INSTALLED_CONTENT)->toObject(); - QJsonObject installed_archive { - { INSTALLED_ARCHIVE_FILENAME, archiveJson[INSTALLED_ARCHIVE_FILENAME]}, - { INSTALLED_ARCHIVE_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() }, - { INSTALLED_ARCHIVE_INSTALLED_BY, ""} + QJsonObject installed_content { + { INSTALLED_CONTENT_FILENAME, sourceFilename }, + { INSTALLED_CONTENT_NAME, archiveJson[INSTALLED_CONTENT_NAME].toString()}, + { INSTALLED_CONTENT_CREATION_TIME, archiveJson[INSTALLED_CONTENT_CREATION_TIME].toVariant().toLongLong() }, + { INSTALLED_CONTENT_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() }, + { INSTALLED_CONTENT_INSTALLED_BY, "" } }; - jsonObject.insert(INSTALLED_ARCHIVE, installed_archive); + jsonObject.insert(INSTALLED_CONTENT, installed_content); if (!_settingsManager.restoreSettingsFromObject(jsonObject, ContentSettings)) { QString errorStr("Failed to restore settings from " + CONTENT_SETTINGS_BACKUP_FILENAME + " in content archive"); diff --git a/domain-server/src/ContentSettingsBackupHandler.h b/domain-server/src/ContentSettingsBackupHandler.h index 39ba752221..0e44a18424 100644 --- a/domain-server/src/ContentSettingsBackupHandler.h +++ b/domain-server/src/ContentSettingsBackupHandler.h @@ -28,7 +28,7 @@ public: void createBackup(const QString& backupName, QuaZip& zip) override; - std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override; void deleteBackup(const QString& backupName) override {} diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp index 67a53cd1d4..11930f0b49 100644 --- a/domain-server/src/DomainContentBackupManager.cpp +++ b/domain-server/src/DomainContentBackupManager.cpp @@ -42,9 +42,6 @@ const std::chrono::seconds DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL // Backup format looks like: daily_backup-TIMESTAMP.zip static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" }; -static const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" }; -static const QString AUTOMATIC_BACKUP_PREFIX { "autobackup-" }; -static const QString MANUAL_BACKUP_PREFIX { "backup-" }; static const QString PRE_UPLOAD_SUFFIX{ "pre_upload" }; static const QString MANUAL_BACKUP_NAME_RE { "[a-zA-Z0-9\\-_ ]+" }; @@ -282,7 +279,7 @@ void DomainContentBackupManager::deleteBackup(MiniPromise::Promise promise, cons }); } -bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip, bool rollingBack) { +bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip, const QString& sourceFilename, bool rollingBack) { if (!zip.open(QuaZip::Mode::mdUnzip)) { qWarning() << "Failed to unzip file: " << backupName; return false; @@ -293,7 +290,7 @@ bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, for (auto& handler : _backupHandlers) { bool success; QString errorStr; - std::tie(success, errorStr) = handler->recoverBackup(backupName, zip); + std::tie(success, errorStr) = handler->recoverBackup(backupName, zip, sourceFilename); if (!success) { if (!rollingBack) { _recoveryError = errorStr; @@ -330,7 +327,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, if (backupFile.open(QIODevice::ReadOnly)) { QuaZip zip { &backupFile }; - success = recoverFromBackupZip(backupName, zip); + success = recoverFromBackupZip(backupName, zip, backupName); backupFile.close(); } else { @@ -358,21 +355,21 @@ void DomainContentBackupManager::recoverFromUploadedBackup(MiniPromise::Promise QuaZip uploadedZip { &uploadedBackupBuffer }; QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; - bool success = recoverFromBackupZip(backupName, uploadedZip); + bool success = recoverFromBackupZip(backupName, uploadedZip, QString()); promise->resolve({ { "success", success } }); } -void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename) { +void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, QString sourceFilename) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "recoverFromUploadedFile", Q_ARG(MiniPromise::Promise, promise), - Q_ARG(QString, uploadedFilename)); + Q_ARG(QString, uploadedFilename), Q_ARG(QString, sourceFilename)); return; } - qDebug() << "Recovering from uploaded file -" << uploadedFilename; + qDebug() << "Recovering from uploaded file -" << uploadedFilename << "source" << sourceFilename; bool success; QString path; std::tie(success, path) = createBackup(AUTOMATIC_BACKUP_PREFIX, PRE_UPLOAD_SUFFIX); @@ -385,7 +382,7 @@ void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise pr QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; - bool success = recoverFromBackupZip(backupName, uploadedZip); + bool success = recoverFromBackupZip(backupName, uploadedZip, sourceFilename); if (!success) { @@ -397,7 +394,7 @@ void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise pr QuaZip uploadedZip { &uploadedFile }; QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip"; - recoverFromBackupZip(backupName, uploadedZip, true); + recoverFromBackupZip(backupName, uploadedZip, sourceFilename, true); } } @@ -494,28 +491,40 @@ void DomainContentBackupManager::getAllBackupsAndStatus(MiniPromise::Promise pro status["recoveryError"] = _recoveryError; } - QVariantMap currentArchive; - QString fileName = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_FILENAME).toString(); - QString prefixFormat = "(" + QRegExp::escape(AUTOMATIC_BACKUP_PREFIX) + "|" + QRegExp::escape(MANUAL_BACKUP_PREFIX) + ")"; - QString nameFormat = "(.+)"; - QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")"; - QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" }; - if (backupNameFormat.exactMatch(fileName)) { - auto type = backupNameFormat.cap(1); - auto name = backupNameFormat.cap(2); - auto dateTime = backupNameFormat.cap(3); - auto createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT); - currentArchive["name"] = name; - currentArchive["creation_time"] = createdAt.toMSecsSinceEpoch(); - currentArchive["install_time"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_INSTALL_TIME).toULongLong(); - currentArchive["installed_by"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_ARCHIVE_INSTALLED_BY).toString(); + QString filename = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_INSTALLED_CONTENT_FILENAME).toString(); + QString name = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_INSTALLED_CONTENT_NAME).toString(); + auto creationTime = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_INSTALLED_CONTENT_CREATION_TIME).toULongLong(); + + if (name.isEmpty() || creationTime == 0) { + QString prefixFormat = "(" + QRegExp::escape(AUTOMATIC_BACKUP_PREFIX) + "|" + QRegExp::escape(MANUAL_BACKUP_PREFIX) + ")"; + QString nameFormat = "(.+)"; + QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")"; + QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" }; + + + if (backupNameFormat.exactMatch(filename)) { + if (name.isEmpty()) { + name = backupNameFormat.cap(2); + } + if (creationTime == 0) { + auto dateTime = backupNameFormat.cap(3); + creationTime = QDateTime::fromString(dateTime, DATETIME_FORMAT).toMSecsSinceEpoch(); + } + } } + QVariantMap currentArchive; + currentArchive["filename"] = filename; + currentArchive["name"] = name; + currentArchive["creation_time"] = creationTime; + currentArchive["install_time"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALL_TIME).toULongLong(); + currentArchive["installed_by"] = _settingsManager.valueForKeyPath(CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALLED_BY).toString(); + QVariantMap info { { "backups", variantBackups }, { "status", status }, - { "installed_archive", currentArchive } + { "installed_content", currentArchive } }; promise->resolve(info); diff --git a/domain-server/src/DomainContentBackupManager.h b/domain-server/src/DomainContentBackupManager.h index 6e562b1773..1f4e72b4c6 100644 --- a/domain-server/src/DomainContentBackupManager.h +++ b/domain-server/src/DomainContentBackupManager.h @@ -34,6 +34,10 @@ #include +const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" }; +const QString AUTOMATIC_BACKUP_PREFIX { "autobackup-" }; +const QString MANUAL_BACKUP_PREFIX { "backup-" }; + struct BackupItemInfo { BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) : id(pId), name(pName), absolutePath(pAbsolutePath), createdAt(pCreatedAt), isManualBackup(pIsManualBackup) { }; @@ -87,7 +91,7 @@ public slots: void createManualBackup(MiniPromise::Promise promise, const QString& name); void recoverFromBackup(MiniPromise::Promise promise, const QString& backupName); void recoverFromUploadedBackup(MiniPromise::Promise promise, QByteArray uploadedBackup); - void recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename); + void recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, QString sourceFilename); void deleteBackup(MiniPromise::Promise promise, const QString& backupName); signals: @@ -109,7 +113,7 @@ protected: std::pair createBackup(const QString& prefix, const QString& name); - bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip, bool rollingBack = false); + bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip, const QString& sourceFilename, bool rollingBack = false); private slots: void removeOldConsolidatedBackups(); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d20ddb186e..9dfbb46ca5 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2591,7 +2591,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite _pendingContentFiles.erase(sessionId); }); - _contentManager->recoverFromUploadedFile(deferred, _pendingFileContent.fileName()); + _contentManager->recoverFromUploadedFile(deferred, _pendingFileContent.fileName(), filename); } } else if (filename.endsWith(".json", Qt::CaseInsensitive) || filename.endsWith(".json.gz", Qt::CaseInsensitive)) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index a053001f0c..e28b9f6cd1 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -35,9 +35,11 @@ const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_finger const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions"; const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens"; const QString AUTOMATIC_CONTENT_ARCHIVES_GROUP = "automatic_content_archives"; -const QString CONTENT_SETTINGS_ARCHIVE_FILENAME = "installed_archive.filename"; -const QString CONTENT_SETTINGS_ARCHIVE_INSTALL_TIME = "installed_archive.install_time"; -const QString CONTENT_SETTINGS_ARCHIVE_INSTALLED_BY = "installed_archive.installed_by"; +const QString CONTENT_SETTINGS_INSTALLED_CONTENT_FILENAME = "installed_content.filename"; +const QString CONTENT_SETTINGS_INSTALLED_CONTENT_NAME = "installed_content.name"; +const QString CONTENT_SETTINGS_INSTALLED_CONTENT_CREATION_TIME = "installed_content.creation_time"; +const QString CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALL_TIME = "installed_content.install_time"; +const QString CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALLED_BY = "installed_content.installed_by"; using GroupByUUIDKey = QPair; // groupID, rankID diff --git a/domain-server/src/EntitiesBackupHandler.cpp b/domain-server/src/EntitiesBackupHandler.cpp index f306e9680e..03baec9164 100644 --- a/domain-server/src/EntitiesBackupHandler.cpp +++ b/domain-server/src/EntitiesBackupHandler.cpp @@ -57,7 +57,7 @@ void EntitiesBackupHandler::createBackup(const QString& backupName, QuaZip& zip) } } -std::pair EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip) { +std::pair EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) { if (!zip.setCurrentFile(ENTITIES_BACKUP_FILENAME)) { QString errorStr("Failed to find " + ENTITIES_BACKUP_FILENAME + " while recovering backup"); qWarning() << errorStr; diff --git a/domain-server/src/EntitiesBackupHandler.h b/domain-server/src/EntitiesBackupHandler.h index 4dd6462974..f8b6cba8a0 100644 --- a/domain-server/src/EntitiesBackupHandler.h +++ b/domain-server/src/EntitiesBackupHandler.h @@ -29,7 +29,7 @@ public: void createBackup(const QString& backupName, QuaZip& zip) override; // Recover from a full backup - std::pair recoverBackup(const QString& backupName, QuaZip& zip) override; + std::pair recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override; // Delete a skeleton backup void deleteBackup(const QString& backupName) override {} From 130e68c9b589d331d61c06456f23903ea697e363 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 25 Jul 2019 14:37:41 -0700 Subject: [PATCH 08/32] DEV-168 - make interface-installed content sets display info on web installed content section --- .../src/ContentSettingsBackupHandler.cpp | 6 ----- .../src/DomainContentBackupManager.h | 6 +++++ domain-server/src/DomainServer.cpp | 27 +++++++++++++++---- domain-server/src/DomainServer.h | 2 +- .../qml/hifi/commerce/checkout/Checkout.qml | 2 +- .../marketplaceItemTester/ItemUnderTest.qml | 2 +- .../hifi/commerce/purchases/PurchasedItem.qml | 2 +- .../qml/hifi/commerce/purchases/Purchases.qml | 2 +- interface/src/Application.cpp | 12 ++++++--- interface/src/Application.h | 2 +- interface/src/commerce/QmlCommerce.cpp | 4 +-- interface/src/commerce/QmlCommerce.h | 2 +- 12 files changed, 46 insertions(+), 23 deletions(-) diff --git a/domain-server/src/ContentSettingsBackupHandler.cpp b/domain-server/src/ContentSettingsBackupHandler.cpp index a905a0bc03..b3748a66a3 100644 --- a/domain-server/src/ContentSettingsBackupHandler.cpp +++ b/domain-server/src/ContentSettingsBackupHandler.cpp @@ -33,12 +33,6 @@ ContentSettingsBackupHandler::ContentSettingsBackupHandler(DomainServerSettingsM } static const QString CONTENT_SETTINGS_BACKUP_FILENAME = "content-settings.json"; -static const QString INSTALLED_CONTENT = "installed_content"; -static const QString INSTALLED_CONTENT_FILENAME = "filename"; -static const QString INSTALLED_CONTENT_NAME = "name"; -static const QString INSTALLED_CONTENT_CREATION_TIME = "creation_time"; -static const QString INSTALLED_CONTENT_INSTALL_TIME = "install_time"; -static const QString INSTALLED_CONTENT_INSTALLED_BY = "installed_by"; void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { diff --git a/domain-server/src/DomainContentBackupManager.h b/domain-server/src/DomainContentBackupManager.h index 1f4e72b4c6..f5957d74f5 100644 --- a/domain-server/src/DomainContentBackupManager.h +++ b/domain-server/src/DomainContentBackupManager.h @@ -37,6 +37,12 @@ const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" }; const QString AUTOMATIC_BACKUP_PREFIX { "autobackup-" }; const QString MANUAL_BACKUP_PREFIX { "backup-" }; +const QString INSTALLED_CONTENT = "installed_content"; +const QString INSTALLED_CONTENT_FILENAME = "filename"; +const QString INSTALLED_CONTENT_NAME = "name"; +const QString INSTALLED_CONTENT_CREATION_TIME = "creation_time"; +const QString INSTALLED_CONTENT_INSTALL_TIME = "install_time"; +const QString INSTALLED_CONTENT_INSTALLED_BY = "installed_by"; struct BackupItemInfo { BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) : diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9dfbb46ca5..44688d0b88 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2606,7 +2606,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") { // invoke our method to hand the new octree file off to the octree server QMetaObject::invokeMethod(this, "handleOctreeFileReplacement", - Qt::QueuedConnection, Q_ARG(QByteArray, _pendingUploadedContent)); + Qt::QueuedConnection, Q_ARG(QByteArray, _pendingUploadedContent), Q_ARG(QString, filename), Q_ARG(QString, QString())); _pendingUploadedContents.erase(sessionId); } } else { @@ -3491,7 +3491,7 @@ void DomainServer::maybeHandleReplacementEntityFile() { } } -void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { +void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name) { OctreeUtils::RawEntityData data; if (data.readOctreeDataInfoFromData(octreeFile)) { data.resetIdAndVersion(); @@ -3507,6 +3507,18 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { // process it when it comes back up qInfo() << "Wrote octree replacement file to" << replacementFilePath << "- stopping server"; + QJsonObject installed_content { + { INSTALLED_CONTENT_FILENAME, sourceFilename }, + { INSTALLED_CONTENT_NAME, name }, + { INSTALLED_CONTENT_CREATION_TIME, 0 }, + { INSTALLED_CONTENT_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() }, + { INSTALLED_CONTENT_INSTALLED_BY, "" } + }; + + QJsonObject jsonObject { { INSTALLED_CONTENT, installed_content } }; + + _settingsManager.recurseJSONObjectAndOverwriteSettings(jsonObject, ContentSettings); + QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection); } else { qWarning() << "Could not write replacement octree data to file - refusing to process"; @@ -3516,6 +3528,8 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { } } +static const QString CONTENT_SET_NAME_QUERY_PARAM = "name"; + void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { qInfo() << "Received request to replace content from a url"; auto node = DependencyManager::get()->findNodeWithAddr(message->getSenderSockAddr()); @@ -3527,13 +3541,16 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointererror(); if (networkError == QNetworkReply::NoError) { if (modelsURL.fileName().endsWith(".json.gz")) { - handleOctreeFileReplacement(reply->readAll()); + QUrlQuery urlQuery(modelsURL.query(QUrl::FullyEncoded)); + + QString itemName = urlQuery.queryItemValue(CONTENT_SET_NAME_QUERY_PARAM); + handleOctreeFileReplacement(reply->readAll(), modelsURL.fileName(), itemName); } else if (modelsURL.fileName().endsWith(".zip")) { auto deferred = makePromise("recoverFromUploadedBackup"); _contentManager->recoverFromUploadedBackup(deferred, reply->readAll()); @@ -3548,6 +3565,6 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { auto node = DependencyManager::get()->nodeWithLocalID(message->getSourceID()); if (node->getCanReplaceContent()) { - handleOctreeFileReplacement(message->readAll()); + handleOctreeFileReplacement(message->readAll(), QString(), QString()); } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 54b7fbe466..1f28169040 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -99,7 +99,7 @@ private slots: void handleDomainContentReplacementFromURLRequest(QSharedPointer message); void handleOctreeFileReplacementRequest(QSharedPointer message); - void handleOctreeFileReplacement(QByteArray octreeFile); + void handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name); void processOctreeDataRequestMessage(QSharedPointer message); void processOctreeDataPersistMessage(QSharedPointer message); diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 3ace6f381f..41ac9232e2 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -786,7 +786,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - Commerce.replaceContentSet(root.itemHref, root.certificateId); + Commerce.replaceContentSet(root.itemHref, root.certificateId, root.itemName); lightboxPopup.visible = false; rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index 966f359e92..157f3dda6a 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -36,7 +36,7 @@ Rectangle { break; case "content set": urlHandler.handleUrl("hifi://localhost/0,0,0"); - Commerce.replaceContentSet(toUrl(resource), ""); + Commerce.replaceContentSet(toUrl(resource), "", ""); break; case "entity": case "wearable": diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 0e3402a6a9..1dbcd34cce 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -729,7 +729,7 @@ Item { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId}); + sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId, itemName: root.itemName}); } else if (root.itemType === "avatar") { sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref}); } else if (root.itemType === "app") { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 9a2bf62e08..03fbbb178e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -609,7 +609,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - Commerce.replaceContentSet(msg.itemHref, msg.certID); + Commerce.replaceContentSet(msg.itemHref, msg.certID, msg.itemName); lightboxPopup.visible = false; }; lightboxPopup.visible = true; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad38599dcf..fd7102a07f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7788,9 +7788,15 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { return true; } -void Application::replaceDomainContent(const QString& url) { +static const QString CONTENT_SET_NAME_QUERY_PARAM = "name"; + +void Application::replaceDomainContent(const QString& url, const QString& itemName) { qCDebug(interfaceapp) << "Attempting to replace domain content"; - QByteArray urlData(url.toUtf8()); + QUrl msgUrl(url); + QUrlQuery urlQuery(msgUrl.query()); + urlQuery.addQueryItem(CONTENT_SET_NAME_QUERY_PARAM, itemName); + msgUrl.setQuery(urlQuery.query(QUrl::QUrl::FullyEncoded)); + QByteArray urlData(msgUrl.toString(QUrl::QUrl::FullyEncoded).toUtf8()); auto limitedNodeList = DependencyManager::get(); const auto& domainHandler = limitedNodeList->getDomainHandler(); @@ -7824,7 +7830,7 @@ bool Application::askToReplaceDomainContent(const QString& url) { QString details; if (static_cast(answer.toInt()) == QMessageBox::Yes) { // Given confirmation, send request to domain server to replace content - replaceDomainContent(url); + replaceDomainContent(url, QString()); details = "SuccessfulRequestToReplaceContent"; } else { details = "UserDeclinedToReplaceContent"; diff --git a/interface/src/Application.h b/interface/src/Application.h index 1e7180e203..913671473d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -326,7 +326,7 @@ public: bool isInterstitialMode() const { return _interstitialMode; } bool failedToConnectToEntityServer() const { return _failedToConnectToEntityServer; } - void replaceDomainContent(const QString& url); + void replaceDomainContent(const QString& url, const QString& itemName); void loadAvatarScripts(const QVector& urls); void unloadAvatarScripts(); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 046e697b6d..c8ea044f4b 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -259,7 +259,7 @@ void QmlCommerce::authorizeAssetTransfer(const QString& couponID, ledger->authorizeAssetTransfer(key, couponID, certificateID, amount, optionalMessage); } -void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) { +void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName) { if (!certificateID.isEmpty()) { auto ledger = DependencyManager::get(); ledger->updateLocation( @@ -267,7 +267,7 @@ void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& cert DependencyManager::get()->getPlaceName(), true); } - qApp->replaceDomainContent(itemHref); + qApp->replaceDomainContent(itemHref, itemName); QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, { "content_set_url", itemHref } }; diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 99b3e32e8b..713a5ee94f 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -90,7 +90,7 @@ protected: Q_INVOKABLE void transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void authorizeAssetTransfer(const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); + Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName); Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = ""); Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false); From 4b5a45209ea98de30bf93be75da18b8972effd30 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 25 Jul 2019 11:06:28 -0700 Subject: [PATCH 09/32] Prefer using LODManager.lodAngleDeg for setting manual LOD --- interface/src/LODManager.h | 2 -- scripts/simplifiedUI/ui/simplifiedUI.js | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index c0a7797561..6fd9904906 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -55,8 +55,6 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality NOTIFY worldDetailQualityChanged) - Q_PROPERTY(float octreeSizeScale READ getOctreeSizeScale WRITE setOctreeSizeScale) - Q_PROPERTY(bool automaticLODAdjust READ getAutomaticLODAdjust WRITE setAutomaticLODAdjust NOTIFY autoLODChanged) Q_PROPERTY(float presentTime READ getPresentTime) diff --git a/scripts/simplifiedUI/ui/simplifiedUI.js b/scripts/simplifiedUI/ui/simplifiedUI.js index e9f49587aa..3cbdadf47d 100644 --- a/scripts/simplifiedUI/ui/simplifiedUI.js +++ b/scripts/simplifiedUI/ui/simplifiedUI.js @@ -531,21 +531,21 @@ function maybeUpdateOutputDeviceMutedOverlay() { var oldAutomaticLODAdjust; -var oldOctreeSizeScale; +var oldLODAngleDeg; var SIMPLIFIED_UI_AUTO_LOD_ADJUST = false; -var SIMPLIFIED_UI_OCTREE_SIZE_SCALE = 32768 * 916; // Octree cell size in meters (constant) * distance in meters at which we want a 1 meter cube to be visible +var SIMPLIFIED_UI_LOD_ANGLE_DEG = 1.0 function modifyLODSettings() { oldAutomaticLODAdjust = LODManager.automaticLODAdjust; - oldOctreeSizeScale = LODManager.octreeSizeScale; + oldLODAngleDeg = LODManager.lodAngleDeg; LODManager.automaticLODAdjust = SIMPLIFIED_UI_AUTO_LOD_ADJUST; - LODManager.octreeSizeScale = SIMPLIFIED_UI_OCTREE_SIZE_SCALE; + LODManager.lodAngleDeg = SIMPLIFIED_UI_LOD_ANGLE_DEG; } function restoreLODSettings() { LODManager.automaticLODAdjust = oldAutomaticLODAdjust; - LODManager.octreeSizeScale = oldOctreeSizeScale; + LODManager.lodAngleDeg = oldLODAngleDeg; } From 94e725dc2a07c0219ce379e0a658c560d78e067b Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 25 Jul 2019 11:33:19 -0700 Subject: [PATCH 10/32] Fix rare case where script would fail to set LOD after disabling auto LOD --- interface/src/LODManager.cpp | 2 ++ interface/src/LODManager.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 2cba5f9b1b..2973208fef 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -54,6 +54,7 @@ void LODManager::setRenderTimes(float presentTime, float engineRunTime, float ba } void LODManager::autoAdjustLOD(float realTimeDelta) { + std::lock_guard { _automaticLODLock }; // The "render time" is the worse of: // - engineRunTime: Time spent in the render thread in the engine producing the gpu::Frame N @@ -235,6 +236,7 @@ void LODManager::resetLODAdjust() { } void LODManager::setAutomaticLODAdjust(bool value) { + std::lock_guard { _automaticLODLock }; _automaticLODAdjust = value; emit autoLODChanged(); } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 6fd9904906..8fd39e7161 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -12,6 +12,8 @@ #ifndef hifi_LODManager_h #define hifi_LODManager_h +#include + #include #include #include @@ -230,6 +232,7 @@ signals: private: LODManager(); + std::mutex _automaticLODLock; bool _automaticLODAdjust = true; float _presentTime{ 0.0f }; // msec From 3da5896e2268918adf20612a9ca347b882529157 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 25 Jul 2019 11:49:26 -0700 Subject: [PATCH 11/32] Bring back lodQualityLevel --- interface/src/LODManager.cpp | 8 ++++++++ interface/src/LODManager.h | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 2973208fef..0cf795e35b 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -427,3 +427,11 @@ float LODManager::getWorldDetailQuality() const { return HIGH; } + +void LODManager::setLODQualityLevel(float quality) { + _lodQualityLevel = quality; +} + +float LODManager::getLODQualityLevel() const { + return _lodQualityLevel; +} diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 8fd39e7161..649e0e8e34 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -57,6 +57,8 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality NOTIFY worldDetailQualityChanged) + Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged) + Q_PROPERTY(bool automaticLODAdjust READ getAutomaticLODAdjust WRITE setAutomaticLODAdjust NOTIFY autoLODChanged) Q_PROPERTY(float presentTime READ getPresentTime) @@ -189,6 +191,9 @@ public: void setWorldDetailQuality(float quality); float getWorldDetailQuality() const; + void setLODQualityLevel(float quality); + float getLODQualityLevel() const; + float getLODAngleDeg() const; void setLODAngleDeg(float lodAngle); float getLODAngleHalfTan() const; @@ -244,6 +249,8 @@ private: float _smoothScale{ 10.0f }; // smooth is evaluated over 10 times longer than now float _smoothRenderTime{ 0.0f }; // msec + float _lodQualityLevel{ LOD_DEFAULT_QUALITY_LEVEL }; + float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS }; float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS }; From 601b579c4265fd09dfbed810b30ca62b3fa1ff2a Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 25 Jul 2019 17:26:32 -0700 Subject: [PATCH 12/32] Set the LOD angle in simplifiedUI to current effective default, to be adjusted later --- scripts/simplifiedUI/ui/simplifiedUI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/simplifiedUI/ui/simplifiedUI.js b/scripts/simplifiedUI/ui/simplifiedUI.js index 3cbdadf47d..f4f2627c66 100644 --- a/scripts/simplifiedUI/ui/simplifiedUI.js +++ b/scripts/simplifiedUI/ui/simplifiedUI.js @@ -533,7 +533,7 @@ function maybeUpdateOutputDeviceMutedOverlay() { var oldAutomaticLODAdjust; var oldLODAngleDeg; var SIMPLIFIED_UI_AUTO_LOD_ADJUST = false; -var SIMPLIFIED_UI_LOD_ANGLE_DEG = 1.0 +var SIMPLIFIED_UI_LOD_ANGLE_DEG = 0.5; function modifyLODSettings() { oldAutomaticLODAdjust = LODManager.automaticLODAdjust; oldLODAngleDeg = LODManager.lodAngleDeg; From a9d34136260264ae33649f4664eb6c227ceb177e Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 25 Jul 2019 17:51:01 -0700 Subject: [PATCH 13/32] Delete script audio-injector wrapper when wrapped object goes --- libraries/script-engine/src/ScriptAudioInjector.cpp | 1 + libraries/script-engine/src/ScriptAudioInjector.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp index 267ac3339d..f149718b1f 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -30,6 +30,7 @@ ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) : _injector(injector) { QObject::connect(injector.data(), &AudioInjector::finished, this, &ScriptAudioInjector::finished); + connect(injector.data(), &QObject::destroyed, this, &QObject::deleteLater); } ScriptAudioInjector::~ScriptAudioInjector() { diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h index 3023623d72..5f086019de 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -137,7 +137,7 @@ signals: void finished(); private: - AudioInjectorPointer _injector; + QWeakPointer _injector; friend QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); }; From b770ff7b794dfe5aaa24c7cc6f6f6ac12c1660d8 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 25 Jul 2019 18:14:11 -0700 Subject: [PATCH 14/32] BUGZ-829 - error handling for web uploaded model files --- domain-server/src/DomainServer.cpp | 13 +++++++++---- domain-server/src/DomainServer.h | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 44688d0b88..0efa003572 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2601,14 +2601,16 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite } QByteArray& _pendingUploadedContent = _pendingUploadedContents[sessionId]; _pendingUploadedContent += dataChunk; - connection->respond(HTTPConnection::StatusCode200); if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") { // invoke our method to hand the new octree file off to the octree server - QMetaObject::invokeMethod(this, "handleOctreeFileReplacement", - Qt::QueuedConnection, Q_ARG(QByteArray, _pendingUploadedContent), Q_ARG(QString, filename), Q_ARG(QString, QString())); + if(!handleOctreeFileReplacement(_pendingUploadedContent, filename, QString())) { + connection->respond(HTTPConnection::StatusCode400); + return false; + } _pendingUploadedContents.erase(sessionId); } + connection->respond(HTTPConnection::StatusCode200); } else { connection->respond(HTTPConnection::StatusCode400); return false; @@ -3491,7 +3493,7 @@ void DomainServer::maybeHandleReplacementEntityFile() { } } -void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name) { +bool DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name) { OctreeUtils::RawEntityData data; if (data.readOctreeDataInfoFromData(octreeFile)) { data.resetIdAndVersion(); @@ -3520,11 +3522,14 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString so _settingsManager.recurseJSONObjectAndOverwriteSettings(jsonObject, ContentSettings); QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection); + return true; } else { qWarning() << "Could not write replacement octree data to file - refusing to process"; + return false; } } else { qDebug() << "Received replacement octree file that is invalid - refusing to process"; + return false; } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 1f28169040..aef59a4e4a 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -99,7 +99,7 @@ private slots: void handleDomainContentReplacementFromURLRequest(QSharedPointer message); void handleOctreeFileReplacementRequest(QSharedPointer message); - void handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name); + bool handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name); void processOctreeDataRequestMessage(QSharedPointer message); void processOctreeDataPersistMessage(QSharedPointer message); From 11d7890f486a398b500f921f7b52d046d167af78 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 25 Jul 2019 18:24:53 -0700 Subject: [PATCH 15/32] BUGZ-964: fix for incorrect color curve when rendering 3D into QML --- interface/src/ui/ResourceImageItem.cpp | 70 +++++++++++++++++++++++--- interface/src/ui/ResourceImageItem.h | 11 ++-- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/interface/src/ui/ResourceImageItem.cpp b/interface/src/ui/ResourceImageItem.cpp index f14f4ca78e..46ffffe62d 100644 --- a/interface/src/ui/ResourceImageItem.cpp +++ b/interface/src/ui/ResourceImageItem.cpp @@ -11,11 +11,52 @@ #include "ResourceImageItem.h" #include - +#include #include +#include #include + +static const char* VERTEX_SHADER = R"SHADER( +#version 450 core + +out vec2 vTexCoord; + +void main(void) { + const float depth = 0.0; + const vec4 UNIT_QUAD[4] = vec4[4]( + vec4(-1.0, -1.0, depth, 1.0), + vec4(1.0, -1.0, depth, 1.0), + vec4(-1.0, 1.0, depth, 1.0), + vec4(1.0, 1.0, depth, 1.0) + ); + vec4 pos = UNIT_QUAD[gl_VertexID]; + + gl_Position = pos; + vTexCoord = (pos.xy + 1.0) * 0.5; +} +)SHADER"; + +static const char* FRAGMENT_SHADER = R"SHADER( +#version 450 core + +uniform sampler2D sampler; + +in vec2 vTexCoord; + +out vec4 FragColor; + +vec3 color_LinearTosRGB(vec3 lrgb) { + return mix(vec3(1.055) * pow(vec3(lrgb), vec3(0.41666)) - vec3(0.055), vec3(lrgb) * vec3(12.92), vec3(lessThan(lrgb, vec3(0.0031308)))); +} + +void main() { + FragColor = vec4(color_LinearTosRGB(texture(sampler, vTexCoord).rgb), 1.0); +} +)SHADER"; + + ResourceImageItem::ResourceImageItem() : QQuickFramebufferObject() { auto textureCache = DependencyManager::get(); connect(textureCache.data(), SIGNAL(spectatorCameraFramebufferReset()), this, SLOT(update())); @@ -95,16 +136,29 @@ void ResourceImageItemRenderer::render() { } if (_ready) { _fboMutex.lock(); - _copyFbo->bind(); - QOpenGLFramebufferObject::blitFramebuffer(framebufferObject(), _copyFbo, GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT, GL_NEAREST); - // this clears the copyFbo texture - // so next frame starts fresh - helps - // when aspect ratio changes - _copyFbo->takeTexture(); + + if (!_shader) { + _shader = new QOpenGLShaderProgram(); + _shader->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, VERTEX_SHADER); + _shader->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, FRAGMENT_SHADER); + _shader->link(); + glGenVertexArrays(1, &_vao); + } + framebufferObject()->bind(); + _shader->bind(); + + auto sourceTextureId = _copyFbo->takeTexture(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, sourceTextureId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindVertexArray(_vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDeleteTextures(1, &sourceTextureId); + _copyFbo->bind(); _copyFbo->release(); - _fboMutex.unlock(); } glFlush(); diff --git a/interface/src/ui/ResourceImageItem.h b/interface/src/ui/ResourceImageItem.h index d154588094..1a679ba2ee 100644 --- a/interface/src/ui/ResourceImageItem.h +++ b/interface/src/ui/ResourceImageItem.h @@ -22,6 +22,9 @@ #include +class QOpenGLFramebufferObject; +class QOpenGLShaderProgram; + class ResourceImageItemRenderer : public QObject, public QQuickFramebufferObject::Renderer { Q_OBJECT public: @@ -30,14 +33,16 @@ public: void synchronize(QQuickFramebufferObject* item) override; void render() override; private: - bool _ready; + bool _ready{ false }; QString _url; - bool _visible; + bool _visible{ false }; NetworkTexturePointer _networkTexture; - QQuickWindow* _window; + QQuickWindow* _window{ nullptr }; QMutex _fboMutex; + uint32_t _vao{ 0 }; QOpenGLFramebufferObject* _copyFbo { nullptr }; + QOpenGLShaderProgram* _shader{ nullptr }; GLsync _fenceSync { 0 }; QTimer _updateTimer; public slots: From 908cb8156b516c159ac41cb1c8fb9dc97f541e75 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 26 Jul 2019 09:40:17 -0700 Subject: [PATCH 16/32] fix coding standards issue --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0efa003572..35b950b77c 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2604,7 +2604,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") { // invoke our method to hand the new octree file off to the octree server - if(!handleOctreeFileReplacement(_pendingUploadedContent, filename, QString())) { + if (!handleOctreeFileReplacement(_pendingUploadedContent, filename, QString())) { connection->respond(HTTPConnection::StatusCode400); return false; } From 6ef08218015ebb4a3763b9edb5532c1e98176456 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 26 Jul 2019 12:44:48 -0700 Subject: [PATCH 17/32] steam gets the oculus store commerce treatment --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1872a03221..7ba6a455f9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1225,8 +1225,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo #endif bool isStore = property(hifi::properties::OCULUS_STORE).toBool(); - - DependencyManager::get()->setLimitedCommerce(isStore); // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties? + // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties? + DependencyManager::get()->setLimitedCommerce(isStore || property(hifi::properties::STEAM).toBool()); updateHeartbeat(); From b2e07fd990101cd179b0589d8cb37c0704241fec Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 26 Jul 2019 13:02:59 -0700 Subject: [PATCH 18/32] changing raw pointer to unique pointer with custom deleter --- interface/src/ui/InteractiveWindow.cpp | 21 ++++++++------------- interface/src/ui/InteractiveWindow.h | 11 +++++++++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 4359995448..f5ae611632 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -134,14 +134,13 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native; if (properties.contains(PRESENTATION_MODE_PROPERTY)) { - presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt(); + presentationMode = (InteractiveWindowPresentationMode)properties[PRESENTATION_MODE_PROPERTY].toInt(); } - if (!_interactiveWindowProxy) { - _interactiveWindowProxy = new InteractiveWindowProxy(); - QObject::connect(_interactiveWindowProxy, &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); - QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy, &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); - } + _interactiveWindowProxy = std::unique_ptr(new InteractiveWindowProxy()); + + QObject::connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); + QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); if (properties.contains(DOCKED_PROPERTY) && presentationMode == InteractiveWindowPresentationMode::Native) { QVariantMap nativeWindowInfo = properties[DOCKED_PROPERTY].toMap(); @@ -161,7 +160,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap _dockWidget = std::shared_ptr(new DockWidget(title, mainWindow), dockWidgetDeleter); auto quickView = _dockWidget->getQuickView(); - Application::setupQmlSurface(quickView->rootContext() , true); + Application::setupQmlSurface(quickView->rootContext(), true); //add any whitelisted callbacks OffscreenUi::applyWhiteList(sourceUrl, quickView->rootContext()); @@ -201,7 +200,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap QObject::connect(quickView.get(), &QQuickView::statusChanged, [&, this] (QQuickView::Status status) { if (status == QQuickView::Ready) { QQuickItem* rootItem = _dockWidget->getRootItem(); - _dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy); + _dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy.get()); // The qmlToScript method handles the thread-safety of this call. Because the QVariant argument // passed to the sendToScript signal may wrap an externally managed and thread-unsafe QJSValue, // qmlToScript needs to be called directly, so the QJSValue can be immediately converted to a plain QVariant. @@ -222,7 +221,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap // Build the event bridge and wrapper on the main thread offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) { _qmlWindowProxy = std::shared_ptr(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter); - context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy); + context->setContextProperty(EVENT_BRIDGE_PROPERTY, _interactiveWindowProxy.get()); if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) { object->setProperty(ADDITIONAL_FLAGS_PROPERTY, properties[ADDITIONAL_FLAGS_PROPERTY].toUInt()); } @@ -313,10 +312,6 @@ void InteractiveWindow::close() { _qmlWindowProxy->deleteLater(); } - if (_interactiveWindowProxy) { - _interactiveWindowProxy->deleteLater(); - } - if (_dockWidget) { auto window = qApp->getWindow(); if (QThread::currentThread() != window->thread()) { diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index a1eede8b8a..dda71b3087 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -37,11 +37,12 @@ private: }; + class InteractiveWindowProxy : public QObject { Q_OBJECT public: InteractiveWindowProxy(){} - + public slots: void emitScriptEvent(const QVariant& scriptMessage); @@ -53,6 +54,12 @@ signals: void webEventReceived(const QVariant& message); }; +struct InteractiveWindowProxyDeleter { + void operator()(InteractiveWindowProxy * p) { + p->deleteLater(); + } +}; + namespace InteractiveWindowEnums { Q_NAMESPACE @@ -325,7 +332,7 @@ protected slots: private: std::shared_ptr _qmlWindowProxy; std::shared_ptr _dockWidget { nullptr }; - InteractiveWindowProxy *_interactiveWindowProxy{ nullptr }; + std::unique_ptr _interactiveWindowProxy; }; typedef InteractiveWindow* InteractiveWindowPointer; From 087b19d64d9fe75579ccd3c6d74f88ac5791020f Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 26 Jul 2019 13:15:01 -0700 Subject: [PATCH 19/32] removed extra space --- interface/src/ui/InteractiveWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index f5ae611632..8fdcb1d9d6 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -134,7 +134,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native; if (properties.contains(PRESENTATION_MODE_PROPERTY)) { - presentationMode = (InteractiveWindowPresentationMode)properties[PRESENTATION_MODE_PROPERTY].toInt(); + presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt(); } _interactiveWindowProxy = std::unique_ptr(new InteractiveWindowProxy()); From de0b038ee1d1bb2c82f2326216c2a2025da5c9a0 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Fri, 26 Jul 2019 13:52:38 -0700 Subject: [PATCH 20/32] trunked to a lambda for simplicity --- interface/src/ui/InteractiveWindow.cpp | 6 ++++-- interface/src/ui/InteractiveWindow.h | 10 +--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 8fdcb1d9d6..8cc2f9a3d5 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -136,8 +136,10 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap if (properties.contains(PRESENTATION_MODE_PROPERTY)) { presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt(); } - - _interactiveWindowProxy = std::unique_ptr(new InteractiveWindowProxy()); + + _interactiveWindowProxy= std::unique_ptr>(new InteractiveWindowProxy, [](InteractiveWindowProxy *p) { + p->deleteLater(); + }); QObject::connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index dda71b3087..357db3744a 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -37,7 +37,6 @@ private: }; - class InteractiveWindowProxy : public QObject { Q_OBJECT public: @@ -54,13 +53,6 @@ signals: void webEventReceived(const QVariant& message); }; -struct InteractiveWindowProxyDeleter { - void operator()(InteractiveWindowProxy * p) { - p->deleteLater(); - } -}; - - namespace InteractiveWindowEnums { Q_NAMESPACE @@ -332,7 +324,7 @@ protected slots: private: std::shared_ptr _qmlWindowProxy; std::shared_ptr _dockWidget { nullptr }; - std::unique_ptr _interactiveWindowProxy; + std::unique_ptr> _interactiveWindowProxy; }; typedef InteractiveWindow* InteractiveWindowPointer; From 03b146cfb2cfa26acf3828f19f5ad4559ba8cccc Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 26 Jul 2019 13:55:59 -0700 Subject: [PATCH 21/32] fix issue with .json.gz files failing to upload properly --- domain-server/src/DomainServer.cpp | 4 ++-- libraries/embedded-webserver/src/HTTPConnection.cpp | 1 + libraries/embedded-webserver/src/HTTPConnection.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 35b950b77c..3e8a56c82c 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2583,7 +2583,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite _pendingFileContent.close(); // Respond immediately - will timeout if we wait for restore. - connection->respond(HTTPConnection::StatusCode200); + connection->respond(HTTPConnection::StatusCode204); if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") { auto deferred = makePromise("recoverFromUploadedBackup"); @@ -2610,7 +2610,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite } _pendingUploadedContents.erase(sessionId); } - connection->respond(HTTPConnection::StatusCode200); + connection->respond(HTTPConnection::StatusCode204); } else { connection->respond(HTTPConnection::StatusCode400); return false; diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index f65cd87f6e..4c00ba676c 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -22,6 +22,7 @@ #include "HTTPManager.h" const char* HTTPConnection::StatusCode200 = "200 OK"; +const char* HTTPConnection::StatusCode204 = "204 No Content"; const char* HTTPConnection::StatusCode301 = "301 Moved Permanently"; const char* HTTPConnection::StatusCode302 = "302 Found"; const char* HTTPConnection::StatusCode400 = "400 Bad Request"; diff --git a/libraries/embedded-webserver/src/HTTPConnection.h b/libraries/embedded-webserver/src/HTTPConnection.h index 4b42acf296..eb4d2dd8c3 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.h +++ b/libraries/embedded-webserver/src/HTTPConnection.h @@ -45,6 +45,7 @@ class HTTPConnection : public QObject { public: static const char* StatusCode200; + static const char* StatusCode204; static const char* StatusCode301; static const char* StatusCode302; static const char* StatusCode400; From d9572d9e8ce2428087829825832592276bda5a8b Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 26 Jul 2019 15:35:09 -0700 Subject: [PATCH 22/32] Improved avatar-verify diagnostics --- assignment-client/src/avatars/MixerAvatar.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/avatars/MixerAvatar.cpp b/assignment-client/src/avatars/MixerAvatar.cpp index f5d598a5cf..6d6358ddf5 100644 --- a/assignment-client/src/avatars/MixerAvatar.cpp +++ b/assignment-client/src/avatars/MixerAvatar.cpp @@ -71,7 +71,7 @@ void MixerAvatar::fetchAvatarFST() { connect(fstRequest, &ResourceRequest::finished, this, &MixerAvatar::fstRequestComplete); fstRequest->send(); } else { - qCDebug(avatars) << "Couldn't create FST request for" << avatarURL; + qCDebug(avatars) << "Couldn't create FST request for" << avatarURL << getSessionUUID(); _verifyState = error; } _needsIdentityUpdate = true; @@ -84,7 +84,7 @@ void MixerAvatar::fstRequestComplete() { auto result = fstRequest->getResult(); if (result != ResourceRequest::Success) { _verifyState = error; - qCDebug(avatars) << "FST request for" << fstRequest->getUrl() << "failed:" << result; + qCDebug(avatars) << "FST request for" << fstRequest->getUrl() << "(user " << getSessionUUID() << ") failed:" << result; } else { _avatarFSTContents = fstRequest->getData(); _verifyState = receivedFST; @@ -178,7 +178,8 @@ void MixerAvatar::ownerRequestComplete() { } else { auto jsonData = QJsonDocument::fromJson(networkReply->readAll())["data"]; if (!jsonData.isUndefined() && !jsonData.toObject()["message"].isUndefined()) { - qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << ":" + qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << "(" + << getSessionUUID() << ") :" << jsonData.toObject()["message"].toString(); _verifyState = error; _pendingEvent = false; @@ -221,7 +222,7 @@ void MixerAvatar::processCertifyEvents() { } else { _needsIdentityUpdate = true; _pendingEvent = false; - qCDebug(avatars) << "Avatar" << getDisplayName() << "FAILED static certification"; + qCDebug(avatars) << "Avatar" << getDisplayName() << "(" << getSessionUUID() << ") FAILED static certification"; } } else { // FST doesn't have a certificate, so noncertified rather than failed: _pendingEvent = false; @@ -261,6 +262,8 @@ void MixerAvatar::processCertifyEvents() { _pendingEvent = true; } else { _verifyState = error; + qCDebug(avatars) << "Get owner status - couldn't parse response for" << getSessionUUID() + << ":" << _dynamicMarketResponse; } } else { qCDebug(avatars) << "Get owner status failed for " << getDisplayName() << _marketplaceIdFromURL << @@ -332,7 +335,7 @@ void MixerAvatar::sendOwnerChallenge() { nonceHash.addData(nonce); _challengeNonceHash = nonceHash.result(); - static constexpr int CHALLENGE_TIMEOUT_MS = 5 * 1000; // 5 s + static constexpr int CHALLENGE_TIMEOUT_MS = 10 * 1000; // 10 s if (_challengeTimeout) { _challengeTimeout->deleteLater(); } @@ -344,6 +347,7 @@ void MixerAvatar::sendOwnerChallenge() { _pendingEvent = false; _verifyState = verificationFailed; _needsIdentityUpdate = true; + qCDebug(avatars) << "Dynamic verification TIMED-OUT for " << getDisplayName() << getSessionUUID(); } }); _challengeTimeout->start(); From 701c457ad414b5c103aacdb9922eb55408bde132 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 26 Jul 2019 16:57:05 -0700 Subject: [PATCH 23/32] Fix issue where reset of server was prematurely causing the drop of an ajax connection which was causing an error popup. --- .../resources/web/content/js/content.js | 22 ++++++++++++++----- domain-server/src/DomainServer.cpp | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index ae9dc23536..9b5c807245 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -70,11 +70,23 @@ $(document).ready(function(){ var ajaxObject = $.ajax(ajaxParams); ajaxObject.fail(function (jqXHR, textStatus, errorThrown) { - showErrorMessage( - "Error", - "There was a problem restoring domain content.\n" - + "Please ensure that the content archive or entity file is valid and try again." - ); + // status of 0 means the connection was reset, which + // happens after the content is parsed and the server restarts + // in the case of json and json.gz files + if (jqXHR.status != 0) { + showErrorMessage( + "Error", + "There was a problem restoring domain content.\n" + + "Please ensure that the content archive or entity file is valid and try again." + ); + } else { + isRestoring = true; + + // immediately reload backup information since one should be restoring now + reloadBackupInformation(); + + swal.close(); + } }); updateProgressBars($('.upload-content-progress'), (offset + nextChunkSize) * 100 / fileSize); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 3e8a56c82c..fa4bf89ad6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2190,7 +2190,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } else if (url.path() == URI_RESTART) { - connection->respond(HTTPConnection::StatusCode200); + connection->respond(HTTPConnection::StatusCode204); restart(); return true; } else if (url.path() == URI_API_METAVERSE_INFO) { From d54bb02f477ce1259019520f89b140a3c5c65a80 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Sat, 27 Jul 2019 08:53:32 -0700 Subject: [PATCH 24/32] Fix installer process windows --- launchers/win32/LauncherDlg.cpp | 13 +++++++------ launchers/win32/LauncherManager.cpp | 11 +++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp index d7d214842d..a82056bab0 100644 --- a/launchers/win32/LauncherDlg.cpp +++ b/launchers/win32/LauncherDlg.cpp @@ -702,13 +702,14 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) { _splashStep = SPLASH_DURATION; setDrawDialog(DrawStep::DrawProcessUpdate); theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 0.0f); + } else if (theApp._manager.shouldSkipSplashScreen()) { + theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 1.0f); + setDrawDialog(DrawStep::DrawProcessFinishUpdate); + _splashStep = SPLASH_DURATION; + _showSplash = false; } else { - if (theApp._manager.shouldSkipSplashScreen()) { - _splashStep = SPLASH_DURATION; - } else { - theApp._manager.addToLog(_T("Start splash screen")); - setDrawDialog(DrawStep::DrawLogo); - } + theApp._manager.addToLog(_T("Start splash screen")); + setDrawDialog(DrawStep::DrawLogo); } } else if (_splashStep > SPLASH_DURATION && !theApp._manager.needsToWait()) { _showSplash = false; diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index d7d92a18fb..00bfe34957 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -611,11 +611,18 @@ void LauncherManager::onFileDownloaded(ProcessType type) { } void LauncherManager::restartNewLauncher() { + CString tempPath; + LauncherManager::getAndCreatePaths(LauncherManager::PathType::Temp_Directory, tempPath); + tempPath += "hql.exe"; + CString installPath; + LauncherManager::getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, installPath); + installPath += LAUNCHER_EXE_FILENAME; + CopyFile(installPath, tempPath, false); closeLog(); if (_willContinueUpdating) { - LauncherUtils::launchApplication(_tempLauncherPath, _T(" --restart --noUpdate --continueUpdating")); + LauncherUtils::launchApplication(tempPath, _T(" --restart --noUpdate --continueUpdating")); } else { - LauncherUtils::launchApplication(_tempLauncherPath, _T(" --restart --noUpdate --skipSplash")); + LauncherUtils::launchApplication(tempPath, _T(" --restart --noUpdate --skipSplash")); } Sleep(500); } From 5e81f3684f18956e7684ae11d7beb902ad5da3b9 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Sat, 27 Jul 2019 20:57:43 -0700 Subject: [PATCH 25/32] fix self install flow and progress bar --- launchers/win32/LauncherApp.cpp | 13 +++++------ launchers/win32/LauncherDlg.cpp | 11 +++++---- launchers/win32/LauncherManager.cpp | 35 +++++++++++++++-------------- launchers/win32/LauncherManager.h | 30 ++++++++++++++----------- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/launchers/win32/LauncherApp.cpp b/launchers/win32/LauncherApp.cpp index 841a0bee3b..eb3c275a77 100644 --- a/launchers/win32/LauncherApp.cpp +++ b/launchers/win32/LauncherApp.cpp @@ -42,8 +42,7 @@ BOOL CLauncherApp::InitInstance() { bool uninstalling = false; bool restarting = false; bool noUpdate = false; - bool continueUpdating = false; - bool skipSplash = false; + CLauncherDlg::DrawStep startScreen = CLauncherDlg::DrawStep::DrawLogo; if (iNumOfArgs > 1) { for (int i = 1; i < iNumOfArgs; i++) { CString curArg = CString(pArgs[i]); @@ -53,10 +52,10 @@ BOOL CLauncherApp::InitInstance() { restarting = true; } else if (curArg.Compare(_T("--noUpdate")) == 0) { noUpdate = true; - } else if (curArg.Compare(_T("--continueUpdating")) == 0) { - continueUpdating = true; - } else if (curArg.Compare(_T("--skipSplash")) == 0) { - skipSplash = true; + } else if (curArg.Compare(_T("--startScreen")) == 0) { + if (i + 1 < iNumOfArgs) { + startScreen = (CLauncherDlg::DrawStep)_wtoi(pArgs[i + 1]); + } } } } @@ -71,7 +70,7 @@ BOOL CLauncherApp::InitInstance() { if (uninstalling) { _manager.uninstall(); } else { - _manager.init(!noUpdate, continueUpdating, skipSplash); + _manager.init(!noUpdate, startScreen); } if (!_manager.hasFailed() && !_manager.installLauncher()) { return FALSE; diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp index a82056bab0..b5e144a52f 100644 --- a/launchers/win32/LauncherDlg.cpp +++ b/launchers/win32/LauncherDlg.cpp @@ -357,7 +357,7 @@ void CLauncherDlg::drawVoxel(CHwndRenderTarget* pRenderTarget) { } void CLauncherDlg::drawProgress(CHwndRenderTarget* pRenderTarget, float progress, const D2D1::ColorF& color) { - auto size = pRenderTarget->GetPixelSize(); + auto size = pRenderTarget->GetSize(); if (progress == 0.0f) { return; } else { @@ -693,16 +693,19 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) { } } } + + DrawStep startStep = theApp._manager.getStartScreen(); if (_showSplash) { if (_splashStep == 0) { if (theApp._manager.needsUninstall()) { theApp._manager.addToLog(_T("Waiting to uninstall")); setDrawDialog(DrawStep::DrawProcessUninstall); - } else if (theApp._manager.shouldContinueUpdating()) { - _splashStep = SPLASH_DURATION; + } else if (startStep == DrawStep::DrawProcessUpdate) { setDrawDialog(DrawStep::DrawProcessUpdate); theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 0.0f); - } else if (theApp._manager.shouldSkipSplashScreen()) { + } else if (startStep == DrawStep::DrawLoginLogin) { + _splashStep = SPLASH_DURATION; + } else if (startStep == DrawStep::DrawProcessFinishUpdate) { theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 1.0f); setDrawDialog(DrawStep::DrawProcessFinishUpdate); _splashStep = SPLASH_DURATION; diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 00bfe34957..0ab7bc6a4b 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -16,22 +16,24 @@ LauncherManager::LauncherManager() { + int tokenPos = 0; + _launcherVersion = CString(LAUNCHER_BUILD_VERSION).Tokenize(_T("-"), tokenPos); } LauncherManager::~LauncherManager() { } -void LauncherManager::init(BOOL allowUpdate, BOOL continueUpdating, BOOL skipSplashScreen) { +void LauncherManager::init(BOOL allowUpdate, CLauncherDlg::DrawStep startScreen) { initLog(); - int tokenPos = 0; _updateLauncherAllowed = allowUpdate; - _continueUpdating = continueUpdating; - _skipSplashScreen = skipSplashScreen; - _shouldWait = !skipSplashScreen; - if (_continueUpdating) { + _startScreen = startScreen; + CString msg; + msg.Format(_T("Start Screen: %d"), (int)startScreen); + addToLog(msg); + _shouldWait = _startScreen == CLauncherDlg::DrawStep::DrawLogo; + if (_startScreen == CLauncherDlg::DrawStep::DrawProcessUpdate) { _progressOffset = CONTINUE_UPDATING_GLOBAL_OFFSET; } - _launcherVersion = CString(LAUNCHER_BUILD_VERSION).Tokenize(_T("-"), tokenPos); addToLog(_T("Launcher is running version: " + _launcherVersion)); addToLog(_T("Getting most recent builds")); getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion); @@ -432,6 +434,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch addToLog(updatingMsg); _shouldUpdateLauncher = TRUE; _shouldDownloadLauncher = TRUE; + _willLogin = !isInstalled; _willContinueUpdating = isInstalled && newInterfaceVersion; } else { if (_updateLauncherAllowed) { @@ -611,19 +614,17 @@ void LauncherManager::onFileDownloaded(ProcessType type) { } void LauncherManager::restartNewLauncher() { - CString tempPath; - LauncherManager::getAndCreatePaths(LauncherManager::PathType::Temp_Directory, tempPath); - tempPath += "hql.exe"; - CString installPath; - LauncherManager::getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, installPath); - installPath += LAUNCHER_EXE_FILENAME; - CopyFile(installPath, tempPath, false); closeLog(); + CLauncherDlg::DrawStep startScreen = CLauncherDlg::DrawStep::DrawProcessFinishUpdate; if (_willContinueUpdating) { - LauncherUtils::launchApplication(tempPath, _T(" --restart --noUpdate --continueUpdating")); - } else { - LauncherUtils::launchApplication(tempPath, _T(" --restart --noUpdate --skipSplash")); + startScreen = CLauncherDlg::DrawStep::DrawProcessUpdate; + } else if (_willLogin) { + startScreen = CLauncherDlg::DrawStep::DrawLoginLogin; } + CStringW params; + params.Format(_T(" --restart --noUpdate --startScreen %d"), (int)startScreen); + LPTSTR par = params.GetBuffer(); + LauncherUtils::launchApplication(_tempLauncherPath, par); Sleep(500); } diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index 108327469d..d63c07316f 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -11,6 +11,7 @@ #pragma once #include "LauncherUtils.h" +#include "LauncherDlg.h" const CString DIRECTORY_NAME_APP = _T("HQ"); const CString DIRECTORY_NAME_DOWNLOADS = _T("downloads"); @@ -27,8 +28,7 @@ const float DOWNLOAD_APPLICATION_UPDATE_WEIGHT = 0.75f; const float EXTRACT_APPLICATION_UPDATE_WEIGHT = 0.25f; const float CONTINUE_UPDATING_GLOBAL_OFFSET = 0.2f; -class LauncherManager -{ +class LauncherManager { public: enum PathType { Running_Path = 0, @@ -57,22 +57,25 @@ public: UnzipApplication, Uninstall }; + LauncherManager(); ~LauncherManager(); - void init(BOOL allowUpdate, BOOL continueUpdating, BOOL skipSplashScreen); + void init(BOOL allowUpdate, CLauncherDlg::DrawStep startScreen); BOOL initLog(); BOOL addToLog(const CString& line); void closeLog(); void saveErrorLog(); BOOL getAndCreatePaths(PathType type, CString& outPath); BOOL getInstalledVersion(const CString& path, CString& version); - BOOL isApplicationInstalled(CString& version, CString& domain, + BOOL isApplicationInstalled(CString& version, CString& domain, CString& content, bool& loggedIn); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); - void getMostRecentBuilds(CString& launcherUrlOut, CString& launcherVersionOut, - CString& interfaceUrlOut, CString& interfaceVersionOut); + void getMostRecentBuilds(CString& launcherUrlOut, + CString& launcherVersionOut, + CString& interfaceUrlOut, + CString& interfaceVersionOut); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); - LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, + LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn); BOOL createConfigJSON(); BOOL createApplicationRegistryKeys(int size); @@ -90,7 +93,6 @@ public: const CString& getVersion() const { return _version; } BOOL shouldShutDown() const { return _shouldShutdown; } BOOL shouldLaunch() const { return _shouldLaunch; } - BOOL shouldSkipSplashScreen() const { return _skipSplashScreen; } BOOL needsUpdate() const { return _shouldUpdate; } BOOL needsSelfUpdate() const { return _shouldUpdateLauncher; } BOOL needsSelfDownload() const { return _shouldDownloadLauncher; } @@ -98,14 +100,17 @@ public: BOOL needsInstall() const { return _shouldInstall; } BOOL needsToWait() const { return _shouldWait; } BOOL needsRestartNewLauncher() const { return _shouldRestartNewLauncher; } - BOOL shouldContinueUpdating() const { return _continueUpdating; } BOOL willContinueUpdating() const { return _willContinueUpdating; } + CLauncherDlg::DrawStep getStartScreen() { return _startScreen; } void setDisplayName(const CString& displayName) { _displayName = displayName; } bool isLoggedIn() const { return _loggedIn; } bool hasFailed() const { return _hasFailed; } void setFailed(bool hasFailed) { _hasFailed = hasFailed; } const CString& getLatestInterfaceURL() const { return _latestApplicationURL; } - void uninstall() { _shouldUninstall = true; _shouldWait = false; }; + void uninstall() { + _shouldUninstall = true; + _shouldWait = false; + }; BOOL downloadFile(ProcessType type, const CString& url, CString& localPath); BOOL downloadContent(); @@ -149,11 +154,10 @@ private: BOOL _shouldDownloadLauncher { FALSE }; BOOL _updateLauncherAllowed { TRUE }; BOOL _shouldRestartNewLauncher { FALSE }; - BOOL _continueUpdating { FALSE }; + BOOL _willLogin { FALSE }; BOOL _willContinueUpdating { FALSE }; - BOOL _skipSplashScreen { FALSE }; + CLauncherDlg::DrawStep _startScreen; float _progressOffset { 0.0f }; float _progress { 0.0f }; CStdioFile _logFile; }; - From 8fde82dafcd774ee5f7e3a762719e2c5c4dc25c6 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 29 Jul 2019 07:57:54 -0700 Subject: [PATCH 26/32] Renamed variables --- launchers/win32/LauncherManager.cpp | 8 ++++---- launchers/win32/LauncherManager.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 0ab7bc6a4b..ed459bc48b 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -434,8 +434,8 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch addToLog(updatingMsg); _shouldUpdateLauncher = TRUE; _shouldDownloadLauncher = TRUE; - _willLogin = !isInstalled; - _willContinueUpdating = isInstalled && newInterfaceVersion; + _keepLoggingIn = !isInstalled; + _keepUpdating = isInstalled && newInterfaceVersion; } else { if (_updateLauncherAllowed) { addToLog(_T("Already running most recent build. Launching interface.exe")); @@ -616,9 +616,9 @@ void LauncherManager::onFileDownloaded(ProcessType type) { void LauncherManager::restartNewLauncher() { closeLog(); CLauncherDlg::DrawStep startScreen = CLauncherDlg::DrawStep::DrawProcessFinishUpdate; - if (_willContinueUpdating) { + if (_keepUpdating) { startScreen = CLauncherDlg::DrawStep::DrawProcessUpdate; - } else if (_willLogin) { + } else if (_keepLoggingIn) { startScreen = CLauncherDlg::DrawStep::DrawLoginLogin; } CStringW params; diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index d63c07316f..1246aff0bb 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -100,7 +100,7 @@ public: BOOL needsInstall() const { return _shouldInstall; } BOOL needsToWait() const { return _shouldWait; } BOOL needsRestartNewLauncher() const { return _shouldRestartNewLauncher; } - BOOL willContinueUpdating() const { return _willContinueUpdating; } + BOOL willContinueUpdating() const { return _keepUpdating; } CLauncherDlg::DrawStep getStartScreen() { return _startScreen; } void setDisplayName(const CString& displayName) { _displayName = displayName; } bool isLoggedIn() const { return _loggedIn; } @@ -154,8 +154,8 @@ private: BOOL _shouldDownloadLauncher { FALSE }; BOOL _updateLauncherAllowed { TRUE }; BOOL _shouldRestartNewLauncher { FALSE }; - BOOL _willLogin { FALSE }; - BOOL _willContinueUpdating { FALSE }; + BOOL _keepLoggingIn { FALSE }; + BOOL _keepUpdating { FALSE }; CLauncherDlg::DrawStep _startScreen; float _progressOffset { 0.0f }; float _progress { 0.0f }; From 854f89caced3611ffb5fc10ee2b90c3f015585a2 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Mon, 29 Jul 2019 09:39:31 -0700 Subject: [PATCH 27/32] addressing comment --- interface/src/ui/InteractiveWindow.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 8cc2f9a3d5..8ad006006c 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -137,12 +137,15 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt(); } - _interactiveWindowProxy= std::unique_ptr>(new InteractiveWindowProxy, [](InteractiveWindowProxy *p) { - p->deleteLater(); + _interactiveWindowProxy= std::unique_ptr>(new InteractiveWindowProxy, [](InteractiveWindowProxy *p) { + p->deleteLater(); }); - QObject::connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); - QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); + QObject::connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, + this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); + QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), + &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); if (properties.contains(DOCKED_PROPERTY) && presentationMode == InteractiveWindowPresentationMode::Native) { QVariantMap nativeWindowInfo = properties[DOCKED_PROPERTY].toMap(); From b3ea9d0de7cc0f6b72e8d1159d3efb6a8958ff94 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Mon, 29 Jul 2019 09:40:58 -0700 Subject: [PATCH 28/32] addressing commetn --- interface/src/ui/InteractiveWindow.cpp | 4 ++-- interface/src/ui/InteractiveWindow.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 8ad006006c..992c6abefc 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -142,9 +142,9 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap p->deleteLater(); }); - QObject::connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, + connect(_interactiveWindowProxy.get(), &InteractiveWindowProxy::webEventReceived, this, &InteractiveWindow::emitWebEvent, Qt::QueuedConnection); - QObject::connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), + connect(this, &InteractiveWindow::scriptEventReceived, _interactiveWindowProxy.get(), &InteractiveWindowProxy::emitScriptEvent, Qt::QueuedConnection); if (properties.contains(DOCKED_PROPERTY) && presentationMode == InteractiveWindowPresentationMode::Native) { diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index 357db3744a..67f0a9ea2e 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -41,7 +41,6 @@ class InteractiveWindowProxy : public QObject { Q_OBJECT public: InteractiveWindowProxy(){} - public slots: void emitScriptEvent(const QVariant& scriptMessage); From 85fa510d38cfb94dc56150eeb056641a0b1f6827 Mon Sep 17 00:00:00 2001 From: amer cerkic Date: Mon, 29 Jul 2019 10:28:31 -0700 Subject: [PATCH 29/32] addressing comment --- interface/src/ui/InteractiveWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 992c6abefc..c0f3e82b29 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -137,7 +137,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap presentationMode = (InteractiveWindowPresentationMode) properties[PRESENTATION_MODE_PROPERTY].toInt(); } - _interactiveWindowProxy= std::unique_ptr>(new InteractiveWindowProxy, [](InteractiveWindowProxy *p) { p->deleteLater(); }); From 2ea8b9efa48060686d3150670bee365a37599802 Mon Sep 17 00:00:00 2001 From: milad Date: Mon, 29 Jul 2019 14:05:55 -0700 Subject: [PATCH 30/32] changed root to micBar which had the gated property --- interface/resources/qml/hifi/audio/MicBarApplication.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/audio/MicBarApplication.qml b/interface/resources/qml/hifi/audio/MicBarApplication.qml index 3070ba3bbd..76551be906 100644 --- a/interface/resources/qml/hifi/audio/MicBarApplication.qml +++ b/interface/resources/qml/hifi/audio/MicBarApplication.qml @@ -39,8 +39,8 @@ Rectangle { } Component.onCompleted: { - AudioScriptingInterface.noiseGateOpened.connect(function() { root.gated = false; }); - AudioScriptingInterface.noiseGateClosed.connect(function() { root.gated = true; }); + AudioScriptingInterface.noiseGateOpened.connect(function() { micBar.gated = false; }); + AudioScriptingInterface.noiseGateClosed.connect(function() { micBar.gated = true; }); HMD.displayModeChanged.connect(function() { muted = AudioScriptingInterface.muted; pushToTalk = AudioScriptingInterface.pushToTalk; @@ -151,7 +151,7 @@ Rectangle { readonly property string yellow: "#C0C000"; readonly property string fill: "#55000000"; readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF"; - readonly property string icon: (muted || clipping) ? mutedColor : root.gated ? gatedColor : unmutedColor; + readonly property string icon: (muted || clipping) ? mutedColor : micBar.gated ? gatedColor : unmutedColor; } Item { @@ -169,7 +169,7 @@ Rectangle { Image { id: image; source: (pushToTalk) ? pushToTalkIcon : muted ? mutedIcon : - clipping ? clippingIcon : root.gated ? gatedIcon : unmutedIcon; + clipping ? clippingIcon : micBar.gated ? gatedIcon : unmutedIcon; width: 29; height: 32; anchors { From 677e0218efc630f9828caf2f2e0e370bbccbf693 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 30 Jul 2019 07:29:47 -0700 Subject: [PATCH 31/32] Pass a string as parameter to continue action --- launchers/win32/LauncherApp.cpp | 8 ++--- launchers/win32/LauncherDlg.cpp | 8 ++--- launchers/win32/LauncherManager.cpp | 53 +++++++++++++++++++++++------ launchers/win32/LauncherManager.h | 14 ++++++-- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/launchers/win32/LauncherApp.cpp b/launchers/win32/LauncherApp.cpp index eb3c275a77..ff63841c5a 100644 --- a/launchers/win32/LauncherApp.cpp +++ b/launchers/win32/LauncherApp.cpp @@ -42,7 +42,7 @@ BOOL CLauncherApp::InitInstance() { bool uninstalling = false; bool restarting = false; bool noUpdate = false; - CLauncherDlg::DrawStep startScreen = CLauncherDlg::DrawStep::DrawLogo; + LauncherManager::ContinueActionOnStart continueAction = LauncherManager::ContinueActionOnStart::ContinueNone; if (iNumOfArgs > 1) { for (int i = 1; i < iNumOfArgs; i++) { CString curArg = CString(pArgs[i]); @@ -52,9 +52,9 @@ BOOL CLauncherApp::InitInstance() { restarting = true; } else if (curArg.Compare(_T("--noUpdate")) == 0) { noUpdate = true; - } else if (curArg.Compare(_T("--startScreen")) == 0) { + } else if (curArg.Compare(_T("--continueAction")) == 0) { if (i + 1 < iNumOfArgs) { - startScreen = (CLauncherDlg::DrawStep)_wtoi(pArgs[i + 1]); + continueAction = LauncherManager::getContinueActionFromParam(pArgs[i + 1]); } } } @@ -70,7 +70,7 @@ BOOL CLauncherApp::InitInstance() { if (uninstalling) { _manager.uninstall(); } else { - _manager.init(!noUpdate, startScreen); + _manager.init(!noUpdate, continueAction); } if (!_manager.hasFailed() && !_manager.installLauncher()) { return FALSE; diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp index b5e144a52f..928bf7010f 100644 --- a/launchers/win32/LauncherDlg.cpp +++ b/launchers/win32/LauncherDlg.cpp @@ -694,18 +694,18 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) { } } - DrawStep startStep = theApp._manager.getStartScreen(); + LauncherManager::ContinueActionOnStart continueAction = theApp._manager.getContinueAction(); if (_showSplash) { if (_splashStep == 0) { if (theApp._manager.needsUninstall()) { theApp._manager.addToLog(_T("Waiting to uninstall")); setDrawDialog(DrawStep::DrawProcessUninstall); - } else if (startStep == DrawStep::DrawProcessUpdate) { + } else if (continueAction == LauncherManager::ContinueActionOnStart::ContinueUpdate) { setDrawDialog(DrawStep::DrawProcessUpdate); theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 0.0f); - } else if (startStep == DrawStep::DrawLoginLogin) { + } else if (continueAction == LauncherManager::ContinueActionOnStart::ContinueLogIn) { _splashStep = SPLASH_DURATION; - } else if (startStep == DrawStep::DrawProcessFinishUpdate) { + } else if (continueAction == LauncherManager::ContinueActionOnStart::ContinueFinish) { theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, 1.0f); setDrawDialog(DrawStep::DrawProcessFinishUpdate); _splashStep = SPLASH_DURATION; diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index ed459bc48b..46d65852e7 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -23,15 +23,15 @@ LauncherManager::LauncherManager() { LauncherManager::~LauncherManager() { } -void LauncherManager::init(BOOL allowUpdate, CLauncherDlg::DrawStep startScreen) { +void LauncherManager::init(BOOL allowUpdate, ContinueActionOnStart continueAction) { initLog(); _updateLauncherAllowed = allowUpdate; - _startScreen = startScreen; + _continueAction = continueAction; CString msg; - msg.Format(_T("Start Screen: %d"), (int)startScreen); + msg.Format(_T("Start Screen: %s"), getContinueActionParam(continueAction)); addToLog(msg); - _shouldWait = _startScreen == CLauncherDlg::DrawStep::DrawLogo; - if (_startScreen == CLauncherDlg::DrawStep::DrawProcessUpdate) { + _shouldWait = _continueAction == ContinueActionOnStart::ContinueNone; + if (_continueAction == ContinueActionOnStart::ContinueUpdate) { _progressOffset = CONTINUE_UPDATING_GLOBAL_OFFSET; } addToLog(_T("Launcher is running version: " + _launcherVersion)); @@ -39,6 +39,32 @@ void LauncherManager::init(BOOL allowUpdate, CLauncherDlg::DrawStep startScreen) getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion); } +CString LauncherManager::getContinueActionParam(LauncherManager::ContinueActionOnStart continueAction) { + switch (continueAction) { + case LauncherManager::ContinueActionOnStart::ContinueNone: + return _T(""); + case LauncherManager::ContinueActionOnStart::ContinueLogIn: + return _T("LogIn"); + case LauncherManager::ContinueActionOnStart::ContinueUpdate: + return _T("Update"); + case LauncherManager::ContinueActionOnStart::ContinueFinish: + return _T("Finish"); + default: + return _T(""); + } +} + +LauncherManager::ContinueActionOnStart LauncherManager::getContinueActionFromParam(const CString& param) { + if (param.Compare(_T("LogIn")) == 0) { + return ContinueActionOnStart::ContinueLogIn; + } else if (param.Compare(_T("Update")) == 0) { + return ContinueActionOnStart::ContinueUpdate; + } else if (param.Compare(_T("Finish")) == 0) { + return ContinueActionOnStart::ContinueFinish; + } else { + return ContinueActionOnStart::ContinueNone; + } +} BOOL LauncherManager::initLog() { CString logPath; auto result = getAndCreatePaths(PathType::Launcher_Directory, logPath); @@ -614,17 +640,24 @@ void LauncherManager::onFileDownloaded(ProcessType type) { } void LauncherManager::restartNewLauncher() { + CString tempPath; + LauncherManager::getAndCreatePaths(LauncherManager::PathType::Temp_Directory, tempPath); + tempPath += "hql.exe"; + CString installPath; + LauncherManager::getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, installPath); + installPath += LAUNCHER_EXE_FILENAME; + CopyFile(installPath, tempPath, false); closeLog(); - CLauncherDlg::DrawStep startScreen = CLauncherDlg::DrawStep::DrawProcessFinishUpdate; + ContinueActionOnStart continueAction = ContinueActionOnStart::ContinueFinish; if (_keepUpdating) { - startScreen = CLauncherDlg::DrawStep::DrawProcessUpdate; + continueAction = ContinueActionOnStart::ContinueUpdate; } else if (_keepLoggingIn) { - startScreen = CLauncherDlg::DrawStep::DrawLoginLogin; + continueAction = ContinueActionOnStart::ContinueLogIn; } CStringW params; - params.Format(_T(" --restart --noUpdate --startScreen %d"), (int)startScreen); + params.Format(_T(" --restart --noUpdate --continueAction %s"), getContinueActionParam(continueAction)); LPTSTR par = params.GetBuffer(); - LauncherUtils::launchApplication(_tempLauncherPath, par); + LauncherUtils::launchApplication(tempPath, par); Sleep(500); } diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index 1246aff0bb..5169edfa75 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -57,10 +57,18 @@ public: UnzipApplication, Uninstall }; + enum ContinueActionOnStart { + ContinueNone = 0, + ContinueLogIn, + ContinueUpdate, + ContinueFinish + }; LauncherManager(); ~LauncherManager(); - void init(BOOL allowUpdate, CLauncherDlg::DrawStep startScreen); + void init(BOOL allowUpdate, ContinueActionOnStart continueAction); + static CString getContinueActionParam(ContinueActionOnStart continueAction); + static ContinueActionOnStart getContinueActionFromParam(const CString& param); BOOL initLog(); BOOL addToLog(const CString& line); void closeLog(); @@ -101,7 +109,7 @@ public: BOOL needsToWait() const { return _shouldWait; } BOOL needsRestartNewLauncher() const { return _shouldRestartNewLauncher; } BOOL willContinueUpdating() const { return _keepUpdating; } - CLauncherDlg::DrawStep getStartScreen() { return _startScreen; } + ContinueActionOnStart getContinueAction() { return _continueAction; } void setDisplayName(const CString& displayName) { _displayName = displayName; } bool isLoggedIn() const { return _loggedIn; } bool hasFailed() const { return _hasFailed; } @@ -156,7 +164,7 @@ private: BOOL _shouldRestartNewLauncher { FALSE }; BOOL _keepLoggingIn { FALSE }; BOOL _keepUpdating { FALSE }; - CLauncherDlg::DrawStep _startScreen; + ContinueActionOnStart _continueAction; float _progressOffset { 0.0f }; float _progress { 0.0f }; CStdioFile _logFile; From 9fbacd49da4346c3fd63d1574297ad7ee892d7c8 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 30 Jul 2019 14:19:26 -0700 Subject: [PATCH 32/32] Delete testing code --- launchers/win32/LauncherManager.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 46d65852e7..49ae058ef5 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -640,13 +640,6 @@ void LauncherManager::onFileDownloaded(ProcessType type) { } void LauncherManager::restartNewLauncher() { - CString tempPath; - LauncherManager::getAndCreatePaths(LauncherManager::PathType::Temp_Directory, tempPath); - tempPath += "hql.exe"; - CString installPath; - LauncherManager::getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, installPath); - installPath += LAUNCHER_EXE_FILENAME; - CopyFile(installPath, tempPath, false); closeLog(); ContinueActionOnStart continueAction = ContinueActionOnStart::ContinueFinish; if (_keepUpdating) { @@ -656,8 +649,7 @@ void LauncherManager::restartNewLauncher() { } CStringW params; params.Format(_T(" --restart --noUpdate --continueAction %s"), getContinueActionParam(continueAction)); - LPTSTR par = params.GetBuffer(); - LauncherUtils::launchApplication(tempPath, par); + LauncherUtils::launchApplication(_tempLauncherPath, params.GetBuffer()); Sleep(500); }