diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 551bed795d..42dc9a047d 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include #include + +#include #include #include #include @@ -244,6 +247,10 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _averageLoopTime.updateAverage(0); qDebug() << "Octree server starting... [" << this << "]"; + + // make sure the AccountManager has an Auth URL for payment redemptions + + AccountManager::getInstance().setAuthURL(DEFAULT_NODE_AUTH_URL); } OctreeServer::~OctreeServer() { @@ -857,6 +864,8 @@ void OctreeServer::readPendingDatagrams() { } } else if (packetType == PacketTypeJurisdictionRequest) { _jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket); + } else if (packetType == PacketTypeSignedTransactionPayment) { + handleSignedTransactionPayment(packetType, receivedPacket); } else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) { _octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket); } else { @@ -1204,6 +1213,49 @@ QString OctreeServer::getStatusLink() { return result; } +void OctreeServer::handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram) { + // for now we're not verifying that this is actual payment for any octree edits + // just use the AccountManager to send it up to the data server and have it redeemed + AccountManager& accountManager = AccountManager::getInstance(); + + const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE = 72; + const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE = 256; + + int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(packetType); + + // pull out the transaction message in binary + QByteArray messageHex = datagram.mid(numBytesPacketHeader, NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE).toHex(); + // pull out the binary signed message digest + QByteArray signatureHex = datagram.mid(numBytesPacketHeader + NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE, + NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE).toHex(); + + // setup the QJSONObject we are posting + QJsonObject postObject; + + const QString TRANSACTION_OBJECT_MESSAGE_KEY = "message"; + const QString TRANSACTION_OBJECT_SIGNATURE_KEY = "signature"; + const QString POST_OBJECT_TRANSACTION_KEY = "transaction"; + + QJsonObject transactionObject; + transactionObject.insert(TRANSACTION_OBJECT_MESSAGE_KEY, QString(messageHex)); + transactionObject.insert(TRANSACTION_OBJECT_SIGNATURE_KEY, QString(signatureHex)); + + postObject.insert(POST_OBJECT_TRANSACTION_KEY, transactionObject); + + // setup our callback params + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "handleSignedTransactionPaymentResponse"; + + accountManager.unauthenticatedRequest("/api/v1/transactions/redeem", QNetworkAccessManager::PostOperation, + callbackParameters, QJsonDocument(postObject).toJson()); + +} + +void OctreeServer::handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject) { + qDebug() << "STP response:" << jsonObject; +} + void OctreeServer::sendStatsPacket() { // TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and // send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 76b39c5771..d00af41d5e 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -137,6 +137,9 @@ protected: QString getConfiguration(); QString getStatusLink(); + void handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram); + void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject); + int _argc; const char** _argv; char** _parsedArgV; diff --git a/interface/src/SignedWalletTransaction.h b/interface/src/SignedWalletTransaction.h index b3b1620dac..6bc66a535e 100644 --- a/interface/src/SignedWalletTransaction.h +++ b/interface/src/SignedWalletTransaction.h @@ -14,8 +14,6 @@ #include -const int NUM_BYTES_SIGNED_TRANSACTION_MESSAGE = 72; - class SignedWalletTransaction : public WalletTransaction { Q_OBJECT public: diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 563d735790..68af384007 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -15,15 +15,15 @@ #include #include #include +#include #include -#include #include "NodeList.h" #include "PacketHeaders.h" #include "AccountManager.h" -const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; +const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true; AccountManager& AccountManager::getInstance() { static AccountManager sharedInstance; @@ -62,6 +62,8 @@ AccountManager::AccountManager() : qRegisterMetaType("QNetworkAccessManager::Operation"); qRegisterMetaType("JSONCallbackParameters"); + + qRegisterMetaType("QHttpMultiPart*"); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); } @@ -142,90 +144,113 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { + QMetaObject::invokeMethod(this, "invokedRequest", Q_ARG(const QString&, path), + Q_ARG(bool, true), Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(const JSONCallbackParameters&, callbackParams), Q_ARG(const QByteArray&, dataByteArray), Q_ARG(QHttpMultiPart*, dataMultiPart)); } -void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, +void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart) { + + QMetaObject::invokeMethod(this, "invokedRequest", + Q_ARG(const QString&, path), + Q_ARG(bool, false), + Q_ARG(QNetworkAccessManager::Operation, operation), + Q_ARG(const JSONCallbackParameters&, callbackParams), + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart)); +} + +void AccountManager::invokedRequest(const QString& path, + bool requiresAuthentication, + QNetworkAccessManager::Operation operation, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - if (hasValidAccessToken()) { - QNetworkRequest authenticatedRequest; - - QUrl requestURL = _authURL; - - if (path.startsWith("/")) { - requestURL.setPath(path); + QNetworkRequest networkRequest; + + QUrl requestURL = _authURL; + + if (path.startsWith("/")) { + requestURL.setPath(path); + } else { + requestURL.setPath("/" + path); + } + + if (requiresAuthentication) { + if (hasValidAccessToken()) { + requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); } else { - requestURL.setPath("/" + path); + qDebug() << "No valid access token present. Bailing on authenticated invoked request."; + return; } - - requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); - - authenticatedRequest.setUrl(requestURL); - - if (VERBOSE_HTTP_REQUEST_DEBUGGING) { - qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); - - if (!dataByteArray.isEmpty()) { - qDebug() << "The POST/PUT body -" << QString(dataByteArray); - } + } + + networkRequest.setUrl(requestURL); + + if (VERBOSE_HTTP_REQUEST_DEBUGGING) { + qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); + + if (!dataByteArray.isEmpty()) { + qDebug() << "The POST/PUT body -" << QString(dataByteArray); } - - QNetworkReply* networkReply = NULL; - - switch (operation) { - case QNetworkAccessManager::GetOperation: - networkReply = networkAccessManager.get(authenticatedRequest); - break; - case QNetworkAccessManager::PostOperation: - case QNetworkAccessManager::PutOperation: - if (dataMultiPart) { - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = networkAccessManager.post(authenticatedRequest, dataMultiPart); - } else { - networkReply = networkAccessManager.put(authenticatedRequest, dataMultiPart); - } - dataMultiPart->setParent(networkReply); + } + + QNetworkReply* networkReply = NULL; + + switch (operation) { + case QNetworkAccessManager::GetOperation: + networkReply = networkAccessManager.get(networkRequest); + break; + case QNetworkAccessManager::PostOperation: + case QNetworkAccessManager::PutOperation: + if (dataMultiPart) { + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = networkAccessManager.post(networkRequest, dataMultiPart); } else { - authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = networkAccessManager.post(authenticatedRequest, dataByteArray); - } else { - networkReply = networkAccessManager.put(authenticatedRequest, dataByteArray); - } + networkReply = networkAccessManager.put(networkRequest, dataMultiPart); } - - break; - case QNetworkAccessManager::DeleteOperation: - networkReply = networkAccessManager.sendCustomRequest(authenticatedRequest, "DELETE"); - break; - default: - // other methods not yet handled - break; - } - - if (networkReply) { - if (!callbackParams.isEmpty()) { - // if we have information for a callback, insert the callbackParams into our local map - _pendingCallbackMap.insert(networkReply, callbackParams); - - if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { - callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), - callbackParams.updateSlot.toStdString().c_str()); + dataMultiPart->setParent(networkReply); + } else { + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = networkAccessManager.post(networkRequest, dataByteArray); + } else { + networkReply = networkAccessManager.put(networkRequest, dataByteArray); } } - - // if we ended up firing of a request, hook up to it now - connect(networkReply, SIGNAL(finished()), SLOT(processReply())); + + break; + case QNetworkAccessManager::DeleteOperation: + networkReply = networkAccessManager.sendCustomRequest(networkRequest, "DELETE"); + break; + default: + // other methods not yet handled + break; + } + + if (networkReply) { + if (!callbackParams.isEmpty()) { + // if we have information for a callback, insert the callbackParams into our local map + _pendingCallbackMap.insert(networkReply, callbackParams); + + if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { + callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), + callbackParams.updateSlot.toStdString().c_str()); + } } + + // if we ended up firing of a request, hook up to it now + connect(networkReply, SIGNAL(finished()), SLOT(processReply())); } } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 49a39c1a22..64d62cd1c2 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -47,6 +47,12 @@ public: const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), const QByteArray& dataByteArray = QByteArray(), QHttpMultiPart* dataMultiPart = NULL); + + void unauthenticatedRequest(const QString& path, + QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, + const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -88,7 +94,9 @@ private: void passSuccessToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply); - Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, + Q_INVOKABLE void invokedRequest(const QString& path, + bool requiresAuthentication, + QNetworkAccessManager::Operation operation, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart);