diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index df946b8dcb..5f9864f45b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -60,10 +60,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : // setup a timer to send transactions to pay assigned nodes every 30 seconds QTimer* nodePaymentTimer = new QTimer(this); - connect(nodePaymentTimer, &QTimer::timeout, this, &DomainServer::payAssignedNodes); + connect(nodePaymentTimer, &QTimer::timeout, this, &DomainServer::setupPendingAssignmentCredits); - const qint64 NODE_PAYMENT_INTERVAL_MSECS = 30 * 1000; - nodePaymentTimer->start(NODE_PAYMENT_INTERVAL_MSECS); + const qint64 CREDIT_CHECK_INTERVAL = 5 * 1000; + nodePaymentTimer->start(CREDIT_CHECK_INTERVAL); } } @@ -656,14 +656,40 @@ void DomainServer::readAvailableDatagrams() { } } -void DomainServer::payAssignedNodes() { +void DomainServer::setupPendingAssignmentCredits() { // enumerate the NodeList to find the assigned nodes foreach (const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) { DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) { - // add a pending transaction for this node or increase the amount for the existing transaction + // check if we have a non-finalized transaction for this node to add this amount to + TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID()); + WalletTransaction* existingTransaction = NULL; + while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { + if (!i.value()->isFinalized()) { + existingTransaction = i.value(); + break; + } else { + ++i; + } + } + + qint64 elapsedMsecsSinceLastPayment = nodeData->getPaymentIntervalTimer().elapsed(); + nodeData->getPaymentIntervalTimer().restart(); + + const float CREDITS_PER_HOUR = 3; + const float CREDITS_PER_MSEC = CREDITS_PER_HOUR / (60 * 60 * 1000); + + float pendingCredits = elapsedMsecsSinceLastPayment * CREDITS_PER_MSEC; + + if (existingTransaction) { + existingTransaction->incrementAmount(pendingCredits); + } else { + // create a fresh transaction to pay this node, there is no transaction to append to + WalletTransaction* freshTransaction = new WalletTransaction(nodeData->getWalletUUID(), pendingCredits); + _pendingAssignmentCredits.insert(nodeData->getWalletUUID(), freshTransaction); + } } } } @@ -717,6 +743,7 @@ const char JSON_KEY_TYPE[] = "type"; const char JSON_KEY_PUBLIC_SOCKET[] = "public"; const char JSON_KEY_LOCAL_SOCKET[] = "local"; const char JSON_KEY_POOL[] = "pool"; +const char JSON_KEY_PENDING_CREDITS[] = "pending_credits"; const char JSON_KEY_WAKE_TIMESTAMP[] = "wake_timestamp"; QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { @@ -745,6 +772,18 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { SharedAssignmentPointer matchingAssignment = _allAssignments.value(nodeData->getAssignmentUUID()); if (matchingAssignment) { nodeJson[JSON_KEY_POOL] = matchingAssignment->getPool(); + + if (!nodeData->getWalletUUID().isNull()) { + TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID()); + double pendingCreditAmount = 0; + + while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { + pendingCreditAmount += i.value()->getAmount(); + ++i; + } + + nodeJson[JSON_KEY_PENDING_CREDITS] = pendingCreditAmount; + } } return nodeJson; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 281a10d88b..cb011be16b 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -24,9 +24,12 @@ #include #include +#include "WalletTransaction.h" + #include "PendingAssignedNodeData.h" typedef QSharedPointer SharedAssignmentPointer; +typedef QMultiHash TransactionHash; class DomainServer : public QCoreApplication, public HTTPSRequestHandler { Q_OBJECT @@ -46,7 +49,7 @@ public slots: private slots: void readAvailableDatagrams(); - void payAssignedNodes(); + void setupPendingAssignmentCredits(); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); @@ -88,6 +91,7 @@ private: QHash _allAssignments; QQueue _unfulfilledAssignments; QHash _pendingAssignedNodes; + TransactionHash _pendingAssignmentCredits; QVariantMap _argumentVariantMap; diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index bdf088c19e..68903cc106 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -21,11 +21,12 @@ DomainServerNodeData::DomainServerNodeData() : _sessionSecretHash(), _assignmentUUID(), _walletUUID(), + _paymentIntervalTimer(), _statsJSONObject(), _sendingSockAddr(), _isAuthenticated(true) { - + _paymentIntervalTimer.start(); } void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) { diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index a8935bea00..a7d7233874 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -12,6 +12,8 @@ #ifndef hifi_DomainServerNodeData_h #define hifi_DomainServerNodeData_h + +#include #include #include @@ -33,6 +35,8 @@ public: void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } + QElapsedTimer& getPaymentIntervalTimer() { return _paymentIntervalTimer; } + void setSendingSockAddr(const HifiSockAddr& sendingSockAddr) { _sendingSockAddr = sendingSockAddr; } const HifiSockAddr& getSendingSockAddr() { return _sendingSockAddr; } @@ -46,6 +50,7 @@ private: QHash _sessionSecretHash; QUuid _assignmentUUID; QUuid _walletUUID; + QElapsedTimer _paymentIntervalTimer; QJsonObject _statsJSONObject; HifiSockAddr _sendingSockAddr; bool _isAuthenticated; diff --git a/domain-server/src/WalletTransaction.cpp b/domain-server/src/WalletTransaction.cpp new file mode 100644 index 0000000000..400eeb0688 --- /dev/null +++ b/domain-server/src/WalletTransaction.cpp @@ -0,0 +1,43 @@ +// +// WalletTransaction.cpp +// domain-server/src +// +// Created by Stephen Birarda on 2014-05-20. +// Copyright 2014 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 + +#include + +#include "WalletTransaction.h" + +WalletTransaction::WalletTransaction(const QUuid& destinationUUID, double amount) : + _uuid(QUuid::createUuid()), + _destinationUUID(destinationUUID), + _amount(amount), + _isFinalized(false) +{ + +} + +QJsonDocument WalletTransaction::postJson() { + QJsonObject rootObject; + QJsonObject transactionObject; + + const QString TRANSCATION_ID_KEY = "id"; + const QString TRANSACTION_DESTINATION_WALLET_ID_KEY = "destination_wallet_id"; + const QString TRANSACTION_AMOUNT_KEY = "amount"; + + transactionObject.insert(TRANSCATION_ID_KEY, uuidStringWithoutCurlyBraces(_uuid)); + transactionObject.insert(TRANSACTION_DESTINATION_WALLET_ID_KEY, uuidStringWithoutCurlyBraces(_destinationUUID)); + transactionObject.insert(TRANSACTION_AMOUNT_KEY, _amount); + + const QString ROOT_OBJECT_TRANSACTION_KEY = "transaction"; + rootObject.insert(ROOT_OBJECT_TRANSACTION_KEY, transactionObject); + + return QJsonDocument(rootObject); +} \ No newline at end of file diff --git a/domain-server/src/WalletTransaction.h b/domain-server/src/WalletTransaction.h new file mode 100644 index 0000000000..f704042804 --- /dev/null +++ b/domain-server/src/WalletTransaction.h @@ -0,0 +1,42 @@ +// +// WalletTransaction.h +// domain-server/src +// +// Created by Stephen Birarda on 2014-05-20. +// Copyright 2014 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 +// + +#ifndef hifi_WalletTransaction_h +#define hifi_WalletTransaction_h + +#include +#include +#include + +class WalletTransaction : public QObject { +public: + WalletTransaction(const QUuid& destinationUUID, double amount); + + const QUuid& getUUID() const { return _uuid; } + + void setDestinationUUID(const QUuid& destinationUUID) { _destinationUUID = destinationUUID; } + const QUuid& getDestinationUUID() const { return _destinationUUID; } + + double getAmount() const { return _amount; } + void setAmount(double amount) { _amount = amount; } + void incrementAmount(double increment) { _amount += increment; } + + bool isFinalized() const { return _isFinalized; } + + QJsonDocument postJson(); +private: + QUuid _uuid; + QUuid _destinationUUID; + double _amount; + bool _isFinalized; +}; + +#endif // hifi_WalletTransaction_h \ No newline at end of file