[GUI] Break up ClientDataModel.{c,h}pp into many files
This has been needing to happen. Now it's done. There's no going back.
This commit is contained in:
parent
9a3a6a5234
commit
1667a72144
14 changed files with 426 additions and 384 deletions
37
programs/light_client/Account.cpp
Normal file
37
programs/light_client/Account.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "Balance.hpp"
|
||||
#include "ChainDataModel.hpp"
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
|
||||
QQmlListProperty<Balance> Account::balances()
|
||||
{
|
||||
auto count = [](QQmlListProperty<Balance>* list) {
|
||||
return reinterpret_cast<Account*>(list->data)->m_balances.size();
|
||||
};
|
||||
auto at = [](QQmlListProperty<Balance>* list, int index) {
|
||||
return reinterpret_cast<Account*>(list->data)->m_balances[index];
|
||||
};
|
||||
|
||||
return QQmlListProperty<Balance>(this, this, count, at);
|
||||
}
|
||||
|
||||
void Account::update(const graphene::chain::account_balance_object& balance)
|
||||
{
|
||||
auto balanceItr = std::find_if(m_balances.begin(), m_balances.end(),
|
||||
[&balance](Balance* b) { return b->type()->id() == balance.asset_type.instance.value; });
|
||||
|
||||
if (balanceItr != m_balances.end()) {
|
||||
ilog("Updating ${a}'s balance: ${b}", ("a", m_name.toStdString())("b", balance));
|
||||
(*balanceItr)->update(balance);
|
||||
Q_EMIT balancesChanged();
|
||||
} else {
|
||||
ilog("Adding to ${a}'s new balance: ${b}", ("a", m_name.toStdString())("b", balance));
|
||||
Balance* newBalance = new Balance;
|
||||
newBalance->setParent(this);
|
||||
auto model = qobject_cast<ChainDataModel*>(parent());
|
||||
newBalance->setProperty("type", QVariant::fromValue(model->getAsset(balance.asset_type.instance.value)));
|
||||
newBalance->setProperty("amount", QVariant::fromValue(balance.balance.value));
|
||||
m_balances.append(newBalance);
|
||||
Q_EMIT balancesChanged();
|
||||
}
|
||||
}
|
||||
42
programs/light_client/Account.hpp
Normal file
42
programs/light_client/Account.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#include "GrapheneObject.hpp"
|
||||
|
||||
#include <QQmlListProperty>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class account_balance_object;
|
||||
}}
|
||||
|
||||
class Balance;
|
||||
class Account : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString name MEMBER m_name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QQmlListProperty<Balance> balances READ balances NOTIFY balancesChanged)
|
||||
|
||||
QString m_name;
|
||||
QList<Balance*> m_balances;
|
||||
|
||||
public:
|
||||
Account(ObjectId id = -1, QString name = QString(), QObject* parent = nullptr)
|
||||
: GrapheneObject(id, parent), m_name(name)
|
||||
{}
|
||||
|
||||
QString name()const { return m_name; }
|
||||
QQmlListProperty<Balance> balances();
|
||||
|
||||
void setBalances(QList<Balance*> balances) {
|
||||
if (balances != m_balances) {
|
||||
m_balances = balances;
|
||||
Q_EMIT balancesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void update(const graphene::chain::account_balance_object& balance);
|
||||
|
||||
Q_SIGNALS:
|
||||
void nameChanged();
|
||||
void balancesChanged();
|
||||
};
|
||||
22
programs/light_client/Asset.cpp
Normal file
22
programs/light_client/Asset.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include "Asset.hpp"
|
||||
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
void Asset::update(const graphene::chain::asset_object& asset)
|
||||
{
|
||||
if (asset.id.instance() != id())
|
||||
setProperty("id", QVariant::fromValue(asset.id.instance()));
|
||||
if (asset.symbol != m_symbol.toStdString()) {
|
||||
m_symbol = QString::fromStdString(asset.symbol);
|
||||
Q_EMIT symbolChanged();
|
||||
}
|
||||
if (asset.precision != m_precision) {
|
||||
m_precision = asset.precision;
|
||||
Q_EMIT precisionChanged();
|
||||
}
|
||||
|
||||
if (asset.options.core_exchange_rate != coreExchangeRate)
|
||||
coreExchangeRate = asset.options.core_exchange_rate;
|
||||
}
|
||||
39
programs/light_client/Asset.hpp
Normal file
39
programs/light_client/Asset.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "GrapheneObject.hpp"
|
||||
|
||||
#include "graphene/chain/protocol/asset.hpp"
|
||||
|
||||
class Asset : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString symbol MEMBER m_symbol READ symbol NOTIFY symbolChanged)
|
||||
Q_PROPERTY(quint32 precision MEMBER m_precision NOTIFY precisionChanged)
|
||||
|
||||
QString m_symbol;
|
||||
quint32 m_precision;
|
||||
|
||||
graphene::chain::price coreExchangeRate;
|
||||
|
||||
public:
|
||||
Asset(ObjectId id = -1, QString symbol = QString(), quint32 precision = 0, QObject* parent = nullptr)
|
||||
: GrapheneObject(id, parent), m_symbol(symbol), m_precision(precision)
|
||||
{}
|
||||
|
||||
QString symbol() const {
|
||||
return m_symbol;
|
||||
}
|
||||
|
||||
quint64 precisionPower() const {
|
||||
quint64 power = 1;
|
||||
for (int i = 0; i < m_precision; ++i)
|
||||
power *= 10;
|
||||
return power;
|
||||
}
|
||||
|
||||
void update(const graphene::chain::asset_object& asset);
|
||||
|
||||
Q_SIGNALS:
|
||||
void symbolChanged();
|
||||
void precisionChanged();
|
||||
};
|
||||
16
programs/light_client/Balance.cpp
Normal file
16
programs/light_client/Balance.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "Balance.hpp"
|
||||
#include "Asset.hpp"
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
|
||||
qreal Balance::amountReal() const {
|
||||
return amount / qreal(m_type->precisionPower());
|
||||
}
|
||||
|
||||
void Balance::update(const graphene::chain::account_balance_object& update)
|
||||
{
|
||||
if (update.balance != amount) {
|
||||
amount = update.balance.value;
|
||||
emit amountChanged();
|
||||
}
|
||||
}
|
||||
33
programs/light_client/Balance.hpp
Normal file
33
programs/light_client/Balance.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#include "GrapheneObject.hpp"
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class account_balance_object;
|
||||
}}
|
||||
|
||||
class Asset;
|
||||
class Balance : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Asset* type MEMBER m_type READ type NOTIFY typeChanged)
|
||||
Q_PROPERTY(qint64 amount MEMBER amount NOTIFY amountChanged)
|
||||
|
||||
Asset* m_type;
|
||||
qint64 amount;
|
||||
|
||||
public:
|
||||
// This ultimately needs to be replaced with a string equivalent
|
||||
Q_INVOKABLE qreal amountReal() const;
|
||||
|
||||
Asset* type()const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void update(const graphene::chain::account_balance_object& update);
|
||||
|
||||
Q_SIGNALS:
|
||||
void typeChanged();
|
||||
void amountChanged();
|
||||
};
|
||||
|
|
@ -18,7 +18,7 @@ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|||
qt5_add_resources(QML_QRC qml/qml.qrc)
|
||||
endif()
|
||||
|
||||
add_executable(light_client ClientDataModel.cpp ClientDataModel.hpp Operations.cpp main.cpp ${QML_QRC} ${QML})
|
||||
add_executable(light_client ChainDataModel.cpp Operations.cpp GrapheneApplication.cpp GrapheneObject.cpp Asset.cpp Account.cpp Balance.cpp main.cpp ${QML_QRC} ${QML})
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS 3.0)
|
||||
add_dependencies(light_client gen_qrc)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "ClientDataModel.hpp"
|
||||
#include "ChainDataModel.hpp"
|
||||
#include "Balance.hpp"
|
||||
#include "Operations.hpp"
|
||||
|
||||
#include <graphene/app/api.hpp>
|
||||
|
|
@ -250,130 +251,3 @@ Account* ChainDataModel::getAccount(QString name)
|
|||
}
|
||||
return *itr;
|
||||
}
|
||||
|
||||
QQmlListProperty<Balance> Account::balances()
|
||||
{
|
||||
auto count = [](QQmlListProperty<Balance>* list) {
|
||||
return reinterpret_cast<Account*>(list->data)->m_balances.size();
|
||||
};
|
||||
auto at = [](QQmlListProperty<Balance>* list, int index) {
|
||||
return reinterpret_cast<Account*>(list->data)->m_balances[index];
|
||||
};
|
||||
|
||||
return QQmlListProperty<Balance>(this, this, count, at);
|
||||
}
|
||||
|
||||
void Account::update(const account_balance_object& balance)
|
||||
{
|
||||
auto balanceItr = std::find_if(m_balances.begin(), m_balances.end(),
|
||||
[&balance](Balance* b) { return b->type()->id() == balance.asset_type.instance.value; });
|
||||
|
||||
if (balanceItr != m_balances.end()) {
|
||||
ilog("Updating ${a}'s balance: ${b}", ("a", m_name.toStdString())("b", balance));
|
||||
(*balanceItr)->update(balance);
|
||||
Q_EMIT balancesChanged();
|
||||
} else {
|
||||
ilog("Adding to ${a}'s new balance: ${b}", ("a", m_name.toStdString())("b", balance));
|
||||
Balance* newBalance = new Balance;
|
||||
newBalance->setParent(this);
|
||||
auto model = qobject_cast<ChainDataModel*>(parent());
|
||||
newBalance->setProperty("type", QVariant::fromValue(model->getAsset(balance.asset_type.instance.value)));
|
||||
newBalance->setProperty("amount", QVariant::fromValue(balance.balance.value));
|
||||
m_balances.append(newBalance);
|
||||
Q_EMIT balancesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
GrapheneApplication::GrapheneApplication(QObject* parent)
|
||||
:QObject(parent),m_thread("app")
|
||||
{
|
||||
connect(this, &GrapheneApplication::queueExecute,
|
||||
this, &GrapheneApplication::execute);
|
||||
|
||||
m_model = new ChainDataModel(m_thread, this);
|
||||
m_operationBuilder = new OperationBuilder(*m_model, this);
|
||||
|
||||
connect(m_model, &ChainDataModel::queueExecute,
|
||||
this, &GrapheneApplication::execute);
|
||||
|
||||
connect(m_model, &ChainDataModel::exceptionThrown,
|
||||
this, &GrapheneApplication::exceptionThrown);
|
||||
}
|
||||
|
||||
GrapheneApplication::~GrapheneApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void GrapheneApplication::setIsConnected(bool v)
|
||||
{
|
||||
if (v != m_isConnected)
|
||||
{
|
||||
m_isConnected = v;
|
||||
Q_EMIT isConnectedChanged(m_isConnected);
|
||||
}
|
||||
}
|
||||
|
||||
void GrapheneApplication::start(QString apiurl, QString user, QString pass)
|
||||
{
|
||||
if (!m_thread.is_current())
|
||||
{
|
||||
m_done = m_thread.async([=](){ return start(apiurl, user, pass); });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
m_client = std::make_shared<fc::http::websocket_client>();
|
||||
ilog("connecting...${s}", ("s",apiurl.toStdString()));
|
||||
auto con = m_client->connect(apiurl.toStdString());
|
||||
m_connectionClosed = con->closed.connect([this]{queueExecute([this]{setIsConnected(false);});});
|
||||
auto apic = std::make_shared<fc::rpc::websocket_api_connection>(*con);
|
||||
auto remote_api = apic->get_remote_api<login_api>(1);
|
||||
auto db_api = apic->get_remote_api<database_api>(0);
|
||||
if (!remote_api->login(user.toStdString(), pass.toStdString()))
|
||||
{
|
||||
elog("login failed");
|
||||
Q_EMIT loginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
ilog("connecting...");
|
||||
queueExecute([=](){
|
||||
m_model->setDatabaseAPI(db_api);
|
||||
});
|
||||
|
||||
queueExecute([=](){ setIsConnected(true); });
|
||||
} catch (const fc::exception& e)
|
||||
{
|
||||
Q_EMIT exceptionThrown(QString::fromStdString(e.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void GrapheneApplication::execute(const std::function<void()>& func)const
|
||||
{
|
||||
func();
|
||||
}
|
||||
|
||||
void Balance::update(const account_balance_object& update)
|
||||
{
|
||||
if (update.balance != amount) {
|
||||
amount = update.balance.value;
|
||||
emit amountChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Asset::update(const asset_object& asset)
|
||||
{
|
||||
if (asset.id.instance() != id())
|
||||
setProperty("id", QVariant::fromValue(asset.id.instance()));
|
||||
if (asset.symbol != m_symbol.toStdString()) {
|
||||
m_symbol = QString::fromStdString(asset.symbol);
|
||||
Q_EMIT symbolChanged();
|
||||
}
|
||||
if (asset.precision != m_precision) {
|
||||
m_precision = asset.precision;
|
||||
Q_EMIT precisionChanged();
|
||||
}
|
||||
|
||||
if (asset.options.core_exchange_rate != coreExchangeRate)
|
||||
coreExchangeRate = asset.options.core_exchange_rate;
|
||||
}
|
||||
73
programs/light_client/ChainDataModel.hpp
Normal file
73
programs/light_client/ChainDataModel.hpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#include <fc/network/http/websocket.hpp>
|
||||
#include <graphene/app/api.hpp>
|
||||
|
||||
#include "BoostMultiIndex.hpp"
|
||||
#include "Asset.hpp"
|
||||
#include "Account.hpp"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
using graphene::chain::by_id;
|
||||
|
||||
namespace fc {
|
||||
class thread;
|
||||
}
|
||||
|
||||
struct by_symbol_name;
|
||||
typedef multi_index_container<
|
||||
Asset*,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
|
||||
ordered_unique< tag<by_symbol_name>, const_mem_fun<Asset, QString, &Asset::symbol> >
|
||||
>
|
||||
> asset_multi_index_type;
|
||||
|
||||
struct by_account_name;
|
||||
typedef multi_index_container<
|
||||
Account*,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
|
||||
ordered_unique< tag<by_account_name>, const_mem_fun<Account, QString, &Account::name> >
|
||||
>
|
||||
> account_multi_index_type;
|
||||
|
||||
class ChainDataModel : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
void processUpdatedObject(const fc::variant& update);
|
||||
|
||||
void getAssetImpl(QString assetIdentifier, Asset* const * assetInContainer);
|
||||
void getAccountImpl(QString accountIdentifier, Account* const * accountInContainer);
|
||||
|
||||
public:
|
||||
Q_INVOKABLE Account* getAccount(ObjectId id);
|
||||
Q_INVOKABLE Account* getAccount(QString name);
|
||||
Q_INVOKABLE Asset* getAsset(ObjectId id);
|
||||
Q_INVOKABLE Asset* getAsset(QString symbol);
|
||||
|
||||
ChainDataModel(){}
|
||||
ChainDataModel(fc::thread& t, QObject* parent = nullptr);
|
||||
|
||||
void setDatabaseAPI(fc::api<graphene::app::database_api> dbapi);
|
||||
|
||||
const graphene::chain::global_property_object& global_properties() const { return m_global_properties; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void queueExecute(const std::function<void()>&);
|
||||
void exceptionThrown(QString message);
|
||||
|
||||
private:
|
||||
fc::thread* m_rpc_thread = nullptr;
|
||||
std::string m_api_url;
|
||||
fc::api<graphene::app::database_api> m_db_api;
|
||||
|
||||
graphene::chain::global_property_object m_global_properties;
|
||||
|
||||
ObjectId m_account_query_num = -1;
|
||||
account_multi_index_type m_accounts;
|
||||
asset_multi_index_type m_assets;
|
||||
};
|
||||
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
#pragma once
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
|
||||
#include <fc/network/http/websocket.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <graphene/app/api.hpp>
|
||||
|
||||
#include <QtQml>
|
||||
#include <QObject>
|
||||
#include <QQmlListProperty>
|
||||
|
||||
using boost::multi_index_container;
|
||||
using namespace boost::multi_index;
|
||||
|
||||
using graphene::chain::by_id;
|
||||
|
||||
using ObjectId = qint64;
|
||||
Q_DECLARE_METATYPE(ObjectId)
|
||||
|
||||
Q_DECLARE_METATYPE(std::function<void()>)
|
||||
|
||||
class GrapheneObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ObjectId id MEMBER m_id READ id NOTIFY idChanged)
|
||||
|
||||
ObjectId m_id;
|
||||
|
||||
public:
|
||||
GrapheneObject(ObjectId id = -1, QObject* parent = nullptr)
|
||||
: QObject(parent), m_id(id)
|
||||
{}
|
||||
|
||||
ObjectId id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void idChanged();
|
||||
};
|
||||
class Crypto {
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString sha256(QByteArray data) {
|
||||
return QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex();
|
||||
}
|
||||
};
|
||||
QML_DECLARE_TYPE(Crypto)
|
||||
|
||||
|
||||
class Asset : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString symbol MEMBER m_symbol READ symbol NOTIFY symbolChanged)
|
||||
Q_PROPERTY(quint32 precision MEMBER m_precision NOTIFY precisionChanged)
|
||||
|
||||
QString m_symbol;
|
||||
quint32 m_precision;
|
||||
|
||||
graphene::chain::price coreExchangeRate;
|
||||
|
||||
public:
|
||||
Asset(ObjectId id = -1, QString symbol = QString(), quint32 precision = 0, QObject* parent = nullptr)
|
||||
: GrapheneObject(id, parent), m_symbol(symbol), m_precision(precision)
|
||||
{}
|
||||
|
||||
QString symbol() const {
|
||||
return m_symbol;
|
||||
}
|
||||
|
||||
quint64 precisionPower() const {
|
||||
quint64 power = 1;
|
||||
for (int i = 0; i < m_precision; ++i)
|
||||
power *= 10;
|
||||
return power;
|
||||
}
|
||||
|
||||
void update(const graphene::chain::asset_object& asset);
|
||||
|
||||
Q_SIGNALS:
|
||||
void symbolChanged();
|
||||
void precisionChanged();
|
||||
};
|
||||
|
||||
struct by_symbol_name;
|
||||
typedef multi_index_container<
|
||||
Asset*,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
|
||||
ordered_unique< tag<by_symbol_name>, const_mem_fun<Asset, QString, &Asset::symbol> >
|
||||
>
|
||||
> asset_multi_index_type;
|
||||
|
||||
class Balance : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Asset* type MEMBER m_type READ type NOTIFY typeChanged)
|
||||
Q_PROPERTY(qint64 amount MEMBER amount NOTIFY amountChanged)
|
||||
|
||||
Asset* m_type;
|
||||
qint64 amount;
|
||||
|
||||
public:
|
||||
// This ultimately needs to be replaced with a string equivalent
|
||||
Q_INVOKABLE qreal amountReal() const {
|
||||
return amount / qreal(m_type->precisionPower());
|
||||
}
|
||||
|
||||
Asset* type()const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void update(const graphene::app::account_balance_object& update);
|
||||
|
||||
Q_SIGNALS:
|
||||
void typeChanged();
|
||||
void amountChanged();
|
||||
};
|
||||
|
||||
class Account : public GrapheneObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString name MEMBER m_name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QQmlListProperty<Balance> balances READ balances NOTIFY balancesChanged)
|
||||
|
||||
QString m_name;
|
||||
QList<Balance*> m_balances;
|
||||
|
||||
public:
|
||||
Account(ObjectId id = -1, QString name = QString(), QObject* parent = nullptr)
|
||||
: GrapheneObject(id, parent), m_name(name)
|
||||
{}
|
||||
|
||||
QString name()const { return m_name; }
|
||||
QQmlListProperty<Balance> balances();
|
||||
|
||||
void setBalances(QList<Balance*> balances) {
|
||||
if (balances != m_balances) {
|
||||
m_balances = balances;
|
||||
Q_EMIT balancesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void update(const graphene::app::account_balance_object& balance);
|
||||
|
||||
Q_SIGNALS:
|
||||
void nameChanged();
|
||||
void balancesChanged();
|
||||
};
|
||||
|
||||
struct by_account_name;
|
||||
typedef multi_index_container<
|
||||
Account*,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
|
||||
ordered_unique< tag<by_account_name>, const_mem_fun<Account, QString, &Account::name> >
|
||||
>
|
||||
> account_multi_index_type;
|
||||
|
||||
class ChainDataModel : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
void processUpdatedObject(const fc::variant& update);
|
||||
|
||||
void getAssetImpl(QString assetIdentifier, Asset* const * assetInContainer);
|
||||
void getAccountImpl(QString accountIdentifier, Account* const * accountInContainer);
|
||||
|
||||
public:
|
||||
Q_INVOKABLE Account* getAccount(ObjectId id);
|
||||
Q_INVOKABLE Account* getAccount(QString name);
|
||||
Q_INVOKABLE Asset* getAsset(ObjectId id);
|
||||
Q_INVOKABLE Asset* getAsset(QString symbol);
|
||||
|
||||
ChainDataModel(){}
|
||||
ChainDataModel( fc::thread& t, QObject* parent = nullptr );
|
||||
|
||||
void setDatabaseAPI(fc::api<graphene::app::database_api> dbapi);
|
||||
|
||||
const graphene::chain::global_property_object& global_properties() const { return m_global_properties; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void queueExecute( const std::function<void()>& );
|
||||
void exceptionThrown( QString message );
|
||||
|
||||
private:
|
||||
fc::thread* m_rpc_thread = nullptr;
|
||||
std::string m_api_url;
|
||||
fc::api<graphene::app::database_api> m_db_api;
|
||||
|
||||
graphene::chain::global_property_object m_global_properties;
|
||||
|
||||
ObjectId m_account_query_num = -1;
|
||||
account_multi_index_type m_accounts;
|
||||
asset_multi_index_type m_assets;
|
||||
};
|
||||
|
||||
class OperationBuilder;
|
||||
class GrapheneApplication : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ChainDataModel* model READ model CONSTANT)
|
||||
Q_PROPERTY(OperationBuilder* operationBuilder READ operationBuilder CONSTANT)
|
||||
Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
|
||||
|
||||
|
||||
fc::thread m_thread;
|
||||
ChainDataModel* m_model = nullptr;
|
||||
OperationBuilder* m_operationBuilder = nullptr;
|
||||
bool m_isConnected = false;
|
||||
|
||||
boost::signals2::scoped_connection m_connectionClosed;
|
||||
|
||||
std::shared_ptr<fc::http::websocket_client> m_client;
|
||||
fc::future<void> m_done;
|
||||
|
||||
void setIsConnected(bool v);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void execute(const std::function<void()>&)const;
|
||||
|
||||
public:
|
||||
GrapheneApplication(QObject* parent = nullptr);
|
||||
~GrapheneApplication();
|
||||
|
||||
ChainDataModel* model() const {
|
||||
return m_model;
|
||||
}
|
||||
OperationBuilder* operationBuilder() const {
|
||||
return m_operationBuilder;
|
||||
}
|
||||
|
||||
Q_INVOKABLE void start(QString apiUrl,
|
||||
QString user,
|
||||
QString pass);
|
||||
|
||||
bool isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void exceptionThrown( QString message );
|
||||
void loginFailed();
|
||||
void isConnectedChanged(bool isConnected);
|
||||
void queueExecute( const std::function<void()>& );
|
||||
};
|
||||
80
programs/light_client/GrapheneApplication.cpp
Normal file
80
programs/light_client/GrapheneApplication.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include "GrapheneApplication.hpp"
|
||||
#include "ChainDataModel.hpp"
|
||||
#include "Operations.hpp"
|
||||
|
||||
#include <graphene/app/api.hpp>
|
||||
|
||||
#include <fc/rpc/websocket_api.hpp>
|
||||
|
||||
using graphene::app::login_api;
|
||||
using graphene::app::database_api;
|
||||
|
||||
GrapheneApplication::GrapheneApplication(QObject* parent)
|
||||
:QObject(parent),m_thread("app")
|
||||
{
|
||||
connect(this, &GrapheneApplication::queueExecute,
|
||||
this, &GrapheneApplication::execute);
|
||||
|
||||
m_model = new ChainDataModel(m_thread, this);
|
||||
m_operationBuilder = new OperationBuilder(*m_model, this);
|
||||
|
||||
connect(m_model, &ChainDataModel::queueExecute,
|
||||
this, &GrapheneApplication::execute);
|
||||
|
||||
connect(m_model, &ChainDataModel::exceptionThrown,
|
||||
this, &GrapheneApplication::exceptionThrown);
|
||||
}
|
||||
|
||||
GrapheneApplication::~GrapheneApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void GrapheneApplication::setIsConnected(bool v)
|
||||
{
|
||||
if (v != m_isConnected)
|
||||
{
|
||||
m_isConnected = v;
|
||||
Q_EMIT isConnectedChanged(m_isConnected);
|
||||
}
|
||||
}
|
||||
|
||||
void GrapheneApplication::start(QString apiurl, QString user, QString pass)
|
||||
{
|
||||
if (!m_thread.is_current())
|
||||
{
|
||||
m_done = m_thread.async([=](){ return start(apiurl, user, pass); });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
m_client = std::make_shared<fc::http::websocket_client>();
|
||||
ilog("connecting...${s}", ("s",apiurl.toStdString()));
|
||||
auto con = m_client->connect(apiurl.toStdString());
|
||||
m_connectionClosed = con->closed.connect([this]{queueExecute([this]{setIsConnected(false);});});
|
||||
auto apic = std::make_shared<fc::rpc::websocket_api_connection>(*con);
|
||||
auto remote_api = apic->get_remote_api<login_api>(1);
|
||||
auto db_api = apic->get_remote_api<database_api>(0);
|
||||
if (!remote_api->login(user.toStdString(), pass.toStdString()))
|
||||
{
|
||||
elog("login failed");
|
||||
Q_EMIT loginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
ilog("connecting...");
|
||||
queueExecute([=](){
|
||||
m_model->setDatabaseAPI(db_api);
|
||||
});
|
||||
|
||||
queueExecute([=](){ setIsConnected(true); });
|
||||
} catch (const fc::exception& e)
|
||||
{
|
||||
Q_EMIT exceptionThrown(QString::fromStdString(e.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void GrapheneApplication::execute(const std::function<void()>& func)const
|
||||
{
|
||||
func();
|
||||
}
|
||||
|
||||
|
||||
65
programs/light_client/GrapheneApplication.hpp
Normal file
65
programs/light_client/GrapheneApplication.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace fc { namespace http {
|
||||
class websocket_client;
|
||||
}}
|
||||
|
||||
class ChainDataModel;
|
||||
class OperationBuilder;
|
||||
class GrapheneApplication : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ChainDataModel* model READ model CONSTANT)
|
||||
Q_PROPERTY(OperationBuilder* operationBuilder READ operationBuilder CONSTANT)
|
||||
Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
|
||||
|
||||
|
||||
fc::thread m_thread;
|
||||
ChainDataModel* m_model = nullptr;
|
||||
OperationBuilder* m_operationBuilder = nullptr;
|
||||
bool m_isConnected = false;
|
||||
|
||||
boost::signals2::scoped_connection m_connectionClosed;
|
||||
|
||||
std::shared_ptr<fc::http::websocket_client> m_client;
|
||||
fc::future<void> m_done;
|
||||
|
||||
void setIsConnected(bool v);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void execute(const std::function<void()>&)const;
|
||||
|
||||
public:
|
||||
GrapheneApplication(QObject* parent = nullptr);
|
||||
~GrapheneApplication();
|
||||
|
||||
ChainDataModel* model() const {
|
||||
return m_model;
|
||||
}
|
||||
OperationBuilder* operationBuilder() const {
|
||||
return m_operationBuilder;
|
||||
}
|
||||
|
||||
Q_INVOKABLE void start(QString apiUrl,
|
||||
QString user,
|
||||
QString pass);
|
||||
|
||||
bool isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void exceptionThrown(QString message);
|
||||
void loginFailed();
|
||||
void isConnectedChanged(bool isConnected);
|
||||
void queueExecute(const std::function<void()>&);
|
||||
};
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "ClientDataModel.hpp"
|
||||
#include "ChainDataModel.hpp"
|
||||
|
||||
#include <graphene/chain/protocol/transfer.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,20 @@
|
|||
#include <QQmlApplicationEngine>
|
||||
#include <QtQml>
|
||||
|
||||
#include "ClientDataModel.hpp"
|
||||
#include "GrapheneApplication.hpp"
|
||||
#include "ChainDataModel.hpp"
|
||||
#include "Operations.hpp"
|
||||
#include "Balance.hpp"
|
||||
|
||||
class Crypto {
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString sha256(QByteArray data) {
|
||||
return QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex();
|
||||
}
|
||||
};
|
||||
QML_DECLARE_TYPE(Crypto)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
|
@ -38,3 +50,5 @@ int main(int argc, char *argv[])
|
|||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
||||
|
|
|
|||
Loading…
Reference in a new issue