Skip to content

Commit

Permalink
Request handler impl/portal http client impl (#21)
Browse files Browse the repository at this point in the history
* Added UI elements

* Refactoring code, changin color of labels

* Added expand for transactionList

* TransactionsList changed

* TransactionList fixed

* Updated TransactionList, added MainPage, MainMenuListView

* Changed MainPage structure, small updates to WalletMenuListView, fixed errors, changed colors

* Updated sizes in transactionListView, added changing icons of the coins when changing coins

* Commented out tests

* Changed TransactionView structure, added MainItem, rewrited WalletMenuListView, update buttons view

* Addind popup windows for sending and receiving

* Changed buttons view, fixed assetsListView

* Added new images for receive popup

* Changed access to assetsList using id, added new roles to WalletAssetsModel, fixed color on buttons and assetsList views

* Added plus and minus to delta, fixed WalletPageHeaderView height, changed Stakenet colors

* Small changes in WalletPage view

* Added new components ofr sendPopup

* Added 2 menu modes, created MenuIcon, added new images

* Added receiving addres from walletViewModel

* Removed redundant code

* Moved constant sizes to QMLUtils

* Changed WalletPage view, WalletMenuList view

* Changed TransactionListView

* Added menu background

* Added TransactionsPage, added currency and smbol roles to transactionsListModel, added assetId to TransactionEntry

* Corrected remarks, changed icons to new ones, deleted PortfolioCharts and replace it on corrected PageHeaderView

* Added WalletsListHeaderView, changed Portfolio view

* Added model to WalletsListView

* Changed WalletPageHeaderView, Statistics part in Portfolio tab

* Added fonts, changed header in wallet page

* Created carousel,added new fonts, changed Text to XSNLabel

* Added AssetsBalance

* Fixed balance calculating and updating, fixed sorting by balance

* Fixed updating TransactionListModel

* Updated setting current index in WalletAssetsListView

* Corrected all remarks

* Added search by wallet in portfolio tab

* Added usdBalance role and accoutBalance in AssetsListModel

* Added AssetListProxyModel, changed sorting and search

* Added LocalCurrency data, CurrencyModel,added base SettingsPage, Localization view

* Added RequestHandlerImpl/PortalHttpClientImpl

* Small changes

* Added test and modified TransactionHandler

* Fixed tests for networking. Fixed networking module

* Updated networking API and tests
  • Loading branch information
UlyanaAndrukhiv authored and durkmurder committed Nov 2, 2018
1 parent 0b73153 commit 7b5aaf6
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 8 deletions.
8 changes: 4 additions & 4 deletions src.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ Project {
"src/app/app.qbs",
"src/core/core.qbs",
"src/bitcoin/bitcoin.qbs"
// "src/networking/networking.qbs",
//"src/networking/networking.qbs",
]


// SubProject {
// filePath: "src/tests/tests.qbs"
// }
SubProject {
filePath: "src/tests/tests.qbs"
}

AutotestRunner {
name: "run_autotests"
Expand Down
92 changes: 92 additions & 0 deletions src/core/Data/RequestHandlerImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "RequestHandlerImpl.hpp"
#include <QJsonDocument>
#include <QTimer>
#include <QUrlQuery>
#include <functional>

#define NetworkNotAvailableMessage tr("Network is not available.")

//==============================================================================

RequestHandlerImpl::RequestHandlerImpl(QNetworkAccessManager *networkManager, QObject *parent) :
_networkAccessManager(networkManager)
{

}

//==============================================================================

RequestHandlerImpl::~RequestHandlerImpl()
{

}

//==============================================================================

void RequestHandlerImpl::makeGetRequest(const QString &path, const QVariantMap &params, RequestHandlerImpl::NetworkErrorHandler errorHandler, RequestHandlerImpl::ResponseHandler responseHandler, int retryAttempts)
{
if (_networkAccessManager->networkAccessible() != QNetworkAccessManager::Accessible) {
if (errorHandler) {
errorHandler(-1, NetworkNotAvailableMessage);
}
return;
}

QNetworkRequest request(buildUrl(path, params));

qDebug() << request.url();


RequestMaker requestMaker = [this, request](){
return _networkAccessManager->get(request);
};

processRequest(requestMaker, errorHandler, responseHandler, retryAttempts);
}

//==============================================================================

void RequestHandlerImpl::processResponse(QNetworkReply *reply, RequestHandlerImpl::NetworkErrorHandler errorHandler, RequestHandlerImpl::ResponseHandler responseHandler)
{
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
responseHandler(response);
} else {
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "HTTP error" << statusCode << reply->errorString();
errorHandler(statusCode, reply->errorString());
}
}

//==============================================================================

void RequestHandlerImpl::processRequest(RequestHandlerImpl::RequestMaker requestMaker, RequestHandlerImpl::NetworkErrorHandler errorHandler, RequestHandlerImpl::ResponseHandler responseHandler, int retryAttempts)
{
auto reply = requestMaker();

connect(reply, &QNetworkReply::finished, this, [=](){
if (reply->error() == QNetworkReply::OperationCanceledError && retryAttempts > 0) {
qWarning() << "Retrying request, attempts" << retryAttempts;
processRequest(requestMaker, errorHandler, responseHandler, retryAttempts - 1);
} else {
processResponse(reply, errorHandler, responseHandler);
}
});
}

//==============================================================================

QUrl RequestHandlerImpl::buildUrl(const QString &path, const QVariantMap &params)
{
QUrl url(QString("https://%1").arg(QString("xsnexplorer.io/api/%1").arg(path)));

QUrlQuery query;
for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
query.addQueryItem(it.key(), QUrl::toPercentEncoding(it.value().toString()));
}
url.setQuery(query);

return url;
}

//==============================================================================
45 changes: 45 additions & 0 deletions src/core/Data/RequestHandlerImpl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef REQUESTHANDLERIMPL_HPP
#define REQUESTHANDLERIMPL_HPP

#include <QNetworkReply>
#include <QVariantMap>
#include <QJsonObject>
#include <QJsonArray>
#include <functional>

class RequestHandlerImpl : public QObject
{
Q_OBJECT
public:
using ResponseHandler = std::function<void(const QByteArray&)>;
using NetworkErrorHandler = std::function<void(int, const QString&)>;
using RequestMaker = std::function<QNetworkReply*()>;

public:
RequestHandlerImpl(QNetworkAccessManager* networkManager,
QObject *parent = nullptr);
virtual ~RequestHandlerImpl();

void makeGetRequest(const QString &path,
const QVariantMap &params,
NetworkErrorHandler errorHandler,
ResponseHandler responseHandler,
int retryAttempts = 0);

private slots:
void processResponse(QNetworkReply *reply,
NetworkErrorHandler errorHandler,
ResponseHandler responseHandler);

private:
void processRequest(RequestMaker requestMaker,
NetworkErrorHandler errorHandler,
ResponseHandler responseHandler,
int retryAttempts = 1);

QUrl buildUrl(const QString &path, const QVariantMap &params = QVariantMap());

QNetworkAccessManager *_networkAccessManager;
};

#endif // REQUESTHANDLERIMPL_HPP
58 changes: 58 additions & 0 deletions src/core/Data/TransactionHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "TransactionHandler.hpp"
#include <QJsonObject>
#include <QJsonDocument>
#include "RequestHandlerImpl.hpp"

//==============================================================================

TransactionHandler::TransactionHandler(QObject *parent) :
QObject(parent)
{
auto manager = new QNetworkAccessManager(this);
_requestHandler = new RequestHandlerImpl(manager);
}

//==============================================================================

TransactionHandler::~TransactionHandler()
{

}

//==============================================================================

void TransactionHandler::getTransactionsByAddress(QString address)
{
Q_ASSERT(!address.isEmpty());

auto errorHandler = [=](int errorCode, const QString &errorString){
emit transactionByAddressFailed(address, errorCode, errorString);
};

QString offset;
QString limit;
QString orderBy;

auto responseHandler = [&](const QByteArray &response) {
QJsonObject json = QJsonDocument::fromJson(response).object();

// offset = json.value("offset").toString();
// limit = json.value("limit").toString();
// orderBy = json.value("orderBy").toString();

QJsonObject data = json.value("data").toObject();

emit transactionByAddressFinished(address, response);
};

QVariantMap params = {
{"offset", offset},
{"limit", limit},
{"orderBy", orderBy}
};

const QString url = QString("addresses/%1/transactions").arg(QString(QUrl::toPercentEncoding(address)));
_requestHandler->makeGetRequest(url, {}, errorHandler, responseHandler);
}

//==============================================================================
27 changes: 27 additions & 0 deletions src/core/Data/TransactionHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef TransactionHandler_HPP
#define TransactionHandler_HPP

#include <QObject>
#include <QNetworkReply>
#include "RequestHandlerImpl.hpp"

class TransactionHandler : public QObject
{
Q_OBJECT
public:
TransactionHandler(QObject *parent = nullptr);
virtual ~TransactionHandler();

signals:
void transactionByAddressFailed(QString address, int errorCode, QString errorString);
void transactionByAddressFinished(QString address, QByteArray response);

public slots:
void getTransactionsByAddress(QString address);

private:
RequestHandlerImpl *_requestHandler;
};


#endif // TransactionHandler_HPP
5 changes: 5 additions & 0 deletions src/core/core.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ Product {
"Data/CoinAsset.hpp",
"Data/LocalCurrency.cpp",
"Data/LocalCurrency.hpp",
"Data/RequestHandlerImpl.cpp",
"Data/RequestHandlerImpl.hpp",
"Data/TransactionEntry.cpp",
"Data/TransactionEntry.hpp",
"Data/TransactionHandler.cpp",
"Data/TransactionHandler.hpp",
"Data/WalletAssetsModel.cpp",
"Data/WalletAssetsModel.hpp",
"Models/AllTransactionsDataSource.cpp",
Expand Down Expand Up @@ -50,6 +54,7 @@ Product {
Depends { name: "gsl" }
Depends { name: "bitcoin" }
Depends { name: "boost"}
Depends { name: "Qt.network" }
cpp.defines: ['CRUCIAL_DEFINE']
cpp.includePaths: [product.sourceDirectory]

Expand Down
7 changes: 6 additions & 1 deletion src/tests/core_tests/core_tests.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CppApplication {
Depends { name: "libbitcoin" }
Depends { name: "gtest" }
Depends { name: "bitcoin" }
Depends { name: "Qt.network" }
name: "core_tests"
type: base.concat("autotest")

Expand All @@ -17,13 +18,17 @@ CppApplication {
"tst_addressmanager.hpp",
"tst_coretests.hpp",
"tst_keystorage.hpp",
"tst_portalhttpclient.hpp",
]

Group {
name: "testdata"
prefix: "testdata/"
qbs.install: true
files: ["**/*", "../../../app/assets/assets_conf.json"]
files: [
"**/*",
"../../../app/assets/assets_conf.json",
]
fileTags: []
}

Expand Down
11 changes: 8 additions & 3 deletions src/tests/core_tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "tst_coretests.hpp"
#include "tst_keystorage.hpp"
#include "tst_portalhttpclient.hpp"

#include <gtest/gtest.h>

int main(int argc, char *argv[])
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
testing::InitGoogleTest(&argc, argv);
QCoreApplication app(argc, argv);
QTimer::singleShot(0, []{
QCoreApplication::exit(RUN_ALL_TESTS());
});
return app.exec();
}
30 changes: 30 additions & 0 deletions src/tests/core_tests/tst_portalhttpclient.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef TST_PORTALHTTPCLIENT_HPP
#define TST_PORTALHTTPCLIENT_HPP

#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QTimer>
#include <QSignalSpy>
#include <QJsonObject>
#include <QJsonDocument>
#include "Data/TransactionHandler.hpp"

using namespace testing;

TEST(CoreTests, getTransactionsByAddress)
{
TransactionHandler portalApi{};

QSignalSpy spy(&portalApi, &TransactionHandler::transactionByAddressFinished);
const QString address = "XvNBN8xe5twNu1qLh2M7ZgkjRY9sEeXpCx";
portalApi.getTransactionsByAddress(address);

spy.wait(2000);
EXPECT_EQ(spy.count(), 1);
QList<QVariant> arguments = spy.takeFirst();
EXPECT_EQ(arguments.at(0).toInt(), 1);
EXPECT_TRUE(arguments.at(1).toString().contains("5"));
}
#endif // TST_PORTALHTTPCLIENT_HPP

0 comments on commit 7b5aaf6

Please sign in to comment.