mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 17:03:58 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into animenu
This commit is contained in:
commit
8bb4ca19cd
16 changed files with 482 additions and 40 deletions
|
@ -67,9 +67,20 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
if (argumentIndex != -1) {
|
||||
assignmentPool = argumentList[argumentIndex + 1];
|
||||
}
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
||||
// check if we were passed a wallet UUID on the command line
|
||||
// this would represent where the user running AC wants funds sent to
|
||||
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet";
|
||||
if ((argumentIndex = argumentList.indexOf(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) != -1) {
|
||||
QUuid walletUUID = QString(argumentList[argumentIndex + 1]);
|
||||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||
_requestAssignment.setWalletUUID(walletUUID);
|
||||
}
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<th>Public</th>
|
||||
<th>Local</th>
|
||||
<th>Uptime (s)</th>
|
||||
<th>Pending Credits</th>
|
||||
<th>Kill?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -42,6 +42,8 @@ $(document).ready(function(){
|
|||
var uptimeSeconds = (Date.now() - data.wake_timestamp) / 1000;
|
||||
nodesTableBody += "<td>" + uptimeSeconds.toLocaleString() + "</td>";
|
||||
|
||||
nodesTableBody += "<td>" + (typeof data.pending_credits == 'number' ? data.pending_credits.toLocaleString() : 'N/A') + "</td>";
|
||||
|
||||
nodesTableBody += "<td><span class='glyphicon glyphicon-remove' data-uuid=" + data.uuid + "></span></td>";
|
||||
nodesTableBody += "</tr>";
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
_httpsManager(NULL),
|
||||
_allAssignments(),
|
||||
_unfulfilledAssignments(),
|
||||
_pendingAssignedNodes(),
|
||||
_isUsingDTLS(false),
|
||||
_oauthProviderURL(),
|
||||
_oauthClientID(),
|
||||
|
@ -49,13 +50,14 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
|
||||
_argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) {
|
||||
// we either read a certificate and private key or were not passed one, good to load assignments
|
||||
// and set up the node list
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
|
||||
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) {
|
||||
// we either read a certificate and private key or were not passed one
|
||||
// and completed login or did not need to
|
||||
|
||||
qDebug() << "Setting up LimitedNodeList and assignments.";
|
||||
setupNodeListAndAssignments();
|
||||
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +131,7 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
|
||||
_hostname = _argumentVariantMap.value(REDIRECT_HOSTNAME_OPTION).toString();
|
||||
|
||||
if (!_oauthProviderURL.isEmpty() || !_hostname.isEmpty() || !_oauthClientID.isEmpty()) {
|
||||
if (!_oauthClientID.isEmpty()) {
|
||||
if (_oauthProviderURL.isEmpty()
|
||||
|| _hostname.isEmpty()
|
||||
|| _oauthClientID.isEmpty()
|
||||
|
@ -187,6 +189,65 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
addStaticAssignmentsToQueue();
|
||||
}
|
||||
|
||||
bool DomainServer::optionallySetupAssignmentPayment() {
|
||||
// check if we have a username and password set via env
|
||||
const QString PAY_FOR_ASSIGNMENTS_OPTION = "pay-for-assignments";
|
||||
const QString HIFI_USERNAME_ENV_KEY = "DOMAIN_SERVER_USERNAME";
|
||||
const QString HIFI_PASSWORD_ENV_KEY = "DOMAIN_SERVER_PASSWORD";
|
||||
|
||||
if (_argumentVariantMap.contains(PAY_FOR_ASSIGNMENTS_OPTION)) {
|
||||
if (!_oauthProviderURL.isEmpty()) {
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
accountManager.setAuthURL(_oauthProviderURL);
|
||||
|
||||
if (!accountManager.hasValidAccessToken()) {
|
||||
// we don't have a valid access token so we need to get one
|
||||
QString username = QProcessEnvironment::systemEnvironment().value(HIFI_USERNAME_ENV_KEY);
|
||||
QString password = QProcessEnvironment::systemEnvironment().value(HIFI_PASSWORD_ENV_KEY);
|
||||
|
||||
if (!username.isEmpty() && !password.isEmpty()) {
|
||||
accountManager.requestAccessToken(username, password);
|
||||
|
||||
// connect to loginFailed signal from AccountManager so we can quit if that is the case
|
||||
connect(&accountManager, &AccountManager::loginFailed, this, &DomainServer::loginFailed);
|
||||
} else {
|
||||
qDebug() << "Missing access-token or username and password combination. domain-server will now quit.";
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// assume that the fact we are authing against HF data server means we will pay for assignments
|
||||
// setup a timer to send transactions to pay assigned nodes every 30 seconds
|
||||
QTimer* creditSetupTimer = new QTimer(this);
|
||||
connect(creditSetupTimer, &QTimer::timeout, this, &DomainServer::setupPendingAssignmentCredits);
|
||||
|
||||
const qint64 CREDIT_CHECK_INTERVAL_MSECS = 5 * 1000;
|
||||
creditSetupTimer->start(CREDIT_CHECK_INTERVAL_MSECS);
|
||||
|
||||
QTimer* nodePaymentTimer = new QTimer(this);
|
||||
connect(nodePaymentTimer, &QTimer::timeout, this, &DomainServer::sendPendingTransactionsToServer);
|
||||
|
||||
const qint64 TRANSACTION_SEND_INTERVAL_MSECS = 30 * 1000;
|
||||
nodePaymentTimer->start(TRANSACTION_SEND_INTERVAL_MSECS);
|
||||
|
||||
} else {
|
||||
qDebug() << "Missing OAuth provider URL, but assigned node payment was enabled. domain-server will now quit.";
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DomainServer::loginFailed() {
|
||||
qDebug() << "Login to data server has failed. domain-server will now quit";
|
||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void DomainServer::parseAssignmentConfigs(QSet<Assignment::Type>& excludedTypes) {
|
||||
// check for configs from the command line, these take precedence
|
||||
const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)";
|
||||
|
@ -339,10 +400,23 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
QUuid packetUUID = uuidFromPacketHeader(packet);
|
||||
|
||||
// check if this connect request matches an assignment in the queue
|
||||
bool isFulfilledOrUnfulfilledAssignment = _allAssignments.contains(packetUUID);
|
||||
bool isAssignment = _pendingAssignedNodes.contains(packetUUID);
|
||||
SharedAssignmentPointer matchingQueuedAssignment = SharedAssignmentPointer();
|
||||
if (isFulfilledOrUnfulfilledAssignment) {
|
||||
matchingQueuedAssignment = matchingQueuedAssignmentForCheckIn(packetUUID, nodeType);
|
||||
PendingAssignedNodeData* pendingAssigneeData = NULL;
|
||||
|
||||
if (isAssignment) {
|
||||
pendingAssigneeData = _pendingAssignedNodes.take(packetUUID);
|
||||
|
||||
if (pendingAssigneeData) {
|
||||
matchingQueuedAssignment = matchingQueuedAssignmentForCheckIn(pendingAssigneeData->getAssignmentUUID(), nodeType);
|
||||
|
||||
if (matchingQueuedAssignment) {
|
||||
qDebug() << "Assignment deployed with" << uuidStringWithoutCurlyBraces(packetUUID)
|
||||
<< "matches unfulfilled assignment"
|
||||
<< uuidStringWithoutCurlyBraces(matchingQueuedAssignment->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!matchingQueuedAssignment && !_oauthProviderURL.isEmpty() && _argumentVariantMap.contains(ALLOWED_ROLES_CONFIG_KEY)) {
|
||||
|
@ -371,8 +445,8 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
}
|
||||
}
|
||||
|
||||
if ((!isFulfilledOrUnfulfilledAssignment && !STATICALLY_ASSIGNED_NODES.contains(nodeType))
|
||||
|| (isFulfilledOrUnfulfilledAssignment && matchingQueuedAssignment)) {
|
||||
if ((!isAssignment && !STATICALLY_ASSIGNED_NODES.contains(nodeType))
|
||||
|| (isAssignment && matchingQueuedAssignment)) {
|
||||
// this was either not a static assignment or it was and we had a matching one in the queue
|
||||
|
||||
// create a new session UUID for this node
|
||||
|
@ -384,8 +458,12 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
// if this was a static assignment set the UUID, set the sendingSockAddr
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(newNode->getLinkedData());
|
||||
|
||||
if (isFulfilledOrUnfulfilledAssignment) {
|
||||
nodeData->setAssignmentUUID(packetUUID);
|
||||
if (isAssignment) {
|
||||
nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID());
|
||||
nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID());
|
||||
|
||||
// now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data
|
||||
delete pendingAssigneeData;
|
||||
}
|
||||
|
||||
nodeData->setSendingSockAddr(senderSockAddr);
|
||||
|
@ -564,14 +642,21 @@ void DomainServer::readAvailableDatagrams() {
|
|||
Assignment requestAssignment(receivedPacket);
|
||||
|
||||
// Suppress these for Assignment::AgentType to once per 5 seconds
|
||||
static quint64 lastNoisyMessage = usecTimestampNow();
|
||||
quint64 timeNow = usecTimestampNow();
|
||||
const quint64 NOISY_TIME_ELAPSED = 5 * USECS_PER_SECOND;
|
||||
bool noisyMessage = false;
|
||||
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
|
||||
static QElapsedTimer noisyMessageTimer;
|
||||
static bool wasNoisyTimerStarted = false;
|
||||
|
||||
if (!wasNoisyTimerStarted) {
|
||||
noisyMessageTimer.start();
|
||||
wasNoisyTimerStarted = true;
|
||||
}
|
||||
|
||||
const quint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000;
|
||||
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessage = true;
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
|
||||
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
||||
|
@ -582,23 +667,29 @@ void DomainServer::readAvailableDatagrams() {
|
|||
// give this assignment out, either the type matches or the requestor said they will take any
|
||||
assignmentPacket.resize(numAssignmentPacketHeaderBytes);
|
||||
|
||||
// setup a copy of this assignment that will have a unique UUID, for packaging purposes
|
||||
Assignment uniqueAssignment(*assignmentToDeploy.data());
|
||||
uniqueAssignment.setUUID(QUuid::createUuid());
|
||||
|
||||
QDataStream assignmentStream(&assignmentPacket, QIODevice::Append);
|
||||
|
||||
assignmentStream << *assignmentToDeploy.data();
|
||||
assignmentStream << uniqueAssignment;
|
||||
|
||||
nodeList->getNodeSocket().writeDatagram(assignmentPacket,
|
||||
senderSockAddr.getAddress(), senderSockAddr.getPort());
|
||||
|
||||
// add the information for that deployed assignment to the hash of pending assigned nodes
|
||||
PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(),
|
||||
requestAssignment.getWalletUUID());
|
||||
_pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData);
|
||||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessage = true;
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
if (noisyMessage) {
|
||||
lastNoisyMessage = timeNow;
|
||||
}
|
||||
} else if (!_isUsingDTLS) {
|
||||
// not using DTLS, process datagram normally
|
||||
processDatagram(receivedPacket, senderSockAddr);
|
||||
|
@ -618,6 +709,97 @@ void DomainServer::readAvailableDatagrams() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::setupPendingAssignmentCredits() {
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
foreach (const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) {
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::sendPendingTransactionsToServer() {
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
||||
if (accountManager.hasValidAccessToken()) {
|
||||
|
||||
// enumerate the pending transactions and send them to the server to complete payment
|
||||
TransactionHash::iterator i = _pendingAssignmentCredits.begin();
|
||||
|
||||
JSONCallbackParameters transactionCallbackParams;
|
||||
|
||||
transactionCallbackParams.jsonCallbackReceiver = this;
|
||||
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
|
||||
|
||||
while (i != _pendingAssignmentCredits.end()) {
|
||||
accountManager.authenticatedRequest("api/v1/transactions", QNetworkAccessManager::PostOperation,
|
||||
transactionCallbackParams, i.value()->postJson().toJson());
|
||||
|
||||
// set this transaction to finalized so we don't add additional credits to it
|
||||
i.value()->setIsFinalized(true);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DomainServer::transactionJSONCallback(const QJsonObject& data) {
|
||||
// check if this was successful - if so we can remove it from our list of pending
|
||||
if (data.value("status").toString() == "success") {
|
||||
// create a dummy wallet transaction to unpack the JSON to
|
||||
WalletTransaction dummyTransaction;
|
||||
dummyTransaction.loadFromJson(data);
|
||||
|
||||
TransactionHash::iterator i = _pendingAssignmentCredits.find(dummyTransaction.getDestinationUUID());
|
||||
|
||||
while (i != _pendingAssignmentCredits.end() && i.key() == dummyTransaction.getDestinationUUID()) {
|
||||
if (i.value()->getUUID() == dummyTransaction.getUUID()) {
|
||||
// we have a match - we can remove this from the hash of pending credits
|
||||
// and delete it for clean up
|
||||
|
||||
WalletTransaction* matchingTransaction = i.value();
|
||||
_pendingAssignmentCredits.erase(i);
|
||||
delete matchingTransaction;
|
||||
|
||||
break;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
|
||||
|
@ -667,6 +849,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) {
|
||||
|
@ -695,6 +878,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;
|
||||
|
@ -764,6 +959,24 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
connection->respond(HTTPConnection::StatusCode200, assignmentDocument.toJson(), qPrintable(JSON_MIME_TYPE));
|
||||
|
||||
// we've processed this request
|
||||
return true;
|
||||
} else if (url.path() == "/transactions.json") {
|
||||
// enumerate our pending transactions and display them in an array
|
||||
QJsonObject rootObject;
|
||||
QJsonArray transactionArray;
|
||||
|
||||
TransactionHash::iterator i = _pendingAssignmentCredits.begin();
|
||||
while (i != _pendingAssignmentCredits.end()) {
|
||||
transactionArray.push_back(i.value()->toJson());
|
||||
++i;
|
||||
}
|
||||
|
||||
rootObject["pending_transactions"] = transactionArray;
|
||||
|
||||
// print out the created JSON
|
||||
QJsonDocument transactionsDocument(rootObject);
|
||||
connection->respond(HTTPConnection::StatusCode200, transactionsDocument.toJson(), qPrintable(JSON_MIME_TYPE));
|
||||
|
||||
return true;
|
||||
} else if (url.path() == QString("%1.json").arg(URI_NODES)) {
|
||||
// setup the JSON
|
||||
|
@ -1062,11 +1275,15 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
}
|
||||
|
||||
SharedAssignmentPointer DomainServer::matchingQueuedAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
|
||||
SharedAssignmentPointer DomainServer::matchingQueuedAssignmentForCheckIn(const QUuid& assignmentUUID, NodeType_t nodeType) {
|
||||
QQueue<SharedAssignmentPointer>::iterator i = _unfulfilledAssignments.begin();
|
||||
|
||||
while (i != _unfulfilledAssignments.end()) {
|
||||
if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) {
|
||||
if (i->data()->getType() == Assignment::typeForNodeType(nodeType)
|
||||
&& i->data()->getUUID() == assignmentUUID) {
|
||||
// we have an unfulfilled assignment to return
|
||||
|
||||
// return the matching assignment
|
||||
return _unfulfilledAssignments.takeAt(i - _unfulfilledAssignments.begin());
|
||||
} else {
|
||||
++i;
|
||||
|
|
|
@ -24,7 +24,12 @@
|
|||
#include <HTTPSConnection.h>
|
||||
#include <LimitedNodeList.h>
|
||||
|
||||
#include "WalletTransaction.h"
|
||||
|
||||
#include "PendingAssignedNodeData.h"
|
||||
|
||||
typedef QSharedPointer<Assignment> SharedAssignmentPointer;
|
||||
typedef QMultiHash<QUuid, WalletTransaction*> TransactionHash;
|
||||
|
||||
class DomainServer : public QCoreApplication, public HTTPSRequestHandler {
|
||||
Q_OBJECT
|
||||
|
@ -42,13 +47,18 @@ public slots:
|
|||
/// Called by NodeList to inform us a node has been killed
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
|
||||
private slots:
|
||||
void transactionJSONCallback(const QJsonObject& data);
|
||||
|
||||
private slots:
|
||||
void loginFailed();
|
||||
void readAvailableDatagrams();
|
||||
void setupPendingAssignmentCredits();
|
||||
void sendPendingTransactionsToServer();
|
||||
private:
|
||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||
bool optionallySetupOAuth();
|
||||
bool optionallyReadX509KeyAndCertificate();
|
||||
bool optionallySetupAssignmentPayment();
|
||||
|
||||
void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
|
@ -85,6 +95,8 @@ private:
|
|||
|
||||
QHash<QUuid, SharedAssignmentPointer> _allAssignments;
|
||||
QQueue<SharedAssignmentPointer> _unfulfilledAssignments;
|
||||
QHash<QUuid, PendingAssignedNodeData*> _pendingAssignedNodes;
|
||||
TransactionHash _pendingAssignmentCredits;
|
||||
|
||||
QVariantMap _argumentVariantMap;
|
||||
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
DomainServerNodeData::DomainServerNodeData() :
|
||||
_sessionSecretHash(),
|
||||
_assignmentUUID(),
|
||||
_walletUUID(),
|
||||
_paymentIntervalTimer(),
|
||||
_statsJSONObject(),
|
||||
_sendingSockAddr(),
|
||||
_isAuthenticated(true)
|
||||
{
|
||||
|
||||
_paymentIntervalTimer.start();
|
||||
}
|
||||
|
||||
void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_DomainServerNodeData_h
|
||||
#define hifi_DomainServerNodeData_h
|
||||
|
||||
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
|
@ -30,6 +32,11 @@ public:
|
|||
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||
|
||||
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; }
|
||||
|
||||
|
@ -42,6 +49,8 @@ private:
|
|||
|
||||
QHash<QUuid, QUuid> _sessionSecretHash;
|
||||
QUuid _assignmentUUID;
|
||||
QUuid _walletUUID;
|
||||
QElapsedTimer _paymentIntervalTimer;
|
||||
QJsonObject _statsJSONObject;
|
||||
HifiSockAddr _sendingSockAddr;
|
||||
bool _isAuthenticated;
|
||||
|
|
19
domain-server/src/PendingAssignedNodeData.cpp
Normal file
19
domain-server/src/PendingAssignedNodeData.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// PendingAssignedNodeData.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 "PendingAssignedNodeData.h"
|
||||
|
||||
PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID) :
|
||||
_assignmentUUID(assignmentUUID),
|
||||
_walletUUID(walletUUID)
|
||||
{
|
||||
|
||||
}
|
33
domain-server/src/PendingAssignedNodeData.h
Normal file
33
domain-server/src/PendingAssignedNodeData.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// PendingAssignedNodeData.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_PendingAssignedNodeData_h
|
||||
#define hifi_PendingAssignedNodeData_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
class PendingAssignedNodeData : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID);
|
||||
|
||||
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||
|
||||
void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; }
|
||||
const QUuid& getWalletUUID() const { return _walletUUID; }
|
||||
private:
|
||||
QUuid _assignmentUUID;
|
||||
QUuid _walletUUID;
|
||||
};
|
||||
|
||||
#endif // hifi_PendingAssignedNodeData_h
|
67
domain-server/src/WalletTransaction.cpp
Normal file
67
domain-server/src/WalletTransaction.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// 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 <QtCore/QJsonObject>
|
||||
|
||||
#include <UUID.h>
|
||||
|
||||
#include "WalletTransaction.h"
|
||||
|
||||
WalletTransaction::WalletTransaction() :
|
||||
_uuid(),
|
||||
_destinationUUID(),
|
||||
_amount(),
|
||||
_isFinalized(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WalletTransaction::WalletTransaction(const QUuid& destinationUUID, double amount) :
|
||||
_uuid(QUuid::createUuid()),
|
||||
_destinationUUID(destinationUUID),
|
||||
_amount(amount),
|
||||
_isFinalized(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const QString TRANSACTION_ID_KEY = "id";
|
||||
const QString TRANSACTION_DESTINATION_WALLET_ID_KEY = "destination_wallet_id";
|
||||
const QString TRANSACTION_AMOUNT_KEY = "amount";
|
||||
|
||||
const QString ROOT_OBJECT_TRANSACTION_KEY = "transaction";
|
||||
|
||||
QJsonDocument WalletTransaction::postJson() {
|
||||
QJsonObject rootObject;
|
||||
|
||||
rootObject.insert(ROOT_OBJECT_TRANSACTION_KEY, toJson());
|
||||
|
||||
return QJsonDocument(rootObject);
|
||||
}
|
||||
|
||||
QJsonObject WalletTransaction::toJson() {
|
||||
QJsonObject transactionObject;
|
||||
|
||||
transactionObject.insert(TRANSACTION_ID_KEY, uuidStringWithoutCurlyBraces(_uuid));
|
||||
transactionObject.insert(TRANSACTION_DESTINATION_WALLET_ID_KEY, uuidStringWithoutCurlyBraces(_destinationUUID));
|
||||
transactionObject.insert(TRANSACTION_AMOUNT_KEY, _amount);
|
||||
|
||||
return transactionObject;
|
||||
}
|
||||
|
||||
void WalletTransaction::loadFromJson(const QJsonObject& jsonObject) {
|
||||
// pull the destination wallet and ID of the transaction to match it
|
||||
QJsonObject transactionObject = jsonObject.value("data").toObject().value(ROOT_OBJECT_TRANSACTION_KEY).toObject();
|
||||
|
||||
_uuid = QUuid(transactionObject.value(TRANSACTION_ID_KEY).toString());
|
||||
_destinationUUID = QUuid(transactionObject.value(TRANSACTION_DESTINATION_WALLET_ID_KEY).toString());
|
||||
_amount = transactionObject.value(TRANSACTION_AMOUNT_KEY).toDouble();
|
||||
}
|
46
domain-server/src/WalletTransaction.h
Normal file
46
domain-server/src/WalletTransaction.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// 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 <QtCore/QJsonDocument>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
class WalletTransaction : public QObject {
|
||||
public:
|
||||
WalletTransaction();
|
||||
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; }
|
||||
void setIsFinalized(bool isFinalized) { _isFinalized = isFinalized; }
|
||||
|
||||
QJsonDocument postJson();
|
||||
QJsonObject toJson();
|
||||
void loadFromJson(const QJsonObject& jsonObject);
|
||||
private:
|
||||
QUuid _uuid;
|
||||
QUuid _destinationUUID;
|
||||
double _amount;
|
||||
bool _isFinalized;
|
||||
};
|
||||
|
||||
#endif // hifi_WalletTransaction_h
|
|
@ -136,7 +136,13 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
|||
QNetworkRequest authenticatedRequest;
|
||||
|
||||
QUrl requestURL = _authURL;
|
||||
requestURL.setPath(path);
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
requestURL.setPath(path);
|
||||
} else {
|
||||
requestURL.setPath("/" + path);
|
||||
}
|
||||
|
||||
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
|
||||
|
||||
authenticatedRequest.setUrl(requestURL);
|
||||
|
|
|
@ -63,7 +63,8 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const
|
|||
_pool(pool),
|
||||
_location(location),
|
||||
_payload(),
|
||||
_isStatic(false)
|
||||
_isStatic(false),
|
||||
_walletUUID()
|
||||
{
|
||||
if (_command == Assignment::CreateCommand) {
|
||||
// this is a newly created assignment, generate a random UUID
|
||||
|
@ -74,7 +75,8 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const
|
|||
Assignment::Assignment(const QByteArray& packet) :
|
||||
_pool(),
|
||||
_location(GlobalLocation),
|
||||
_payload()
|
||||
_payload(),
|
||||
_walletUUID()
|
||||
{
|
||||
PacketType packetType = packetTypeForPacket(packet);
|
||||
|
||||
|
@ -104,6 +106,7 @@ Assignment::Assignment(const Assignment& otherAssignment) {
|
|||
_location = otherAssignment._location;
|
||||
_pool = otherAssignment._pool;
|
||||
_payload = otherAssignment._payload;
|
||||
_walletUUID = otherAssignment._walletUUID;
|
||||
}
|
||||
|
||||
Assignment& Assignment::operator=(const Assignment& rhsAssignment) {
|
||||
|
@ -121,6 +124,7 @@ void Assignment::swap(Assignment& otherAssignment) {
|
|||
swap(_location, otherAssignment._location);
|
||||
swap(_pool, otherAssignment._pool);
|
||||
swap(_payload, otherAssignment._payload);
|
||||
swap(_walletUUID, otherAssignment._walletUUID);
|
||||
}
|
||||
|
||||
const char* Assignment::getTypeName() const {
|
||||
|
@ -156,6 +160,10 @@ QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
|||
QDataStream& operator<<(QDataStream &out, const Assignment& assignment) {
|
||||
out << (quint8) assignment._type << assignment._uuid << assignment._pool << assignment._payload;
|
||||
|
||||
if (assignment._command == Assignment::RequestCommand) {
|
||||
out << assignment._walletUUID;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -166,5 +174,9 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) {
|
|||
|
||||
in >> assignment._uuid >> assignment._pool >> assignment._payload;
|
||||
|
||||
if (assignment._command == Assignment::RequestCommand) {
|
||||
in >> assignment._walletUUID;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,9 @@ public:
|
|||
void setIsStatic(bool isStatic) { _isStatic = isStatic; }
|
||||
bool isStatic() const { return _isStatic; }
|
||||
|
||||
void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; }
|
||||
const QUuid& getWalletUUID() const { return _walletUUID; }
|
||||
|
||||
const char* getTypeName() const;
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
|
@ -98,6 +101,7 @@ protected:
|
|||
Assignment::Location _location; /// the location of the assignment, allows a domain to preferentially use local ACs
|
||||
QByteArray _payload; /// an optional payload attached to this assignment, a maximum for 1024 bytes will be packed
|
||||
bool _isStatic; /// defines if this assignment needs to be re-queued in the domain-server if it stops being fulfilled
|
||||
QUuid _walletUUID; /// the UUID for the wallet that should be paid for this assignment
|
||||
};
|
||||
|
||||
#endif // hifi_Assignment_h
|
||||
|
|
|
@ -152,10 +152,11 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) {
|
|||
|
||||
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||
PacketType checkType = packetTypeForPacket(packet);
|
||||
if (packet[1] != versionForPacketType(checkType)
|
||||
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
||||
|
||||
if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
|
||||
&& checkType != PacketTypeStunResponse) {
|
||||
PacketType mismatchType = packetTypeForPacket(packet);
|
||||
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
||||
|
||||
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
||||
|
||||
|
|
|
@ -41,19 +41,19 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL
|
|||
|
||||
nextKeyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1);
|
||||
|
||||
if (nextKeyIndex == keyIndex + 1) {
|
||||
if (nextKeyIndex == keyIndex + 1 || keyIndex == argumentList.size() - 1) {
|
||||
// there's no value associated with this option, it's a boolean
|
||||
// so add it to the variant map with NULL as value
|
||||
mergedMap.insertMulti(key, QVariant());
|
||||
} else {
|
||||
int maxIndex = (nextKeyIndex == -1) ? argumentList.size() : nextKeyIndex;
|
||||
int maxIndex = (nextKeyIndex == -1) ? argumentList.size() - 1: nextKeyIndex;
|
||||
|
||||
// there's at least one value associated with the option
|
||||
// pull the first value to start
|
||||
QString value = argumentList[keyIndex + 1];
|
||||
|
||||
// for any extra values, append them, with a space, to the value string
|
||||
for (int i = keyIndex + 2; i < maxIndex; i++) {
|
||||
for (int i = keyIndex + 2; i <= maxIndex; i++) {
|
||||
value += " " + argumentList[i];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue