diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2a4088dcc..4a829b3191 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -161,7 +161,6 @@ extern "C" { using namespace std; static QTimer locationUpdateTimer; -static QTimer balanceUpdateTimer; static QTimer identityPacketTimer; static QTimer pingTimer; @@ -677,6 +676,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); + // send a location update immediately + discoverabilityManager->updateLocation(); + connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated); @@ -688,13 +690,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); - const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * MSECS_PER_SEC; - - connect(&balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance); - balanceUpdateTimer.start(BALANCE_UPDATE_INTERVAL_MSECS); - - connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle); - auto dialogsManager = DependencyManager::get(); connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle); @@ -1197,7 +1192,6 @@ void Application::cleanupBeforeQuit() { // first stop all timers directly or by invokeMethod // depending on what thread they run in locationUpdateTimer.stop(); - balanceUpdateTimer.stop(); identityPacketTimer.stop(); pingTimer.stop(); QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection); diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 46aabe8702..a8b0a265c9 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "DiscoverabilityManager.h" @@ -29,53 +30,103 @@ DiscoverabilityManager::DiscoverabilityManager() : } const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; +const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat"; + +const QString SESSION_ID_KEY = "session_id"; void DiscoverabilityManager::updateLocation() { AccountManager& accountManager = AccountManager::getInstance(); - if (_mode.get() != Discoverability::None) { + if (_mode.get() != Discoverability::None && accountManager.isLoggedIn()) { auto addressManager = DependencyManager::get(); DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - - if (accountManager.isLoggedIn() && domainHandler.isConnected() - && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { - - // construct a QJsonObject given the user's current address information - QJsonObject rootObject; - - QJsonObject locationObject; - - QString pathString = addressManager->currentPath(); - - const QString LOCATION_KEY_IN_ROOT = "location"; - - const QString PATH_KEY_IN_LOCATION = "path"; - locationObject.insert(PATH_KEY_IN_LOCATION, pathString); - - if (!addressManager->getRootPlaceID().isNull()) { - const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; - locationObject.insert(PLACE_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); - - } else { - const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; - locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(domainHandler.getUUID())); - } - - const QString FRIENDS_ONLY_KEY_IN_LOCATION = "friends_only"; - locationObject.insert(FRIENDS_ONLY_KEY_IN_LOCATION, (_mode.get() == Discoverability::Friends)); - - rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - - accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, - QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + + // construct a QJsonObject given the user's current address information + QJsonObject rootObject; + + QJsonObject locationObject; + + QString pathString = addressManager->currentPath(); + + const QString LOCATION_KEY_IN_ROOT = "location"; + + const QString PATH_KEY_IN_LOCATION = "path"; + locationObject.insert(PATH_KEY_IN_LOCATION, pathString); + + const QString CONNECTED_KEY_IN_LOCATION = "connected"; + locationObject.insert(CONNECTED_KEY_IN_LOCATION, domainHandler.isConnected()); + + if (!addressManager->getRootPlaceID().isNull()) { + const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; + locationObject.insert(PLACE_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); } - } else { + + if (!domainHandler.getUUID().isNull()) { + const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; + locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + } + + // in case the place/domain isn't in the database, we send the network address and port + auto& domainSockAddr = domainHandler.getSockAddr(); + const QString NETWORK_ADRESS_KEY_IN_LOCATION = "network_address"; + locationObject.insert(NETWORK_ADRESS_KEY_IN_LOCATION, domainSockAddr.getAddress().toString()); + + const QString NETWORK_ADDRESS_PORT_IN_LOCATION = "network_port"; + locationObject.insert(NETWORK_ADDRESS_PORT_IN_LOCATION, domainSockAddr.getPort()); + + const QString FRIENDS_ONLY_KEY_IN_LOCATION = "friends_only"; + locationObject.insert(FRIENDS_ONLY_KEY_IN_LOCATION, (_mode.get() == Discoverability::Friends)); + + // if we have a session ID add it now, otherwise add a null value + rootObject[SESSION_ID_KEY] = _sessionID.isEmpty() ? QJsonValue() : _sessionID; + + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "handleHeartbeatResponse"; + + // figure out if we'll send a fresh location or just a simple heartbeat + auto apiPath = API_USER_HEARTBEAT_PATH; + + if (locationObject != _lastLocationObject) { + // we have a changed location, send it now + _lastLocationObject = locationObject; + + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); + + apiPath = API_USER_LOCATION_PATH; + } + + accountManager.sendRequest(apiPath, AccountManagerAuth::Required, + QNetworkAccessManager::PutOperation, + callbackParameters, QJsonDocument(rootObject).toJson()); + + } else if (UserActivityLogger::getInstance().isEnabled()) { // we still send a heartbeat to the metaverse server for stats collection - const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat"; - accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation); + + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "handleHeartbeatResponse"; + + QJsonObject heartbeatObject; + if (!_sessionID.isEmpty()) { + heartbeatObject[SESSION_ID_KEY] = _sessionID; + } else { + heartbeatObject[SESSION_ID_KEY] = QJsonValue(); + } + + accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional, + QNetworkAccessManager::PutOperation, callbackParameters, + QJsonDocument(heartbeatObject).toJson()); + } +} + +void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) { + auto dataObject = AccountManager::dataObjectFromResponse(requestReply); + + if (!dataObject.isEmpty()) { + _sessionID = dataObject[SESSION_ID_KEY].toString(); } } @@ -93,6 +144,9 @@ void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discov if (static_cast(_mode.get()) == Discoverability::None) { // if we just got set to no discoverability, make sure that we delete our location in DB removeLocation(); + } else { + // we have a discoverability mode that says we should send a location, do that right away + updateLocation(); } emit discoverabilityModeChanged(discoverabilityMode); diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 1b5adcdb5d..9a1fa7b39c 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -42,10 +42,15 @@ public slots: signals: void discoverabilityModeChanged(Discoverability::Mode discoverabilityMode); +private slots: + void handleHeartbeatResponse(QNetworkReply& requestReply); + private: DiscoverabilityManager(); Setting::Handle _mode; + QString _sessionID; + QJsonObject _lastLocationObject; }; -#endif // hifi_DiscoverabilityManager_h \ No newline at end of file +#endif // hifi_DiscoverabilityManager_h diff --git a/interface/src/scripting/AccountScriptingInterface.cpp b/interface/src/scripting/AccountScriptingInterface.cpp index 126cd53003..1b6d52ac2a 100644 --- a/interface/src/scripting/AccountScriptingInterface.cpp +++ b/interface/src/scripting/AccountScriptingInterface.cpp @@ -13,32 +13,16 @@ #include "AccountScriptingInterface.h" -AccountScriptingInterface::AccountScriptingInterface() { - AccountManager& accountManager = AccountManager::getInstance(); - connect(&accountManager, &AccountManager::balanceChanged, this, - &AccountScriptingInterface::updateBalance); -} - AccountScriptingInterface* AccountScriptingInterface::getInstance() { static AccountScriptingInterface sharedInstance; return &sharedInstance; } -float AccountScriptingInterface::getBalance() { - AccountManager& accountManager = AccountManager::getInstance(); - return accountManager.getAccountInfo().getBalanceInSatoshis(); -} - bool AccountScriptingInterface::isLoggedIn() { AccountManager& accountManager = AccountManager::getInstance(); return accountManager.isLoggedIn(); } -void AccountScriptingInterface::updateBalance() { - AccountManager& accountManager = AccountManager::getInstance(); - emit balanceChanged(accountManager.getAccountInfo().getBalanceInSatoshis()); -} - QString AccountScriptingInterface::getUsername() { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.isLoggedIn()) { diff --git a/interface/src/scripting/AccountScriptingInterface.h b/interface/src/scripting/AccountScriptingInterface.h index 578a9d6728..888149b836 100644 --- a/interface/src/scripting/AccountScriptingInterface.h +++ b/interface/src/scripting/AccountScriptingInterface.h @@ -16,17 +16,11 @@ class AccountScriptingInterface : public QObject { Q_OBJECT - AccountScriptingInterface(); -signals: - void balanceChanged(float newBalance); - public slots: static AccountScriptingInterface* getInstance(); - float getBalance(); QString getUsername(); bool isLoggedIn(); - void updateBalance(); }; #endif // hifi_AccountScriptingInterface_h diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index e97b077f24..8c23844f4e 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -66,6 +66,19 @@ JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, co } +QJsonObject AccountManager::dataObjectFromResponse(QNetworkReply &requestReply) { + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + + static const QString STATUS_KEY = "status"; + static const QString DATA_KEY = "data"; + + if (jsonObject.contains(STATUS_KEY) && jsonObject[STATUS_KEY] == "success" && jsonObject.contains(DATA_KEY)) { + return jsonObject[DATA_KEY].toObject(); + } else { + return QJsonObject(); + } +} + AccountManager::AccountManager() : _authURL(), _pendingCallbackMap() @@ -82,8 +95,6 @@ AccountManager::AccountManager() : qRegisterMetaType("QHttpMultiPart*"); qRegisterMetaType(); - - connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); } const QString DOUBLE_SLASH_SUBSTITUTE = "slashslash"; @@ -92,9 +103,6 @@ void AccountManager::logout() { // a logout means we want to delete the DataServerAccountInfo we currently have for this URL, in-memory and in file _accountInfo = DataServerAccountInfo(); - emit balanceChanged(0); - connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); - // remove this account from the account settings file removeAccountFromFile(); @@ -103,21 +111,6 @@ void AccountManager::logout() { emit usernameChanged(QString()); } -void AccountManager::updateBalance() { - if (hasValidAccessToken()) { - // ask our auth endpoint for our balance - JSONCallbackParameters callbackParameters; - callbackParameters.jsonCallbackReceiver = &_accountInfo; - callbackParameters.jsonCallbackMethod = "setBalanceFromJSON"; - - sendRequest("/api/v1/wallets/mine", AccountManagerAuth::Required, QNetworkAccessManager::GetOperation, callbackParameters); - } -} - -void AccountManager::accountInfoBalanceChanged(qint64 newBalance) { - emit balanceChanged(newBalance); -} - QString accountFileDir() { return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 0ebefafbed..108b49f678 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -77,6 +77,8 @@ public: DataServerAccountInfo& getAccountInfo() { return _accountInfo; } + static QJsonObject dataObjectFromResponse(QNetworkReply& requestReply); + public slots: void requestAccessToken(const QString& login, const QString& password); @@ -85,8 +87,6 @@ public slots: void requestAccessTokenError(QNetworkReply::NetworkError error); void requestProfileError(QNetworkReply::NetworkError error); void logout(); - void updateBalance(); - void accountInfoBalanceChanged(qint64 newBalance); void generateNewUserKeypair() { generateNewKeypair(); } void generateNewDomainKeypair(const QUuid& domainID) { generateNewKeypair(false, domainID); } @@ -98,7 +98,6 @@ signals: void loginComplete(const QUrl& authURL); void loginFailed(); void logoutComplete(); - void balanceChanged(qint64 newBalance); void newKeypair(); private slots: diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 9455fb1b88..211bfdccfa 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -31,8 +31,6 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI _xmppPassword = otherInfo._xmppPassword; _discourseApiKey = otherInfo._discourseApiKey; _walletID = otherInfo._walletID; - _balance = otherInfo._balance; - _hasBalance = otherInfo._hasBalance; _privateKey = otherInfo._privateKey; _domainID = otherInfo._domainID; } @@ -51,8 +49,6 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { swap(_xmppPassword, otherInfo._xmppPassword); swap(_discourseApiKey, otherInfo._discourseApiKey); swap(_walletID, otherInfo._walletID); - swap(_balance, otherInfo._balance); - swap(_hasBalance, otherInfo._hasBalance); swap(_privateKey, otherInfo._privateKey); swap(_domainID, otherInfo._domainID); } @@ -87,23 +83,6 @@ void DataServerAccountInfo::setWalletID(const QUuid& walletID) { } } -void DataServerAccountInfo::setBalance(qint64 balance) { - if (!_hasBalance || _balance != balance) { - _balance = balance; - _hasBalance = true; - - emit balanceChanged(_balance); - } -} - -void DataServerAccountInfo::setBalanceFromJSON(QNetworkReply& requestReply) { - QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); - if (jsonObject["status"].toString() == "success") { - qint64 balanceInSatoshis = jsonObject["data"].toObject()["wallet"].toObject()["balance"].toDouble(); - setBalance(balanceInSatoshis); - } -} - bool DataServerAccountInfo::hasProfile() const { return _username.length() > 0; } diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 6223bc008e..6ee726efde 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -43,13 +43,6 @@ public: const QUuid& getWalletID() const { return _walletID; } void setWalletID(const QUuid& walletID); - qint64 getBalance() const { return _balance; } - float getBalanceInSatoshis() const { return _balance / SATOSHIS_PER_CREDIT; } - void setBalance(qint64 balance); - bool hasBalance() const { return _hasBalance; } - void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; } - Q_INVOKABLE void setBalanceFromJSON(QNetworkReply& requestReply); - QByteArray getUsernameSignature(const QUuid& connectionToken); bool hasPrivateKey() const { return !_privateKey.isEmpty(); } void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; } @@ -65,8 +58,7 @@ public: friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info); friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info); -signals: - qint64 balanceChanged(qint64 newBalance); + private: void swap(DataServerAccountInfo& otherInfo); @@ -75,8 +67,6 @@ private: QString _xmppPassword; QString _discourseApiKey; QUuid _walletID; - qint64 _balance { 0 }; - bool _hasBalance { false }; QUuid _domainID; // if this holds account info for a domain, this holds the ID of that domain QByteArray _privateKey; diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h index a1940611bc..a512ae8887 100644 --- a/libraries/networking/src/NetworkingConstants.h +++ b/libraries/networking/src/NetworkingConstants.h @@ -18,4 +18,4 @@ namespace NetworkingConstants { const QUrl METAVERSE_SERVER_URL = QUrl("https://metaverse.highfidelity.com"); } -#endif // hifi_NetworkingConstants_h \ No newline at end of file +#endif // hifi_NetworkingConstants_h diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h index 5c1cb03e3a..c2ab93db2f 100644 --- a/libraries/networking/src/UserActivityLogger.h +++ b/libraries/networking/src/UserActivityLogger.h @@ -28,6 +28,8 @@ public: static UserActivityLogger& getInstance(); public slots: + bool isEnabled() { return !_disabled.get(); } + void disable(bool disable); void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());