394 lines · 15.9 KB · C++
RawDownload
////  QmlCommerce.cpp//  interface/src/commerce////  Created by Howard Stearns on 8/4/17.//  Copyright 2017 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "QmlCommerce.h"#include "CommerceLogging.h"#include "Application.h"#include "DependencyManager.h"#include "Ledger.h"#include "Wallet.h"#include <AccountManager.h>#include <Application.h>#include <UserActivityLogger.h>#include <ScriptEngines.h>#include <ui/TabletScriptingInterface.h>#include "scripting/HMDScriptingInterface.h" QmlCommerce::QmlCommerce() {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);    connect(ledger.data(), &Ledger::balanceResult, this, &QmlCommerce::balanceResult);    connect(ledger.data(), &Ledger::inventoryResult, this, &QmlCommerce::inventoryResult);    connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult);    connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult);    connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);    connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult);    connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult);    connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult);    connect(ledger.data(), &Ledger::alreadyOwnedResult, this, &QmlCommerce::alreadyOwnedResult);    connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus);    connect(ledger.data(), &Ledger::transferAssetToNodeResult, this, &QmlCommerce::transferAssetToNodeResult);    connect(ledger.data(), &Ledger::transferAssetToUsernameResult, this, &QmlCommerce::transferAssetToUsernameResult);    connect(ledger.data(), &Ledger::availableUpdatesResult, this, &QmlCommerce::availableUpdatesResult);    connect(ledger.data(), &Ledger::updateItemResult, this, &QmlCommerce::updateItemResult);     auto accountManager = DependencyManager::get<AccountManager>();    connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { setPassphrase(""); });     _appsPath = PathUtils::getAppDataPath() + "Apps/";} void QmlCommerce::getWalletStatus() {    auto wallet = DependencyManager::get<Wallet>();    wallet->getWalletStatus();} void QmlCommerce::getLoginStatus() {    emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());} void QmlCommerce::getKeyFilePathIfExists() {    auto wallet = DependencyManager::get<Wallet>();    emit keyFilePathIfExistsResult(wallet->getKeyFilePath());} bool QmlCommerce::copyKeyFileFrom(const QString& pathname) {    auto wallet = DependencyManager::get<Wallet>();    return wallet->copyKeyFileFrom(pathname);} void QmlCommerce::getWalletAuthenticatedStatus() {    auto wallet = DependencyManager::get<Wallet>();    emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());} void QmlCommerce::getSecurityImage() {    auto wallet = DependencyManager::get<Wallet>();    wallet->getSecurityImage();} void QmlCommerce::chooseSecurityImage(const QString& imageFile) {    auto wallet = DependencyManager::get<Wallet>();    wallet->chooseSecurityImage(imageFile);} void QmlCommerce::buy(const QString& assetId, int cost, const bool controlledFailure) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList keys = wallet->listPublicKeys();    if (keys.count() == 0) {        QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };        return emit buyResult(result);    }    QString key = keys[0];    // For now, we receive at the same key that pays for it.    ledger->buy(key, cost, assetId, key, controlledFailure);} void QmlCommerce::balance() {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList cachedPublicKeys = wallet->listPublicKeys();    if (!cachedPublicKeys.isEmpty()) {        ledger->balance(cachedPublicKeys);    }} void QmlCommerce::inventory(const QString& editionFilter,                            const QString& typeFilter,                            const QString& titleFilter,                            const int& page,                            const int& perPage) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList cachedPublicKeys = wallet->listPublicKeys();    if (!cachedPublicKeys.isEmpty()) {        ledger->inventory(editionFilter, typeFilter, titleFilter, page, perPage);    }} void QmlCommerce::history(const int& pageNumber, const int& itemsPerPage) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList cachedPublicKeys = wallet->listPublicKeys();    if (!cachedPublicKeys.isEmpty()) {        ledger->history(cachedPublicKeys, pageNumber, itemsPerPage);    }} void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString& newPassphrase) {    auto wallet = DependencyManager::get<Wallet>();    if (wallet->getPassphrase()->isEmpty()) {        emit changePassphraseStatusResult(wallet->setPassphrase(newPassphrase));    } else if (wallet->getPassphrase() == oldPassphrase && !newPassphrase.isEmpty()) {        emit changePassphraseStatusResult(wallet->changePassphrase(newPassphrase));    } else {        emit changePassphraseStatusResult(false);    }} void QmlCommerce::setSoftReset() {    auto wallet = DependencyManager::get<Wallet>();    wallet->setSoftReset();} void QmlCommerce::clearWallet() {    auto wallet = DependencyManager::get<Wallet>();    wallet->clear();} void QmlCommerce::setPassphrase(const QString& passphrase) {    auto wallet = DependencyManager::get<Wallet>();    wallet->setPassphrase(passphrase);    getWalletAuthenticatedStatus();} void QmlCommerce::generateKeyPair() {    auto wallet = DependencyManager::get<Wallet>();    wallet->generateKeyPair();    getWalletAuthenticatedStatus();} void QmlCommerce::account() {    auto ledger = DependencyManager::get<Ledger>();    ledger->account();} void QmlCommerce::certificateInfo(const QString& certificateId) {    auto ledger = DependencyManager::get<Ledger>();    ledger->certificateInfo(certificateId);} void QmlCommerce::transferAssetToNode(const QString& nodeID,                                      const QString& certificateID,                                      const int& amount,                                      const QString& optionalMessage) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList keys = wallet->listPublicKeys();    if (keys.count() == 0) {        QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };        return emit transferAssetToNodeResult(result);    }    QString key = keys[0];    ledger->transferAssetToNode(key, nodeID, certificateID, amount, optionalMessage);} void QmlCommerce::transferAssetToUsername(const QString& username,                                          const QString& certificateID,                                          const int& amount,                                          const QString& optionalMessage) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList keys = wallet->listPublicKeys();    if (keys.count() == 0) {        QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };        return emit transferAssetToUsernameResult(result);    }    QString key = keys[0];    ledger->transferAssetToUsername(key, username, certificateID, amount, optionalMessage);} void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) {    auto ledger = DependencyManager::get<Ledger>();    ledger->updateLocation(certificateID, DependencyManager::get<AddressManager>()->getPlaceName(), true);    qApp->replaceDomainContent(itemHref);    QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, { "content_set_url", itemHref } };    UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties);     emit contentSetChanged(itemHref);} void QmlCommerce::alreadyOwned(const QString& marketplaceId) {    auto ledger = DependencyManager::get<Ledger>();    ledger->alreadyOwned(marketplaceId);} QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) {    QString installedAppsFromMarketplace;    QStringList runningScripts = DependencyManager::get<ScriptEngines>()->getRunningScripts();     QDir directory(_appsPath);    QStringList apps = directory.entryList(QStringList("*.app.json"));    foreach (QString appFileName, apps) {        // If we were supplied a "justInstalledAppID" argument, that means we're entering this function        // to get the new list of installed apps immediately after installing an app.        // In that case, the app we installed may not yet have its associated script running -        // that task is asynchronous and takes a nonzero amount of time. This is especially true        // for apps that are not in Interface's script cache.        // Thus, we protect against deleting the .app.json from the user's disk (below)        // by skipping that check for the app we just installed.        if ((justInstalledAppID != "") && ((justInstalledAppID + ".app.json") == appFileName)) {            continue;        }         QFile appFile(_appsPath + appFileName);        if (appFile.open(QIODevice::ReadOnly)) {            QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll());             appFile.close();             QJsonObject appFileJsonObject = appFileJsonDocument.object();            QString scriptURL = appFileJsonObject["scriptURL"].toString();             // If the script .app.json is on the user's local disk but the associated script isn't running            // for some reason (i.e. the user stopped it from Running Scripts),            // delete the .app.json from the user's local disk.            if (!runningScripts.contains(scriptURL)) {                if (!appFile.remove()) {                    qCWarning(commerce) << "Couldn't delete local .app.json file (app's script isn't running). App filename is:"                                        << appFileName;                }            } else {                installedAppsFromMarketplace += appFileName;                installedAppsFromMarketplace += ",";            }        } else {            qCDebug(commerce) << "Couldn't open local .app.json file for reading.";        }    }     return installedAppsFromMarketplace;} bool QmlCommerce::installApp(const QString& itemHref) {    if (!QDir(_appsPath).exists()) {        if (!QDir().mkdir(_appsPath)) {            qCDebug(commerce) << "Couldn't make _appsPath directory.";            return false;        }    }     QUrl appHref(itemHref);     auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, appHref);     if (!request) {        qCDebug(commerce) << "Couldn't create resource request for app.";        return false;    }     connect(request, &ResourceRequest::finished, this, [=]() {        if (request->getResult() != ResourceRequest::Success) {            qCDebug(commerce) << "Failed to get .app.json file from remote.";            return false;        }         // Copy the .app.json to the apps directory inside %AppData%/High Fidelity/Interface        auto requestData = request->getData();        QFile appFile(_appsPath + "/" + appHref.fileName());        if (!appFile.open(QIODevice::WriteOnly)) {            qCDebug(commerce) << "Couldn't open local .app.json file for creation.";            return false;        }        if (appFile.write(requestData) == -1) {            qCDebug(commerce) << "Couldn't write to local .app.json file.";            return false;        }        // Close the file        appFile.close();         // Read from the returned datastream to know what .js to add to Running Scripts        QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(requestData);        QJsonObject appFileJsonObject = appFileJsonDocument.object();        QString scriptUrl = appFileJsonObject["scriptURL"].toString();         if ((DependencyManager::get<ScriptEngines>()->loadScript(scriptUrl.trimmed())).isNull()) {            qCDebug(commerce) << "Couldn't load script.";            return false;        }         QFileInfo appFileInfo(appFile);        emit appInstalled(appFileInfo.baseName());        return true;    });    request->send();    return true;} bool QmlCommerce::uninstallApp(const QString& itemHref) {    QUrl appHref(itemHref);     // Read from the file to know what .js script to stop    QFile appFile(_appsPath + "/" + appHref.fileName());    if (!appFile.open(QIODevice::ReadOnly)) {        qCDebug(commerce)            << "Couldn't open local .app.json file for deletion. Cannot continue with app uninstallation. App filename is:"            << appHref.fileName();        return false;    }    QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll());    QJsonObject appFileJsonObject = appFileJsonDocument.object();    QString scriptUrl = appFileJsonObject["scriptURL"].toString();     if (!DependencyManager::get<ScriptEngines>()->stopScript(scriptUrl.trimmed(), false)) {        qCWarning(commerce) << "Couldn't stop script during app uninstall. Continuing anyway. ScriptURL is:"                            << scriptUrl.trimmed();    }     // Delete the .app.json from the filesystem    // remove() closes the file first.    if (!appFile.remove()) {        qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:"                            << appHref.fileName();    }     QFileInfo appFileInfo(appFile);    emit appUninstalled(appFileInfo.baseName());    return true;} bool QmlCommerce::openApp(const QString& itemHref) {    QUrl appHref(itemHref);     // Read from the file to know what .html or .qml document to open    QFile appFile(_appsPath + "/" + appHref.fileName());    if (!appFile.open(QIODevice::ReadOnly)) {        qCDebug(commerce) << "Couldn't open local .app.json file.";        return false;    }    QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll());    QJsonObject appFileJsonObject = appFileJsonDocument.object();    QString homeUrl = appFileJsonObject["homeURL"].toString();     auto tablet = dynamic_cast<TabletProxy*>(        DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system"));    if (homeUrl.contains(".qml", Qt::CaseInsensitive)) {        tablet->loadQMLSource(homeUrl);    } else if (homeUrl.contains(".html", Qt::CaseInsensitive)) {        tablet->gotoWebScreen(homeUrl);    } else {        qCDebug(commerce) << "Attempted to open unknown type of homeURL!";        return false;    }     DependencyManager::get<HMDScriptingInterface>()->openTablet();     return true;} void QmlCommerce::getAvailableUpdates(const QString& itemId) {    auto ledger = DependencyManager::get<Ledger>();    ledger->getAvailableUpdates(itemId);} void QmlCommerce::updateItem(const QString& certificateId) {    auto ledger = DependencyManager::get<Ledger>();    auto wallet = DependencyManager::get<Wallet>();    QStringList keys = wallet->listPublicKeys();    if (keys.count() == 0) {        QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };        return emit updateItemResult(result);    }    QString key = keys[0];    ledger->updateItem(key, certificateId);}