chore(cpp): apply clang-format

This commit is contained in:
Patryk Osmaczko 2022-10-19 15:41:53 +02:00 committed by osmaczko
parent 1dcc3a1f2f
commit c53264b124
104 changed files with 1736 additions and 1511 deletions

View File

@ -2,14 +2,13 @@
#include <QtQml/QQmlEngine> #include <QtQml/QQmlEngine>
namespace Status::Application { namespace Status::Application
{
ApplicationController::ApplicationController(QObject* parent) ApplicationController::ApplicationController(QObject* parent)
: QObject{parent} : QObject{parent}
, m_dataProvider(std::make_unique<DataProvider>()) , m_dataProvider(std::make_unique<DataProvider>())
{ { }
}
void ApplicationController::initOnLogin() void ApplicationController::initOnLogin()
{ {
@ -30,10 +29,9 @@ QObject *ApplicationController::statusAccount() const
void ApplicationController::setStatusAccount(QObject* newStatusAccount) void ApplicationController::setStatusAccount(QObject* newStatusAccount)
{ {
if (m_statusAccount == newStatusAccount) if(m_statusAccount == newStatusAccount) return;
return;
m_statusAccount = newStatusAccount; m_statusAccount = newStatusAccount;
emit statusAccountChanged(); emit statusAccountChanged();
} }
} } // namespace Status::Application

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "DbSettingsObj.h"
#include "DataProvider.h" #include "DataProvider.h"
#include "DbSettingsObj.h"
#include <QObject> #include <QObject>
#include <QtQml/qqmlregistration.h> #include <QtQml/qqmlregistration.h>
@ -9,7 +9,8 @@
// TODO: investigate. This line breaks qobject_cast in OnboardingController::login // TODO: investigate. This line breaks qobject_cast in OnboardingController::login
//#include <Onboarding/UserAccount.h> //#include <Onboarding/UserAccount.h>
namespace Status::Application { namespace Status::Application
{
/** /**
* @brief Responsible for providing general information and utility components * @brief Responsible for providing general information and utility components
@ -41,4 +42,4 @@ private:
std::shared_ptr<DbSettingsObj> m_dbSettings; std::shared_ptr<DbSettingsObj> m_dbSettings;
}; };
} } // namespace Status::Application

View File

@ -6,18 +6,20 @@ namespace StatusGo = Status::StatusGo;
DataProvider::DataProvider() DataProvider::DataProvider()
: QObject(nullptr) : QObject(nullptr)
{ { }
}
StatusGo::Settings::SettingsDto DataProvider::getSettings() const StatusGo::Settings::SettingsDto DataProvider::getSettings() const
{ {
try { try
{
return StatusGo::Settings::getSettings(); return StatusGo::Settings::getSettings();
} }
catch (std::exception& e) { catch(std::exception& e)
{
qWarning() << "DataProvider::getSettings, error: " << e.what(); qWarning() << "DataProvider::getSettings, error: " << e.what();
} }
catch (...) { catch(...)
{
qWarning() << "DataProvider::getSettings, unknown error"; qWarning() << "DataProvider::getSettings, unknown error";
} }
return StatusGo::Settings::SettingsDto{}; return StatusGo::Settings::SettingsDto{};

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <StatusGo/SettingsAPI>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <StatusGo/SettingsAPI>
namespace Status::Application { namespace Status::Application
{
class DataProvider : public QObject class DataProvider : public QObject
{ {
@ -14,4 +15,4 @@ namespace Status::Application {
StatusGo::Settings::SettingsDto getSettings() const; StatusGo::Settings::SettingsDto getSettings() const;
}; };
} } // namespace Status::Application

View File

@ -5,8 +5,7 @@ using namespace Status::Application;
DbSettingsObj::DbSettingsObj(StatusGo::Settings::SettingsDto rawData) DbSettingsObj::DbSettingsObj(StatusGo::Settings::SettingsDto rawData)
: QObject(nullptr) : QObject(nullptr)
, m_data(std::move(rawData)) , m_data(std::move(rawData))
{ { }
}
QString DbSettingsObj::address() const QString DbSettingsObj::address() const
{ {
@ -15,8 +14,7 @@ QString DbSettingsObj::address() const
void DbSettingsObj::setAddress(const QString& value) void DbSettingsObj::setAddress(const QString& value)
{ {
if (m_data.address == value) if(m_data.address == value) return;
return;
m_data.address = value; m_data.address = value;
emit addressChanged(); emit addressChanged();
} }
@ -28,8 +26,7 @@ QString DbSettingsObj::displayName() const
void DbSettingsObj::setDisplayName(const QString& value) void DbSettingsObj::setDisplayName(const QString& value)
{ {
if (m_data.displayName == value) if(m_data.displayName == value) return;
return;
m_data.displayName = value; m_data.displayName = value;
emit displayNameChanged(); emit displayNameChanged();
} }
@ -41,8 +38,7 @@ QString DbSettingsObj::preferredName() const
void DbSettingsObj::setPreferredName(const QString& value) void DbSettingsObj::setPreferredName(const QString& value)
{ {
if (m_data.preferredName == value) if(m_data.preferredName == value) return;
return;
m_data.preferredName = value; m_data.preferredName = value;
emit preferredNameChanged(); emit preferredNameChanged();
} }
@ -54,8 +50,7 @@ QString DbSettingsObj::keyUid() const
void DbSettingsObj::setKeyUid(const QString& value) void DbSettingsObj::setKeyUid(const QString& value)
{ {
if (m_data.keyUid == value) if(m_data.keyUid == value) return;
return;
m_data.keyUid = value; m_data.keyUid = value;
emit keyUidChanged(); emit keyUidChanged();
} }
@ -67,8 +62,7 @@ QString DbSettingsObj::publicKey() const
void DbSettingsObj::setPublicKey(const QString& value) void DbSettingsObj::setPublicKey(const QString& value)
{ {
if (m_data.publicKey == value) if(m_data.publicKey == value) return;
return;
m_data.publicKey = value; m_data.publicKey = value;
emit publicKeyChanged(); emit publicKeyChanged();
} }

View File

@ -4,7 +4,8 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
namespace Status::Application { namespace Status::Application
{
class DbSettingsObj : public QObject class DbSettingsObj : public QObject
{ {
@ -16,7 +17,6 @@ namespace Status::Application {
Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged) Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged)
Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged) Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged)
public: public:
explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData); explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData);
@ -35,7 +35,6 @@ namespace Status::Application {
[[nodiscard]] QString publicKey() const; [[nodiscard]] QString publicKey() const;
void setPublicKey(const QString& value); void setPublicKey(const QString& value);
signals: signals:
void addressChanged(); void addressChanged();
void displayNameChanged(); void displayNameChanged();
@ -46,4 +45,4 @@ namespace Status::Application {
private: private:
StatusGo::Settings::SettingsDto m_data; StatusGo::Settings::SettingsDto m_data;
}; };
} } // namespace Status::Application

View File

@ -7,8 +7,8 @@
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
#include <Helpers/logs.h> #include <Helpers/logs.h>
#include <QDir>
#include <QDebug> #include <QDebug>
#include <QDir>
using namespace Status; using namespace Status;
@ -24,9 +24,11 @@ int main(int argc, char *argv[])
QTranslator translator; QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages(); const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) { for(const QString& locale : uiLanguages)
{
const QString baseName = BUILD_PROJECT_NAME + QLocale(locale).name(); const QString baseName = BUILD_PROJECT_NAME + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) { if(translator.load(":/i18n/" + baseName))
{
app.installTranslator(&translator); app.installTranslator(&translator);
break; break;
} }
@ -35,17 +37,21 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs); const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(
&app, [url](QObject *obj, const QUrl &objUrl) { &engine,
if (!obj && url == objUrl) &QQmlApplicationEngine::objectCreated,
QCoreApplication::exit(-1); &app,
}, Qt::QueuedConnection); [url](QObject* obj, const QUrl& objUrl) {
if(!obj && url == objUrl) QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
engine.load(url); engine.load(url);
return app.exec(); return app.exec();
} }
void setApplicationInformation(QGuiApplication& app) { void setApplicationInformation(QGuiApplication& app)
{
#if !defined BUILD_PROJECT_ORGANIZATION_NAME #if !defined BUILD_PROJECT_ORGANIZATION_NAME
static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME") static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME")
#endif #endif

View File

@ -8,12 +8,14 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::ApplicationCore { namespace Status::ApplicationCore
{
namespace { namespace
{
constexpr auto statusFolder = "Status"; constexpr auto statusFolder = "Status";
constexpr auto dataSubfolder = "data"; constexpr auto dataSubfolder = "data";
} } // namespace
UserConfiguration::UserConfiguration(QObject* parent) UserConfiguration::UserConfiguration(QObject* parent)
: QObject{parent} : QObject{parent}
@ -34,8 +36,7 @@ const fs::path &UserConfiguration::userDataFolder() const
void UserConfiguration::setUserDataFolder(const QString& newUserDataFolder) void UserConfiguration::setUserDataFolder(const QString& newUserDataFolder)
{ {
auto newVal = Status::toPath(newUserDataFolder); auto newVal = Status::toPath(newUserDataFolder);
if (m_userDataFolder.compare(newVal) == 0) if(m_userDataFolder.compare(newVal) == 0) return;
return;
m_userDataFolder = newVal; m_userDataFolder = newVal;
emit userDataFolderChanged(); emit userDataFolderChanged();
} }
@ -43,7 +44,8 @@ void UserConfiguration::setUserDataFolder(const QString &newUserDataFolder)
void UserConfiguration::generateReleaseConfiguration() void UserConfiguration::generateReleaseConfiguration()
{ {
if(!parseFromCommandLineAndReturnTrueIfSet()) if(!parseFromCommandLineAndReturnTrueIfSet())
m_userDataFolder = toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation))/statusFolder/dataSubfolder; m_userDataFolder =
toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)) / statusFolder / dataSubfolder;
emit userDataFolderChanged(); emit userDataFolderChanged();
} }
@ -55,7 +57,8 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
parser.addPositionalArgument("dataDir", "Data folder"); parser.addPositionalArgument("dataDir", "Data folder");
parser.process(*QCoreApplication::instance()); parser.process(*QCoreApplication::instance());
auto args = parser.positionalArguments(); auto args = parser.positionalArguments();
if (args.size() > 0) { if(args.size() > 0)
{
m_userDataFolder = toPath(args[0]); m_userDataFolder = toPath(args[0]);
emit userDataFolderChanged(); emit userDataFolderChanged();
return true; return true;
@ -63,4 +66,4 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
return false; return false;
} }
} } // namespace Status::ApplicationCore

View File

@ -5,7 +5,8 @@
#include <filesystem> #include <filesystem>
namespace Status::ApplicationCore { namespace Status::ApplicationCore
{
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -35,4 +36,4 @@ private:
fs::path m_userDataFolder; fs::path m_userDataFolder;
}; };
} } // namespace Status::ApplicationCore

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <StatusGo/ChatAPI>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <StatusGo/ChatAPI>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatDataProvider : public QObject class ChatDataProvider : public QObject
{ {
@ -14,4 +15,4 @@ namespace Status::ChatSection {
StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const; StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const;
}; };
} } // namespace Status::ChatSection

View File

@ -4,7 +4,8 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatItem : public QObject class ChatItem : public QObject
{ {
@ -49,4 +50,4 @@ namespace Status::ChatSection {
}; };
using ChatItemPtr = std::shared_ptr<ChatItem>; using ChatItemPtr = std::shared_ptr<ChatItem>;
} } // namespace Status::ChatSection

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "ChatItem.h"
#include "ChatDataProvider.h" #include "ChatDataProvider.h"
#include "ChatItem.h"
#include <Helpers/QObjectVectorModel.h> #include <Helpers/QObjectVectorModel.h>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatSectionController : public QObject class ChatSectionController : public QObject
{ {
@ -34,4 +35,4 @@ namespace Status::ChatSection {
std::unique_ptr<ChatDataProvider> m_dataProvider; std::unique_ptr<ChatDataProvider> m_dataProvider;
ChatItemPtr m_currentChat; ChatItemPtr m_currentChat;
}; };
} } // namespace Status::ChatSection

View File

@ -6,22 +6,24 @@ namespace StatusGo = Status::StatusGo;
ChatDataProvider::ChatDataProvider() ChatDataProvider::ChatDataProvider()
: QObject(nullptr) : QObject(nullptr)
{ { }
}
StatusGo::Chats::ChannelGroupDto ChatDataProvider::getSectionData(const QString& sectionId) const StatusGo::Chats::ChannelGroupDto ChatDataProvider::getSectionData(const QString& sectionId) const
{ {
try { try
{
auto result = StatusGo::Chats::getChats(); auto result = StatusGo::Chats::getChats();
for(auto chGroup : result.allChannelGroups) { for(auto chGroup : result.allChannelGroups)
if (chGroup.id == sectionId) {
return chGroup; if(chGroup.id == sectionId) return chGroup;
} }
} }
catch (std::exception& e) { catch(std::exception& e)
{
qWarning() << "ChatDataProvider::getSectionData, error: " << e.what(); qWarning() << "ChatDataProvider::getSectionData, error: " << e.what();
} }
catch (...) { catch(...)
{
qWarning() << "ChatDataProvider::getSectionData, unknown error"; qWarning() << "ChatDataProvider::getSectionData, unknown error";
} }
return StatusGo::Chats::ChannelGroupDto{}; return StatusGo::Chats::ChannelGroupDto{};

View File

@ -5,8 +5,7 @@ using namespace Status::ChatSection;
ChatItem::ChatItem(StatusGo::Chats::ChatDto rawData) ChatItem::ChatItem(StatusGo::Chats::ChatDto rawData)
: QObject(nullptr) : QObject(nullptr)
, m_data(std::move(rawData)) , m_data(std::move(rawData))
{ { }
}
QString ChatItem::id() const QString ChatItem::id() const
{ {
@ -20,8 +19,7 @@ QString ChatItem::name() const
void ChatItem::setName(const QString& value) void ChatItem::setName(const QString& value)
{ {
if (m_data.name == value) if(m_data.name == value) return;
return;
m_data.name = value; m_data.name = value;
emit nameChanged(); emit nameChanged();
} }
@ -33,8 +31,7 @@ QString ChatItem::description() const
void ChatItem::setDescription(const QString& value) void ChatItem::setDescription(const QString& value)
{ {
if (m_data.description == value) if(m_data.description == value) return;
return;
m_data.description = value; m_data.description = value;
emit descriptionChanged(); emit descriptionChanged();
} }
@ -46,8 +43,7 @@ QColor ChatItem::color() const
void ChatItem::setColor(const QColor& value) void ChatItem::setColor(const QColor& value)
{ {
if (m_data.color == value) if(m_data.color == value) return;
return;
m_data.color = value; m_data.color = value;
emit colorChanged(); emit colorChanged();
} }
@ -59,8 +55,7 @@ bool ChatItem::muted() const
void ChatItem::setMuted(bool value) void ChatItem::setMuted(bool value)
{ {
if (m_data.muted == value) if(m_data.muted == value) return;
return;
m_data.muted = value; m_data.muted = value;
emit mutedChanged(); emit mutedChanged();
} }
@ -72,8 +67,7 @@ bool ChatItem::active() const
void ChatItem::setActive(bool value) void ChatItem::setActive(bool value)
{ {
if (m_data.active == value) if(m_data.active == value) return;
return;
m_data.active = value; m_data.active = value;
emit activeChanged(); emit activeChanged();
} }

View File

@ -5,15 +5,15 @@ using namespace Status::ChatSection;
ChatSectionController::ChatSectionController() ChatSectionController::ChatSectionController()
: QObject(nullptr) : QObject(nullptr)
, m_dataProvider(std::make_unique<ChatDataProvider>()) , m_dataProvider(std::make_unique<ChatDataProvider>())
{ { }
}
void ChatSectionController::init(const QString& sectionId) void ChatSectionController::init(const QString& sectionId)
{ {
auto chatSectionData = m_dataProvider->getSectionData(sectionId); auto chatSectionData = m_dataProvider->getSectionData(sectionId);
assert(chatSectionData.chats.size() > 0); assert(chatSectionData.chats.size() > 0);
std::vector<ChatItemPtr> model; std::vector<ChatItemPtr> model;
for (auto c : chatSectionData.chats) { for(auto c : chatSectionData.chats)
{
model.push_back(std::make_shared<ChatItem>(std::move(c))); model.push_back(std::make_shared<ChatItem>(std::move(c)));
} }
m_chats = std::make_shared<ChatsModel>(std::move(model), "chat"); m_chats = std::make_shared<ChatsModel>(std::move(model), "chat");
@ -34,8 +34,7 @@ ChatItem* ChatSectionController::currentChat() const
void ChatSectionController::setCurrentChatIndex(int index) void ChatSectionController::setCurrentChatIndex(int index)
{ {
auto chat = index >= 0 && index < m_chats->size() ? m_chats->get(index) : ChatItemPtr(); auto chat = index >= 0 && index < m_chats->size() ? m_chats->get(index) : ChatItemPtr();
if (m_currentChat == chat) if(m_currentChat == chat) return;
return;
m_currentChat = chat; m_currentChat = chat;
emit currentChatChanged(); emit currentChatChanged();

View File

@ -6,13 +6,12 @@
if(REQUIRED) \ if(REQUIRED) \
j.at(NAME).get_to(d.FIELD); \ j.at(NAME).get_to(d.FIELD); \
else if(j.contains(NAME)) \ else if(j.contains(NAME)) \
j.at(NAME).get_to(d.FIELD); \ j.at(NAME).get_to(d.FIELD);
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true) STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true)
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
// This macro reads prop from the nlohman json object. It implies that nlohman json object is named `j` and the struct // This macro reads prop from the nlohman json object. It implies that nlohman json object is named `j` and the struct
// instance that json object should be mapped to is named `d`. // instance that json object should be mapped to is named `d`.
@ -28,11 +27,7 @@ STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
// STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName", false) // STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName", false)
// //
#define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \
STATUS_EXPAND( \ STATUS_EXPAND(STATUS_MACRO_SELECTOR_3_ARGS(__VA_ARGS__, \
STATUS_MACRO_SELECTOR_3_ARGS( \
__VA_ARGS__, \
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \ STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \ STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \
STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS \ STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS)(__VA_ARGS__))
)(__VA_ARGS__) \
)

View File

@ -4,9 +4,7 @@
#define STATUS_EXPAND(x) x #define STATUS_EXPAND(x) x
// 2 arguments macro selector. // 2 arguments macro selector.
#define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) \ #define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) selected
selected
// 3 arguments macro selector. // 3 arguments macro selector.
#define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) \ #define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) selected
selected

View File

@ -7,7 +7,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::Helpers { namespace Status::Helpers
{
template <typename T> template <typename T>
using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type; using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type;
@ -19,27 +20,52 @@ class NamedType
public: public:
using UnderlyingType = T; using UnderlyingType = T;
explicit constexpr NamedType(T const& value) : m_value(value) {} explicit constexpr NamedType(T const& value)
: m_value(value)
{ }
template <typename T_ = T, typename = IsNotReference<T_>> template <typename T_ = T, typename = IsNotReference<T_>>
explicit constexpr NamedType(T&& value) : m_value(std::move(value)) {} explicit constexpr NamedType(T&& value)
: m_value(std::move(value))
{ }
explicit constexpr NamedType() = default; explicit constexpr NamedType() = default;
constexpr T& get() { constexpr T& get()
{
return m_value; return m_value;
} }
constexpr std::remove_reference_t<T> const& get() const { constexpr std::remove_reference_t<T> const& get() const
{
return m_value; return m_value;
} }
bool operator<(const NamedType<T, Parameter> &other) const { return m_value < other.m_value; }; bool operator<(const NamedType<T, Parameter>& other) const
bool operator>(const NamedType<T, Parameter> &other) const { return m_value > other.m_value; }; {
bool operator<=(const NamedType<T, Parameter> &other) const { return m_value <= other.m_value; }; return m_value < other.m_value;
bool operator>=(const NamedType<T, Parameter> &other) const { return m_value >= other.m_value; }; };
bool operator==(const NamedType<T, Parameter> &other) const { return m_value == other.m_value; }; bool operator>(const NamedType<T, Parameter>& other) const
bool operator!=(const NamedType<T, Parameter> &other) const { return m_value != other.m_value; }; {
return m_value > other.m_value;
};
bool operator<=(const NamedType<T, Parameter>& other) const
{
return m_value <= other.m_value;
};
bool operator>=(const NamedType<T, Parameter>& other) const
{
return m_value >= other.m_value;
};
bool operator==(const NamedType<T, Parameter>& other) const
{
return m_value == other.m_value;
};
bool operator!=(const NamedType<T, Parameter>& other) const
{
return m_value != other.m_value;
};
T &operator=(NamedType<T, Parameter> const& rhs) { T& operator=(NamedType<T, Parameter> const& rhs)
{
return m_value = rhs.m_value; return m_value = rhs.m_value;
}; };
@ -48,16 +74,18 @@ private:
}; };
template <typename T, typename P> template <typename T, typename P>
void to_json(json& j, const NamedType<T, P>& p) { void to_json(json& j, const NamedType<T, P>& p)
{
j = p.get(); j = p.get();
} }
template <typename T, typename P> template <typename T, typename P>
void from_json(const json& j, NamedType<T, P>& p) { void from_json(const json& j, NamedType<T, P>& p)
{
p = NamedType<T, P>{j.get<T>()}; p = NamedType<T, P>{j.get<T>()};
} }
} } // namespace Status::Helpers
namespace std namespace std
{ {

View File

@ -2,7 +2,8 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine> #include <QQmlEngine>
namespace Status::Helpers { namespace Status::Helpers
{
/// Generic typed QObject provider model /// Generic typed QObject provider model
/// ///
@ -15,83 +16,96 @@ class QObjectVectorModel final : public QAbstractListModel
static_assert(std::is_base_of<QObject, T>::value, "Template parameter (T) not a QObject"); static_assert(std::is_base_of<QObject, T>::value, "Template parameter (T) not a QObject");
public: public:
using ObjectContainer = std::vector<std::shared_ptr<T>>; using ObjectContainer = std::vector<std::shared_ptr<T>>;
explicit QObjectVectorModel(ObjectContainer initialObjects, const char* objectRoleName, QObject* parent = nullptr) explicit QObjectVectorModel(ObjectContainer initialObjects, const char* objectRoleName, QObject* parent = nullptr)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_objects(std::move(initialObjects)) , m_objects(std::move(initialObjects))
, m_roleName(objectRoleName) , m_roleName(objectRoleName)
{ { }
}
explicit QObjectVectorModel(const char* objectRoleName, QObject* parent = nullptr) explicit QObjectVectorModel(const char* objectRoleName, QObject* parent = nullptr)
: QObjectVectorModel(ObjectContainer{}, objectRoleName, parent) : QObjectVectorModel(ObjectContainer{}, objectRoleName, parent)
{ } { }
~QObjectVectorModel(){}; ~QObjectVectorModel(){};
QHash<int, QByteArray> roleNames() const override { QHash<int, QByteArray> roleNames() const override
{
return {{ObjectRole, m_roleName}}; return {{ObjectRole, m_roleName}};
}; };
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override { virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override
{
Q_UNUSED(parent) Q_UNUSED(parent)
return m_objects.size(); return m_objects.size();
} }
virtual QVariant data(const QModelIndex& index, int role) const override { virtual QVariant data(const QModelIndex& index, int role) const override
if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole) {
return QVariant(); if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole) return QVariant();
return QVariant::fromValue<QObject*>(m_objects[index.row()].get()); return QVariant::fromValue<QObject*>(m_objects[index.row()].get());
} }
const T* at(size_t pos) const { const T* at(size_t pos) const
{
return m_objects.at(pos).get(); return m_objects.at(pos).get();
}; };
std::shared_ptr<T> get(size_t pos) { std::shared_ptr<T> get(size_t pos)
{
return m_objects.at(pos); return m_objects.at(pos);
}; };
size_t size() const { size_t size() const
{
return m_objects.size(); return m_objects.size();
}; };
void reset(const ObjectContainer& objects) { void reset(const ObjectContainer& objects)
{
beginResetModel(); beginResetModel();
m_objects = objects; m_objects = objects;
endResetModel(); endResetModel();
}; };
void clear() { void clear()
{
reset({}); reset({});
}; };
void push_back(const std::shared_ptr<T>& newValue) { void push_back(const std::shared_ptr<T>& newValue)
{
beginInsertRows(QModelIndex(), m_objects.size(), m_objects.size()); beginInsertRows(QModelIndex(), m_objects.size(), m_objects.size());
m_objects.push_back(newValue); m_objects.push_back(newValue);
endInsertRows(); endInsertRows();
}; };
void resize(size_t count) { void resize(size_t count)
if(count > m_objects.size()) { {
if(count > m_objects.size())
{
beginInsertRows(QModelIndex(), m_objects.size(), count - 1); beginInsertRows(QModelIndex(), m_objects.size(), count - 1);
m_objects.resize(count); m_objects.resize(count);
endInsertRows(); endInsertRows();
} }
else if(count < m_objects.size()) { else if(count < m_objects.size())
{
beginRemoveRows(QModelIndex(), count, m_objects.size() - 1); beginRemoveRows(QModelIndex(), count, m_objects.size() - 1);
m_objects.resize(count); m_objects.resize(count);
endRemoveRows(); endRemoveRows();
} }
}; };
void set(size_t row, const std::shared_ptr<T>& newVal) { void set(size_t row, const std::shared_ptr<T>& newVal)
{
m_objects.at(row) = newVal; m_objects.at(row) = newVal;
emit dataChanged(index(row), index(row), {}); emit dataChanged(index(row), index(row), {});
}; };
const ObjectContainer &objects() const { return m_objects; }; const ObjectContainer& objects() const
{
return m_objects;
};
private: private:
ObjectContainer m_objects; ObjectContainer m_objects;
@ -101,4 +115,4 @@ private:
constexpr static auto ObjectRole = Qt::UserRole + 1; constexpr static auto ObjectRole = Qt::UserRole + 1;
}; };
} } // namespace Status::Helpers

View File

@ -19,9 +19,9 @@ public:
Singleton<T>(const Singleton<T>&) = delete; Singleton<T>(const Singleton<T>&) = delete;
Singleton<T>& operator=(const Singleton<T>&) = delete; Singleton<T>& operator=(const Singleton<T>&) = delete;
private:
private:
Singleton<T>() = default; Singleton<T>() = default;
}; };
} } // namespace Status::Helpers

View File

@ -2,14 +2,17 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status { namespace Status
{
QString toQString(const fs::path &path) { QString toQString(const fs::path& path)
{
return QString::fromStdString(path.string()); return QString::fromStdString(path.string());
} }
fs::path toPath(const QString &pathStr) { fs::path toPath(const QString& pathStr)
{
return fs::path(pathStr.toStdString()); return fs::path(pathStr.toStdString());
} }
} } // namespace Status

View File

@ -2,9 +2,9 @@
#include "helpers.h" #include "helpers.h"
#include <QString>
#include <QByteArray> #include <QByteArray>
#include <QColor> #include <QColor>
#include <QString>
#include <QUrl> #include <QUrl>
#include <filesystem> #include <filesystem>
@ -13,7 +13,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status { namespace Status
{
QString toQString(const std::filesystem::path& path); QString toQString(const std::filesystem::path& path);
@ -21,15 +22,19 @@ std::filesystem::path toPath(const QString& pathStr);
} // namespace Status } // namespace Status
namespace nlohmann { namespace nlohmann
{
template <> template <>
struct adl_serializer<QString> { struct adl_serializer<QString>
static void to_json(json& j, const QString& str) { {
static void to_json(json& j, const QString& str)
{
j = str.toStdString(); j = str.toStdString();
} }
static void from_json(const json& j, QString& str) { static void from_json(const json& j, QString& str)
{
str = QString::fromStdString(j.get<std::string>()); str = QString::fromStdString(j.get<std::string>());
} }
}; };
@ -37,12 +42,15 @@ struct adl_serializer<QString> {
using namespace std::string_literals; using namespace std::string_literals;
template <> template <>
struct adl_serializer<QByteArray> { struct adl_serializer<QByteArray>
static void to_json(json& j, const QByteArray& data) { {
static void to_json(json& j, const QByteArray& data)
{
j = data.toStdString(); j = data.toStdString();
} }
static void from_json(const json& j, QByteArray& data) { static void from_json(const json& j, QByteArray& data)
{
auto str = j.get<std::string>(); auto str = j.get<std::string>();
if(str.size() >= 2 && Status::Helpers::iequals(str, "0x"s, 2)) if(str.size() >= 2 && Status::Helpers::iequals(str, "0x"s, 2))
data = QByteArray::fromHex(QByteArray::fromRawData(str.c_str() + 2 * sizeof(str[0]), str.size() - 2)); data = QByteArray::fromHex(QByteArray::fromRawData(str.c_str() + 2 * sizeof(str[0]), str.size() - 2));
@ -52,34 +60,43 @@ struct adl_serializer<QByteArray> {
}; };
template <> template <>
struct adl_serializer<QColor> { struct adl_serializer<QColor>
static void to_json(json& j, const QColor& color) { {
static void to_json(json& j, const QColor& color)
{
j = color.name(); j = color.name();
} }
static void from_json(const json& j, QColor& color) { static void from_json(const json& j, QColor& color)
{
color = QColor(QString::fromStdString(j.get<std::string>())); color = QColor(QString::fromStdString(j.get<std::string>()));
} }
}; };
template <> template <>
struct adl_serializer<QUrl> { struct adl_serializer<QUrl>
static void to_json(json& j, const QUrl& url) { {
static void to_json(json& j, const QUrl& url)
{
j = url.toString(); j = url.toString();
} }
static void from_json(const json& j, QUrl& url) { static void from_json(const json& j, QUrl& url)
{
url = QUrl(QString::fromStdString(j.get<std::string>())); url = QUrl(QString::fromStdString(j.get<std::string>()));
} }
}; };
template <typename T> template <typename T>
struct adl_serializer<std::optional<T>> { struct adl_serializer<std::optional<T>>
static void to_json(json& j, const std::optional<T>& opt) { {
static void to_json(json& j, const std::optional<T>& opt)
{
j = opt.value(); j = opt.value();
} }
static void from_json(const json& j, std::optional<T>& opt) { static void from_json(const json& j, std::optional<T>& opt)
{
opt.emplace(j.get<T>()); opt.emplace(j.get<T>());
} }
}; };

View File

@ -4,11 +4,12 @@
#include <QObject> #include <QObject>
#include <string>
#include <map> #include <map>
#include <memory.h> #include <memory.h>
#include <string>
namespace Status::Helpers { namespace Status::Helpers
{
constexpr bool isDebugBuild() constexpr bool isDebugBuild()
{ {
@ -26,11 +27,11 @@ template<typename T>
bool iequals(const T& a, const T& b, size_t len = -1) bool iequals(const T& a, const T& b, size_t len = -1)
{ {
return len < a.size() && len < b.size() && return len < a.size() && len < b.size() &&
std::equal(a.begin(), len >= 0 ? a.end() : a.begin() + len, std::equal(a.begin(),
b.begin(), len >= 0 ? b.end() : b.begin() + len, len >= 0 ? a.end() : a.begin() + len,
[](auto a, auto b) { b.begin(),
return tolower(a) == tolower(b); len >= 0 ? b.end() : b.begin() + len,
}); [](auto a, auto b) { return tolower(a) == tolower(b); });
} }
template <typename KeyType, typename ValT> template <typename KeyType, typename ValT>
@ -43,14 +44,16 @@ std::vector<KeyType> getKeys(const std::map<KeyType, ValT>& map)
return keys; return keys;
} }
static void doDeleteLater(QObject *obj) { static void doDeleteLater(QObject* obj)
{
obj->deleteLater(); obj->deleteLater();
} }
// TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared // TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared
template <typename T, typename... Args> template <typename T, typename... Args>
std::shared_ptr<T> makeSharedQObject(Args&& ...args) { std::shared_ptr<T> makeSharedQObject(Args&&... args)
{
return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater); return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater);
} }
} } // namespace Status::Helpers

View File

@ -8,7 +8,8 @@
#include "BuildConfiguration.h" #include "BuildConfiguration.h"
namespace Status::Helpers { namespace Status::Helpers
{
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg) void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{ {
@ -37,7 +38,12 @@ void logFormatter(QtMsgType type, const QMessageLogContext& context, const QStri
case QtFatalMsg: log = "\033[0;31m!!! \033[0m%s \033[1m%s \033[0;33mfile=\033[94m%s:%u %s\n"; break; case QtFatalMsg: log = "\033[0;31m!!! \033[0m%s \033[1m%s \033[0;33mfile=\033[94m%s:%u %s\n"; break;
} }
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout,
log, timestamp.constData(), localMsg.constData(), file, context.line, function.constData()); log,
timestamp.constData(),
localMsg.constData(),
file,
context.line,
function.constData());
} }
} // namespace } // namespace Status::Helpers

View File

@ -4,9 +4,10 @@
#include <QDebug> #include <QDebug>
#include <QString> #include <QString>
namespace Status::Helpers { namespace Status::Helpers
{
/// Formats with colloring output if not a development build /// Formats with colloring output if not a development build
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg); void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg);
} } // namespace Status::Helpers

View File

@ -3,16 +3,14 @@
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/Accounts/AccountsAPI.h> #include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/General.h> #include <StatusGo/General.h>
#include <StatusGo/Utils.h>
#include <StatusGo/Messenger/Service.h> #include <StatusGo/Messenger/Service.h>
#include <StatusGo/Utils.h>
#include <Helpers/conversions.h> #include <Helpers/conversions.h>
#include <optional> #include <optional>
std::optional<QString> getDataFromFile(const fs::path& path)
std::optional<QString>
getDataFromFile(const fs::path &path)
{ {
QFile jsonFile{Status::toQString(path)}; QFile jsonFile{Status::toQString(path)};
if(!jsonFile.open(QIODevice::ReadOnly)) if(!jsonFile.open(QIODevice::ReadOnly))
@ -34,8 +32,7 @@ namespace Status::Onboarding
AccountsService::AccountsService() AccountsService::AccountsService()
: m_isFirstTimeAccountLogin(false) : m_isFirstTimeAccountLogin(false)
{ { }
}
bool AccountsService::init(const fs::path& statusgoDataDir) bool AccountsService::init(const fs::path& statusgoDataDir)
{ {
@ -79,13 +76,14 @@ const std::vector<GeneratedMultiAccount>& AccountsService::generatedAccounts() c
return m_generatedAccounts; return m_generatedAccounts;
} }
bool AccountsService::setupAccountAndLogin(const QString &accountId, const QString &password, const QString &displayName) bool AccountsService::setupAccountAndLogin(const QString& accountId,
const QString& password,
const QString& displayName)
{ {
const QString installationId(QUuid::createUuid().toString(QUuid::WithoutBraces)); const QString installationId(QUuid::createUuid().toString(QUuid::WithoutBraces));
const QJsonObject accountData(getAccountDataForAccountId(accountId, displayName)); const QJsonObject accountData(getAccountDataForAccountId(accountId, displayName));
if(!setKeyStoreDir(accountData.value("key-uid").toString())) if(!setKeyStoreDir(accountData.value("key-uid").toString())) return false;
return false;
QJsonArray subAccountData(getSubaccountDataForAccountId(accountId, displayName)); QJsonArray subAccountData(getSubaccountDataForAccountId(accountId, displayName));
QJsonObject settings(getAccountSettings(accountId, installationId, displayName)); QJsonObject settings(getAccountSettings(accountId, installationId, displayName));
@ -94,8 +92,7 @@ bool AccountsService::setupAccountAndLogin(const QString &accountId, const QStri
auto hashedPassword(Utils::hashPassword(password)); auto hashedPassword(Utils::hashPassword(password));
// This initialize the DB if first time running. Required for storing accounts // This initialize the DB if first time running. Required for storing accounts
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) return false;
return false;
AccountsService::storeAccount(accountId, hashedPassword); AccountsService::storeAccount(accountId, hashedPassword);
AccountsService::storeDerivedAccounts(accountId, hashedPassword, Constants::General::AccountDefaultPaths); AccountsService::storeDerivedAccounts(accountId, hashedPassword, Constants::General::AccountDefaultPaths);
@ -130,8 +127,7 @@ bool AccountsService::setKeyStoreDir(const QString &key)
QString AccountsService::login(MultiAccount account, const QString& password) QString AccountsService::login(MultiAccount account, const QString& password)
{ {
// This is a requirement. Make it more explicit into the status go module // This is a requirement. Make it more explicit into the status go module
if(!setKeyStoreDir(account.keyUid)) if(!setKeyStoreDir(account.keyUid)) return QString("Failed to initialize keystore before logging in");
return QString("Failed to initialize keystore before logging in");
// This initialize the DB if first time running. Required before logging in // This initialize the DB if first time running. Required before logging in
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError())
@ -141,8 +137,8 @@ QString AccountsService::login(MultiAccount account, const QString& password)
const QString thumbnailImage; const QString thumbnailImage;
const QString largeImage; const QString largeImage;
const auto response = StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword, const auto response =
thumbnailImage, largeImage); StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword, thumbnailImage, largeImage);
if(response.containsError()) if(response.containsError())
{ {
qWarning() << response.error.message; qWarning() << response.error.message;
@ -179,7 +175,8 @@ void AccountsService::deleteMultiAccount(const MultiAccount &account)
StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir); StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir);
} }
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password, DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId,
const StatusGo::HashedPassword& password,
const std::vector<Accounts::DerivationPath>& paths) const std::vector<Accounts::DerivationPath>& paths)
{ {
const auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths); const auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths);
@ -202,11 +199,14 @@ StoredMultiAccount AccountsService::storeAccount(const QString& accountId, const
return toStoredMultiAccount(response.result); return toStoredMultiAccount(response.result);
} }
MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account, MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& config) const QJsonObject& config)
{ {
if(!StatusGo::Accounts::saveAccountAndLogin(password, account, subaccounts, settings, config)) { if(!StatusGo::Accounts::saveAccountAndLogin(password, account, subaccounts, settings, config))
{
qWarning() << "Failed saving acccount" << account.value("name"); qWarning() << "Failed saving acccount" << account.value("name");
return MultiAccount(); return MultiAccount();
} }
@ -215,7 +215,8 @@ MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword
return MultiAccount::toMultiAccount(account); return MultiAccount::toMultiAccount(account);
} }
QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedMultiAccount& account,
const QString& displayName) const
{ {
return QJsonObject{{"name", displayName.isEmpty() ? account.alias : displayName}, return QJsonObject{{"name", displayName.isEmpty() ? account.alias : displayName},
{"address", account.address}, {"address", account.address},
@ -245,27 +246,22 @@ QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId
return QJsonObject(); return QJsonObject();
} }
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account,
const QString& displayName) const
{ {
return { return {QJsonObject{{"public-key", account.derivedAccounts.defaultWallet.publicKey},
QJsonObject{
{"public-key", account.derivedAccounts.defaultWallet.publicKey},
{"address", account.derivedAccounts.defaultWallet.address}, {"address", account.derivedAccounts.defaultWallet.address},
{"color", "#4360df"}, {"color", "#4360df"},
{"wallet", true}, {"wallet", true},
{"path", Constants::General::PathDefaultWallet.get()}, {"path", Constants::General::PathDefaultWallet.get()},
{"name", "Status account"}, {"name", "Status account"},
{"derived-from", account.address} {"derived-from", account.address}},
}, QJsonObject{{"public-key", account.derivedAccounts.whisper.publicKey},
QJsonObject{
{"public-key", account.derivedAccounts.whisper.publicKey},
{"address", account.derivedAccounts.whisper.address}, {"address", account.derivedAccounts.whisper.address},
{"name", displayName.isEmpty() ? account.alias : displayName}, {"name", displayName.isEmpty() ? account.alias : displayName},
{"path", Constants::General::PathWhisper.get()}, {"path", Constants::General::PathWhisper.get()},
{"chat", true}, {"chat", true},
{"derived-from", ""} {"derived-from", ""}}};
}
};
} }
QJsonArray AccountsService::getSubaccountDataForAccountId(const QString& accountId, const QString& displayName) const QJsonArray AccountsService::getSubaccountDataForAccountId(const QString& accountId, const QString& displayName) const
@ -306,8 +302,7 @@ QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMul
const QString& installationId, const QString& installationId,
const QString& displayName) const const QString& displayName) const
{ {
return QJsonObject{ return QJsonObject{{"key-uid", account.keyUid},
{"key-uid", account.keyUid},
{"mnemonic", account.mnemonic}, {"mnemonic", account.mnemonic},
{"public-key", account.derivedAccounts.whisper.publicKey}, {"public-key", account.derivedAccounts.whisper.publicKey},
{"name", account.alias}, {"name", account.alias},
@ -326,11 +321,12 @@ QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMul
{"wallet/visible-tokens", QJsonObject()}, {"wallet/visible-tokens", QJsonObject()},
{"waku-enabled", true}, {"waku-enabled", true},
{"appearance", 0}, {"appearance", 0},
{"installation-id", installationId} {"installation-id", installationId}};
};
} }
QJsonObject AccountsService::getAccountSettings(const QString& accountId, const QString& installationId, const QString &displayName) const QJsonObject AccountsService::getAccountSettings(const QString& accountId,
const QString& installationId,
const QString& displayName) const
{ {
for(const GeneratedMultiAccount& acc : m_generatedAccounts) for(const GeneratedMultiAccount& acc : m_generatedAccounts)
@ -363,7 +359,8 @@ QJsonArray getNodes(const QJsonObject& fleet, const QString& nodeType)
QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId) const QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId) const
{ {
try { try
{
auto templateNodeConfigJsonStr = getDataFromFile(":/Status/StaticConfig/node-config.json").value(); auto templateNodeConfigJsonStr = getDataFromFile(":/Status/StaticConfig/node-config.json").value();
auto fleetJson = getDataFromFile(":/Status/StaticConfig/fleets.json").value(); auto fleetJson = getDataFromFile(":/Status/StaticConfig/fleets.json").value();
auto infuraKey = getDataFromFile(":/Status/StaticConfig/infura_key").value(); auto infuraKey = getDataFromFile(":/Status/StaticConfig/infura_key").value();
@ -376,8 +373,8 @@ QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId)
auto DEFAULT_TORRENT_CONFIG_DATADIR = m_statusgoDataDir / "archivedata"; auto DEFAULT_TORRENT_CONFIG_DATADIR = m_statusgoDataDir / "archivedata";
auto DEFAULT_TORRENT_CONFIG_TORRENTDIR = m_statusgoDataDir / "torrents"; auto DEFAULT_TORRENT_CONFIG_TORRENTDIR = m_statusgoDataDir / "torrents";
auto nodeConfigJsonStr = templateNodeConfigJsonStr auto nodeConfigJsonStr =
.replace("%INSTALLATIONID%", installationId) templateNodeConfigJsonStr.replace("%INSTALLATIONID%", installationId)
.replace("%INFURA_TOKEN_RESOLVED%", infuraKey) .replace("%INFURA_TOKEN_RESOLVED%", infuraKey)
.replace("%DEFAULT_TORRENT_CONFIG_PORT%", QString::number(DEFAULT_TORRENT_CONFIG_PORT)) .replace("%DEFAULT_TORRENT_CONFIG_PORT%", QString::number(DEFAULT_TORRENT_CONFIG_PORT))
.replace("%DEFAULT_TORRENT_CONFIG_DATADIR%", DEFAULT_TORRENT_CONFIG_DATADIR.c_str()) .replace("%DEFAULT_TORRENT_CONFIG_DATADIR%", DEFAULT_TORRENT_CONFIG_DATADIR.c_str())
@ -413,9 +410,11 @@ QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId)
nodeConfigJson["KeyStoreDir"] = toQString(fs::relative(m_keyStoreDir, m_statusgoDataDir)); nodeConfigJson["KeyStoreDir"] = toQString(fs::relative(m_keyStoreDir, m_statusgoDataDir));
return nodeConfigJson; return nodeConfigJson;
} catch (std::bad_optional_access) { }
catch(std::bad_optional_access)
{
return QJsonObject(); return QJsonObject();
} }
} }
} } // namespace Status::Onboarding

View File

@ -59,12 +59,15 @@ public:
private: private:
QJsonObject prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const; QJsonObject prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const;
DerivedAccounts storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password, DerivedAccounts storeDerivedAccounts(const QString& accountId,
const StatusGo::HashedPassword& password,
const std::vector<Accounts::DerivationPath>& paths); const std::vector<Accounts::DerivationPath>& paths);
StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password); StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password);
MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account, MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& config); const QJsonObject& config);
QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const; QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const;
@ -79,7 +82,8 @@ private:
const QString& installationId, const QString& installationId,
const QString& displayName) const; const QString& displayName) const;
QJsonObject getAccountSettings(const QString& accountId, const QString& installationId, const QString& displayName) const; QJsonObject
getAccountSettings(const QString& accountId, const QString& installationId, const QString& displayName) const;
QJsonObject getDefaultNodeConfig(const QString& installationId) const; QJsonObject getDefaultNodeConfig(const QString& installationId) const;
@ -97,4 +101,4 @@ private:
static constexpr auto m_keyStoreDirName = "keystore"; static constexpr auto m_keyStoreDirName = "keystore";
}; };
} } // namespace Status::Onboarding

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "MultiAccount.h"
#include "GeneratedMultiAccount.h" #include "GeneratedMultiAccount.h"
#include "MultiAccount.h"
#include <filesystem> #include <filesystem>
@ -13,7 +13,6 @@ namespace Status::Onboarding
class AccountsServiceInterface class AccountsServiceInterface
{ {
public: public:
virtual ~AccountsServiceInterface() = default; virtual ~AccountsServiceInterface() = default;
/// Generates and cache addresses accessible by \c generatedAccounts /// Generates and cache addresses accessible by \c generatedAccounts
@ -26,7 +25,8 @@ public:
[[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0; [[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0;
/// Configure an generated account. \a accountID must be sourced from \c generatedAccounts /// Configure an generated account. \a accountID must be sourced from \c generatedAccounts
virtual bool setupAccountAndLogin(const QString& accountID, const QString& password, const QString& displayName) = 0; virtual bool
setupAccountAndLogin(const QString& accountID, const QString& password, const QString& displayName) = 0;
/// Account that is currently logged-in /// Account that is currently logged-in
[[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0; [[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0;
@ -50,4 +50,4 @@ public:
using AccountsServiceInterfacePtr = std::shared_ptr<AccountsServiceInterface>; using AccountsServiceInterfacePtr = std::shared_ptr<AccountsServiceInterface>;
} } // namespace Status::Onboarding

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "Common/Constants.h" #include "Common/Constants.h"
#include "Common/SigningPhrases.h"
#include "Common/Json.h" #include "Common/Json.h"
#include "Common/SigningPhrases.h"
#include <QtCore> #include <QtCore>
@ -76,17 +76,19 @@ struct StoredMultiAccount
{ {
QString publicKey; QString publicKey;
QString address; QString address;
}; };
static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj) static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj)
{ {
auto result = StoredMultiAccount(); auto result = StoredMultiAccount();
try { try
{
result.address = Json::getMandatoryProp(jsonObj, "address")->toString(); result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString(); result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
} catch (std::exception e) { }
catch(std::exception e)
{
qWarning() << QString("Mapping StoredMultiAccount failed: %1").arg(e.what()); qWarning() << QString("Mapping StoredMultiAccount failed: %1").arg(e.what());
} }
@ -137,4 +139,4 @@ struct GeneratedMultiAccount
} }
}; };
} } // namespace Status::Onboarding

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "Common/Constants.h" #include "Common/Constants.h"
#include "Common/SigningPhrases.h"
#include "Common/Json.h" #include "Common/Json.h"
#include "Common/SigningPhrases.h"
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
@ -39,11 +39,11 @@ struct MultiAccount
{ {
result.name = Json::getMandatoryProp(jsonObj, "name")->toString(); result.name = Json::getMandatoryProp(jsonObj, "name")->toString();
auto timestampIt = Json::getProp(jsonObj, "timestamp"); auto timestampIt = Json::getProp(jsonObj, "timestamp");
if(timestampIt != jsonObj.constEnd()) { if(timestampIt != jsonObj.constEnd())
{
bool ok = false; bool ok = false;
auto t = timestampIt->toString().toLong(&ok); auto t = timestampIt->toString().toLong(&ok);
if(ok) if(ok) result.timestamp = t;
result.timestamp = t;
} }
result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString(); result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString();
result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString(); result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString();
@ -60,4 +60,4 @@ struct MultiAccount
} }
}; };
} } // namespace Status::Onboarding

View File

@ -2,8 +2,8 @@
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
#include <QtCore>
#include <QStringLiteral> #include <QStringLiteral>
#include <QtCore>
namespace GoAccounts = Status::StatusGo::Accounts; namespace GoAccounts = Status::StatusGo::Accounts;
@ -18,7 +18,7 @@ namespace Fleet
inline const auto WakuV2Prod = u"wakuv2.prod"_qs; inline const auto WakuV2Prod = u"wakuv2.prod"_qs;
inline const auto WakuV2Test = u"wakuv2.test"_qs; inline const auto WakuV2Test = u"wakuv2.test"_qs;
inline const auto GoWakuTest = u"go-waku.test"_qs; inline const auto GoWakuTest = u"go-waku.test"_qs;
} } // namespace Fleet
namespace FleetNodes namespace FleetNodes
{ {
@ -29,7 +29,7 @@ namespace FleetNodes
inline const auto Waku = u"waku"_qs; inline const auto Waku = u"waku"_qs;
inline const auto LibP2P = u"libp2p"_qs; inline const auto LibP2P = u"libp2p"_qs;
inline const auto Websocket = u"websocket"_qs; inline const auto Websocket = u"websocket"_qs;
} } // namespace FleetNodes
namespace General namespace General
{ {
@ -46,7 +46,8 @@ namespace General
// EIP1581 Chat Key 0, the default whisper key // EIP1581 Chat Key 0, the default whisper key
inline const GoAccounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs}; inline const GoAccounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs};
inline const std::vector<GoAccounts::DerivationPath> AccountDefaultPaths {PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet}; inline const std::vector<GoAccounts::DerivationPath> AccountDefaultPaths{
} PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet};
} // namespace General
} } // namespace Status::Constants

View File

@ -29,4 +29,4 @@ public:
} }
}; };
} } // namespace Status

View File

@ -50,7 +50,6 @@ constexpr std::array SigningPhrases {
"veal", "veil", "vein", "vest", "vibe", "view", "vise", "wait", "wake", "walk", "wall", "wash", "wasp", "wave", "veal", "veil", "vein", "vest", "vibe", "view", "vise", "wait", "wake", "walk", "wall", "wash", "wasp", "wave",
"wear", "weed", "week", "well", "west", "whip", "wife", "will", "wind", "wine", "wing", "wire", "wish", "wolf", "wear", "weed", "week", "well", "west", "whip", "wife", "will", "wind", "wine", "wing", "wire", "wish", "wolf",
"wood", "wool", "word", "work", "worm", "wrap", "wren", "yard", "yarn", "yawl", "year", "yoga", "yoke", "yurt", "wood", "wool", "word", "work", "worm", "wrap", "wren", "yard", "yarn", "yawl", "year", "yoga", "yoke", "yurt",
"zinc", "zone" "zinc", "zone"};
};
} }

View File

@ -15,33 +15,36 @@ NewAccountController::NewAccountController(AccountsServiceInterfacePtr accountsS
: m_accountsService(accountsService) : m_accountsService(accountsService)
{ {
connect(this, &NewAccountController::passwordChanged, this, &NewAccountController::checkAndUpdateDataValidity); connect(this, &NewAccountController::passwordChanged, this, &NewAccountController::checkAndUpdateDataValidity);
connect(this, &NewAccountController::confirmationPasswordChanged, this, &NewAccountController::checkAndUpdateDataValidity); connect(this,
&NewAccountController::confirmationPasswordChanged,
this,
&NewAccountController::checkAndUpdateDataValidity);
connect(this, &NewAccountController::nameChanged, this, &NewAccountController::checkAndUpdateDataValidity); connect(this, &NewAccountController::nameChanged, this, &NewAccountController::checkAndUpdateDataValidity);
} }
void NewAccountController::createAccount() void NewAccountController::createAccount()
{ {
// TODO: fix this after moving SingalManager to StatusGo wrapper lib // TODO: fix this after moving SingalManager to StatusGo wrapper lib
QObject::connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &NewAccountController::onNodeLogin); QObject::connect(StatusGo::SignalsManager::instance(),
&StatusGo::SignalsManager::nodeLogin,
this,
&NewAccountController::onNodeLogin);
auto setupAccountFn = [this]() { auto setupAccountFn = [this]() {
if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid) { if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid)
{
auto genAccounts = m_accountsService->generatedAccounts(); auto genAccounts = m_accountsService->generatedAccounts();
if(genAccounts.size() > 0) { if(genAccounts.size() > 0)
if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name)) {
return; if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name)) return;
} }
} }
}; };
// TODO: refactor StatusGo wrapper to work with futures instead of SignalManager // TODO: refactor StatusGo wrapper to work with futures instead of SignalManager
m_createAccountFuture = QtConcurrent::run(setupAccountFn) m_createAccountFuture = QtConcurrent::run(setupAccountFn)
.then([] { /*Nothing, we expect status-go events*/ }) .then([] { /*Nothing, we expect status-go events*/ })
.onFailed([this] { .onFailed([this] { emit accountCreationError(); })
emit accountCreationError(); .onCanceled([this] { emit accountCreationError(); });
})
.onCanceled([this] {
emit accountCreationError();
});
} }
const QString& NewAccountController::password() const const QString& NewAccountController::password() const
@ -51,8 +54,7 @@ const QString &NewAccountController::password() const
void NewAccountController::setPassword(const QString& newPassword) void NewAccountController::setPassword(const QString& newPassword)
{ {
if (m_password == newPassword) if(m_password == newPassword) return;
return;
m_password = newPassword; m_password = newPassword;
emit passwordChanged(); emit passwordChanged();
} }
@ -64,8 +66,7 @@ const QString &NewAccountController::confirmationPassword() const
void NewAccountController::setConfirmationPassword(const QString& newConfirmationPassword) void NewAccountController::setConfirmationPassword(const QString& newConfirmationPassword)
{ {
if (m_confirmationPassword == newConfirmationPassword) if(m_confirmationPassword == newConfirmationPassword) return;
return;
m_confirmationPassword = newConfirmationPassword; m_confirmationPassword = newConfirmationPassword;
emit confirmationPasswordChanged(); emit confirmationPasswordChanged();
} }
@ -77,8 +78,7 @@ const QString &NewAccountController::name() const
void NewAccountController::setName(const QString& newName) void NewAccountController::setName(const QString& newName)
{ {
if (m_name == newName) if(m_name == newName) return;
return;
m_name = newName; m_name = newName;
emit nameChanged(); emit nameChanged();
} }
@ -109,19 +109,22 @@ void NewAccountController::onNodeLogin(const QString& error)
void NewAccountController::checkAndUpdateDataValidity() void NewAccountController::checkAndUpdateDataValidity()
{ {
auto passwordValid = m_password.length() >= 6; auto passwordValid = m_password.length() >= 6;
if(passwordValid != m_passwordIsValid) { if(passwordValid != m_passwordIsValid)
{
m_passwordIsValid = passwordValid; m_passwordIsValid = passwordValid;
emit passwordIsValidChanged(); emit passwordIsValidChanged();
} }
auto confirmationPasswordValid = m_password == m_confirmationPassword; auto confirmationPasswordValid = m_password == m_confirmationPassword;
if(confirmationPasswordValid != m_confirmationPasswordIsValid) { if(confirmationPasswordValid != m_confirmationPasswordIsValid)
{
m_confirmationPasswordIsValid = confirmationPasswordValid; m_confirmationPasswordIsValid = confirmationPasswordValid;
emit confirmationPasswordIsValidChanged(); emit confirmationPasswordIsValidChanged();
} }
auto nameValid = m_name.length() >= 10; auto nameValid = m_name.length() >= 10;
if(nameValid != m_nameIsValid) { if(nameValid != m_nameIsValid)
{
m_nameIsValid = nameValid; m_nameIsValid = nameValid;
emit nameIsValidChanged(); emit nameIsValidChanged();
} }

View File

@ -28,10 +28,12 @@ class NewAccountController: public QObject
QML_UNCREATABLE("Created and owned externally") QML_UNCREATABLE("Created and owned externally")
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
Q_PROPERTY(QString confirmationPassword READ confirmationPassword WRITE setConfirmationPassword NOTIFY confirmationPasswordChanged) Q_PROPERTY(QString confirmationPassword READ confirmationPassword WRITE setConfirmationPassword NOTIFY
confirmationPasswordChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool passwordIsValid READ passwordIsValid NOTIFY passwordIsValidChanged) Q_PROPERTY(bool passwordIsValid READ passwordIsValid NOTIFY passwordIsValidChanged)
Q_PROPERTY(bool confirmationPasswordIsValid READ confirmationPasswordIsValid NOTIFY confirmationPasswordIsValidChanged) Q_PROPERTY(
bool confirmationPasswordIsValid READ confirmationPasswordIsValid NOTIFY confirmationPasswordIsValidChanged)
Q_PROPERTY(bool nameIsValid READ nameIsValid NOTIFY nameIsValidChanged) Q_PROPERTY(bool nameIsValid READ nameIsValid NOTIFY nameIsValidChanged)
public: public:

View File

@ -8,7 +8,8 @@
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
namespace Status::Onboarding { namespace Status::Onboarding
{
namespace StatusGo = Status::StatusGo; namespace StatusGo = Status::StatusGo;
@ -18,13 +19,18 @@ OnboardingController::OnboardingController(AccountsServiceInterfacePtr accountsS
{ {
{ // Init accounts { // Init accounts
std::vector<std::shared_ptr<UserAccount>> accounts; std::vector<std::shared_ptr<UserAccount>> accounts;
for(auto &account : getOpenedAccounts()) { for(auto& account : getOpenedAccounts())
accounts.push_back(Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account)))); {
accounts.push_back(
Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
} }
m_accounts = Helpers::makeSharedQObject<UserAccountsModel>(std::move(accounts)); m_accounts = Helpers::makeSharedQObject<UserAccountsModel>(std::move(accounts));
} }
connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &OnboardingController::onLogin); connect(StatusGo::SignalsManager::instance(),
&StatusGo::SignalsManager::nodeLogin,
this,
&OnboardingController::onLogin);
} }
OnboardingController::~OnboardingController() OnboardingController::~OnboardingController()
@ -50,8 +56,7 @@ void OnboardingController::login(QObject* user, const QString& password)
auto account = qobject_cast<UserAccount*>(user); auto account = qobject_cast<UserAccount*>(user);
assert(account != nullptr); assert(account != nullptr);
auto error = m_accountsService->login(account->accountData(), password); auto error = m_accountsService->login(account->accountData(), password);
if(!error.isEmpty()) if(!error.isEmpty()) emit accountLoginError(error);
emit accountLoginError(error);
} }
UserAccountsModel* OnboardingController::accounts() const UserAccountsModel* OnboardingController::accounts() const
@ -82,4 +87,4 @@ AccountsServiceInterfacePtr OnboardingController::accountsService() const
return m_accountsService; return m_accountsService;
} }
} } // namespace Status::Onboarding

View File

@ -22,8 +22,7 @@ class NewAccountController;
* \todo don't use DTOs in controllers, use QObjects directly * \todo don't use DTOs in controllers, use QObjects directly
* \todo make dependency on SignalManager explicit. Now it is hidden. * \todo make dependency on SignalManager explicit. Now it is hidden.
*/ */
class OnboardingController final : public QObject class OnboardingController final : public QObject, public std::enable_shared_from_this<OnboardingController>
, public std::enable_shared_from_this<OnboardingController>
{ {
Q_OBJECT Q_OBJECT
@ -72,4 +71,4 @@ private:
std::unique_ptr<NewAccountController> m_newAccountController; std::unique_ptr<NewAccountController> m_newAccountController;
}; };
} } // namespace Status::Onboarding

View File

@ -10,7 +10,8 @@ namespace AppCore = Status::ApplicationCore;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Onboarding { namespace Status::Onboarding
{
OnboardingModule::OnboardingModule(const fs::path& userDataPath, QObject* parent) OnboardingModule::OnboardingModule(const fs::path& userDataPath, QObject* parent)
: OnboardingModule{parent} : OnboardingModule{parent}
@ -22,8 +23,7 @@ OnboardingModule::OnboardingModule(const fs::path& userDataPath, QObject *parent
OnboardingModule::OnboardingModule(QObject* parent) OnboardingModule::OnboardingModule(QObject* parent)
: QObject{parent} : QObject{parent}
, m_accountsService(std::make_shared<AccountsService>()) , m_accountsService(std::make_shared<AccountsService>())
{ { }
}
OnboardingController* OnboardingModule::controller() const OnboardingController* OnboardingModule::controller() const
{ {
@ -32,9 +32,12 @@ OnboardingController* OnboardingModule::controller() const
void OnboardingModule::componentComplete() void OnboardingModule::componentComplete()
{ {
try { try
{
initWithUserDataPath(m_userDataPath); initWithUserDataPath(m_userDataPath);
} catch(const std::exception &e) { }
catch(const std::exception& e)
{
qCritical() << "OnboardingModule: failed to initialize"; qCritical() << "OnboardingModule: failed to initialize";
} }
} }
@ -42,10 +45,8 @@ void OnboardingModule::componentComplete()
void OnboardingModule::initWithUserDataPath(const fs::path& path) void OnboardingModule::initWithUserDataPath(const fs::path& path)
{ {
auto result = m_accountsService->init(path); auto result = m_accountsService->init(path);
if(!result) if(!result) throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string()); m_controller = Helpers::makeSharedQObject<OnboardingController>(m_accountsService);
m_controller = Helpers::makeSharedQObject<OnboardingController>(
m_accountsService);
emit controllerChanged(); emit controllerChanged();
} }
@ -57,10 +58,9 @@ const QString OnboardingModule::userDataPath() const
void OnboardingModule::setUserDataPath(const QString& newUserDataPath) void OnboardingModule::setUserDataPath(const QString& newUserDataPath)
{ {
auto newVal = newUserDataPath.toStdString(); auto newVal = newUserDataPath.toStdString();
if (m_userDataPath.compare(newVal) == 0) if(m_userDataPath.compare(newVal) == 0) return;
return;
m_userDataPath = newVal; m_userDataPath = newVal;
emit userDataPathChanged(); emit userDataPathChanged();
} }
} } // namespace Status::Onboarding

View File

@ -9,7 +9,8 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Onboarding { namespace Status::Onboarding
{
class AccountsService; class AccountsService;
@ -48,7 +49,6 @@ signals:
void userDataPathChanged(); void userDataPathChanged();
private: private:
/// Throws exceptions /// Throws exceptions
void initWithUserDataPath(const fs::path& path); void initWithUserDataPath(const fs::path& path);
@ -59,4 +59,4 @@ private:
fs::path m_userDataPath; fs::path m_userDataPath;
}; };
} } // namespace Status::Onboarding

View File

@ -8,8 +8,7 @@ namespace Status::Onboarding
UserAccount::UserAccount(std::unique_ptr<MultiAccount> data) UserAccount::UserAccount(std::unique_ptr<MultiAccount> data)
: QObject() : QObject()
, m_data(std::move(data)) , m_data(std::move(data))
{ { }
}
const QString& UserAccount::name() const const QString& UserAccount::name() const
{ {
@ -27,9 +26,7 @@ void UserAccount::updateAccountData(const MultiAccount& newData)
*m_data = newData; *m_data = newData;
if(newData.name != m_data->name) if(newData.name != m_data->name) notifyUpdates.push_back([this]() { emit nameChanged(); });
notifyUpdates.push_back([this]() { emit nameChanged(); });
} }
} } // namespace Status::Onboarding

View File

@ -35,4 +35,4 @@ private:
std::unique_ptr<MultiAccount> m_data; std::unique_ptr<MultiAccount> m_data;
}; };
} } // namespace Status::Onboarding

View File

@ -2,25 +2,19 @@
#include <QObject> #include <QObject>
namespace Status::Onboarding { namespace Status::Onboarding
{
UserAccountsModel::UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent) UserAccountsModel::UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_accounts(std::move(accounts)) , m_accounts(std::move(accounts))
{ { }
}
UserAccountsModel::~UserAccountsModel() UserAccountsModel::~UserAccountsModel() { }
{
}
QHash<int, QByteArray> UserAccountsModel::roleNames() const QHash<int, QByteArray> UserAccountsModel::roleNames() const
{ {
static QHash<int, QByteArray> roles{ static QHash<int, QByteArray> roles{{Name, "name"}, {Account, "account"}};
{Name, "name"},
{Account, "account"}
};
return roles; return roles;
} }
@ -32,14 +26,14 @@ int UserAccountsModel::rowCount(const QModelIndex& parent) const
QVariant UserAccountsModel::data(const QModelIndex& index, int role) const QVariant UserAccountsModel::data(const QModelIndex& index, int role) const
{ {
if(!QAbstractItemModel::checkIndex(index)) if(!QAbstractItemModel::checkIndex(index)) return QVariant();
return QVariant();
switch(static_cast<ModelRole>(role)) { switch(static_cast<ModelRole>(role))
{
case Name: return QVariant::fromValue(m_accounts[index.row()].get()->name()); case Name: return QVariant::fromValue(m_accounts[index.row()].get()->name());
case Account: return QVariant::fromValue<QObject*>(m_accounts[index.row()].get()); case Account: return QVariant::fromValue<QObject*>(m_accounts[index.row()].get());
default: return QVariant(); default: return QVariant();
} }
} }
} } // namespace Status::Onboarding

View File

@ -4,7 +4,8 @@
#include <QAbstractListModel> #include <QAbstractListModel>
namespace Status::Onboarding { namespace Status::Onboarding
{
/// \todo Replace it with \c QObjectVectorModel /// \todo Replace it with \c QObjectVectorModel
class UserAccountsModel : public QAbstractListModel class UserAccountsModel : public QAbstractListModel
@ -14,12 +15,13 @@ class UserAccountsModel : public QAbstractListModel
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("Created by OnboardingController") QML_UNCREATABLE("Created by OnboardingController")
enum ModelRole { enum ModelRole
{
Name = Qt::UserRole + 1, Name = Qt::UserRole + 1,
Account Account
}; };
public:
public:
explicit UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent = nullptr); explicit UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent = nullptr);
~UserAccountsModel(); ~UserAccountsModel();
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
@ -30,4 +32,4 @@ private:
const std::vector<std::shared_ptr<UserAccount>> m_accounts; const std::vector<std::shared_ptr<UserAccount>> m_accounts;
}; };
} } // namespace Status::Onboarding

View File

@ -2,7 +2,8 @@
#include <string> #include <string>
namespace Status::Testing::Constants { namespace Status::Testing::Constants
{
inline constexpr auto userDataDirName = "StatusTest"; inline constexpr auto userDataDirName = "StatusTest";
inline constexpr auto statusGoDataDirName = "data"; inline constexpr auto statusGoDataDirName = "data";
@ -12,4 +13,4 @@ inline constexpr auto qtDataDirName = "qt";
inline constexpr auto keystoreDataDirName = "keystore"; inline constexpr auto keystoreDataDirName = "keystore";
inline constexpr auto globalSettingsFileName = "global"; inline constexpr auto globalSettingsFileName = "global";
} } // namespace Status::Testing::Constants

View File

@ -20,7 +20,8 @@ namespace Accounts = Status::StatusGo::Accounts;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
ScopedTestAccount::ScopedTestAccount(const std::string& tempTestSubfolderName, ScopedTestAccount::ScopedTestAccount(const std::string& tempTestSubfolderName,
const QString& accountName, const QString& accountName,
@ -41,7 +42,9 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
auto accountsService = std::make_shared<Onboarding::AccountsService>(); auto accountsService = std::make_shared<Onboarding::AccountsService>();
auto result = accountsService->init(m_testFolderPath); auto result = accountsService->init(m_testFolderPath);
if(!result) if(!result)
{
throw std::runtime_error("ScopedTestAccount - Failed to create temporary test account"); throw std::runtime_error("ScopedTestAccount - Failed to create temporary test account");
}
// TODO refactor and merge account creation events with login into Onboarding controller // TODO refactor and merge account creation events with login into Onboarding controller
// //
@ -51,42 +54,60 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
// Beware, smartpointer is a requirement // Beware, smartpointer is a requirement
m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService); m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService);
if(m_onboarding->getOpenedAccounts().size() != 0) if(m_onboarding->getOpenedAccounts().size() != 0)
{
throw std::runtime_error("ScopedTestAccount - already have opened account"); throw std::runtime_error("ScopedTestAccount - already have opened account");
}
int accountLoggedInCount = 0; int accountLoggedInCount = 0;
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() { QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() {
accountLoggedInCount++; accountLoggedInCount++;
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoginError, [&accountLoggedInError]() { QObject::connect(m_onboarding.get(),
accountLoggedInError = true; &Onboarding::OnboardingController::accountLoginError,
}); [&accountLoggedInError]() { accountLoggedInError = true; });
// Create Accounts // Create Accounts
auto genAccounts = accountsService->generatedAccounts(); auto genAccounts = accountsService->generatedAccounts();
if(genAccounts.size() == 0) if(genAccounts.size() == 0)
{
throw std::runtime_error("ScopedTestAccount - missing generated accounts"); throw std::runtime_error("ScopedTestAccount - missing generated accounts");
}
if(accountsService->isFirstTimeAccountLogin()) if(accountsService->isFirstTimeAccountLogin())
{
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned true"); throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned true");
}
if(!accountsService->setupAccountAndLogin(genAccounts[0].id, m_accountPassword, m_accountName)) if(!accountsService->setupAccountAndLogin(genAccounts[0].id, m_accountPassword, m_accountName))
{
throw std::runtime_error("ScopedTestAccount - Service::setupAccountAndLogin failed"); throw std::runtime_error("ScopedTestAccount - Service::setupAccountAndLogin failed");
}
if(!accountsService->isFirstTimeAccountLogin()) if(!accountsService->isFirstTimeAccountLogin())
{
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned false"); throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned false");
}
if(!accountsService->getLoggedInAccount().isValid()) if(!accountsService->getLoggedInAccount().isValid())
{
throw std::runtime_error("ScopedTestAccount - newly created account is not valid"); throw std::runtime_error("ScopedTestAccount - newly created account is not valid");
}
if(accountsService->getLoggedInAccount().name != accountName) if(accountsService->getLoggedInAccount().name != accountName)
{
throw std::runtime_error("ScopedTestAccount - newly created account has a wrong name"); throw std::runtime_error("ScopedTestAccount - newly created account has a wrong name");
processMessages(2000, [accountLoggedInCount]() { }
return accountLoggedInCount == 0;
}); processMessages(2000, [accountLoggedInCount]() { return accountLoggedInCount == 0; });
if(accountLoggedInCount != 1) if(accountLoggedInCount != 1)
{
throw std::runtime_error("ScopedTestAccount - missing confirmation of account creation"); throw std::runtime_error("ScopedTestAccount - missing confirmation of account creation");
}
if(accountLoggedInError) if(accountLoggedInError)
{
throw std::runtime_error("ScopedTestAccount - account loggedin error"); throw std::runtime_error("ScopedTestAccount - account loggedin error");
} }
}
ScopedTestAccount::~ScopedTestAccount() ScopedTestAccount::~ScopedTestAccount()
{ {
@ -94,12 +115,14 @@ ScopedTestAccount::~ScopedTestAccount()
m_onboarding->accountsService()->deleteMultiAccount(rootAccount); m_onboarding->accountsService()->deleteMultiAccount(rootAccount);
} }
void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<bool()> shouldWaitUntilTimeout) { void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<bool()> shouldWaitUntilTimeout)
{
using namespace std::chrono_literals; using namespace std::chrono_literals;
std::chrono::milliseconds maxWaitTime{maxWaitTimeMillis}; std::chrono::milliseconds maxWaitTime{maxWaitTimeMillis};
auto iterationSleepTime = 2ms; auto iterationSleepTime = 2ms;
auto remainingIterations = maxWaitTime / iterationSleepTime; auto remainingIterations = maxWaitTime / iterationSleepTime;
while (remainingIterations-- > 0 && shouldWaitUntilTimeout()) { while(remainingIterations-- > 0 && shouldWaitUntilTimeout())
{
std::this_thread::sleep_for(iterationSleepTime); std::this_thread::sleep_for(iterationSleepTime);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
@ -109,28 +132,30 @@ void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<
void ScopedTestAccount::logOut() void ScopedTestAccount::logOut()
{ {
if(Status::StatusGo::Accounts::logout().containsError()) if(Status::StatusGo::Accounts::logout().containsError())
{
throw std::runtime_error("ScopedTestAccount - failed logging out"); throw std::runtime_error("ScopedTestAccount - failed logging out");
} }
}
Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount() Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount()
{ {
auto accounts = Accounts::getAccounts(); auto accounts = Accounts::getAccounts();
auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isChat; });
return a.isChat;
});
if(chatIt == accounts.end()) if(chatIt == accounts.end())
{
throw std::runtime_error("ScopedTestAccount::chatAccount: account not found"); throw std::runtime_error("ScopedTestAccount::chatAccount: account not found");
}
return *chatIt; return *chatIt;
} }
Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount() Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount()
{ {
auto accounts = Accounts::getAccounts(); auto accounts = Accounts::getAccounts();
auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isWallet; });
return a.isWallet;
});
if(walletIt == accounts.end()) if(walletIt == accounts.end())
{
throw std::runtime_error("ScopedTestAccount::firstWalletAccount: account not found"); throw std::runtime_error("ScopedTestAccount::firstWalletAccount: account not found");
}
return *walletIt; return *walletIt;
} }
@ -149,4 +174,4 @@ const std::filesystem::path &ScopedTestAccount::fusedTestFolder() const
return m_testFolderPath; return m_testFolderPath;
} }
} } // namespace Status::Testing

View File

@ -4,27 +4,30 @@
#include <StatusGo/Utils.h> #include <StatusGo/Utils.h>
#include <string>
#include <filesystem> #include <filesystem>
#include <string>
#include <QString> #include <QString>
class QCoreApplication; class QCoreApplication;
namespace Status::Onboarding { namespace Status::Onboarding
{
class OnboardingController; class OnboardingController;
class MultiAccount; class MultiAccount;
} } // namespace Status::Onboarding
namespace Wallet = Status::StatusGo::Wallet; namespace Wallet = Status::StatusGo::Wallet;
namespace Accounts = Status::StatusGo::Accounts; namespace Accounts = Status::StatusGo::Accounts;
namespace GoUtils = Status::StatusGo::Utils; namespace GoUtils = Status::StatusGo::Utils;
namespace Status::Testing { namespace Status::Testing
{
class AutoCleanTempTestDir; class AutoCleanTempTestDir;
class ScopedTestAccount final { class ScopedTestAccount final
{
public: public:
/*! /*!
* \brief Create and logs in a new test account * \brief Create and logs in a new test account
@ -44,8 +47,14 @@ public:
/// Root account /// Root account
const Status::Onboarding::MultiAccount& loggedInAccount() const; const Status::Onboarding::MultiAccount& loggedInAccount() const;
QString password() const { return m_accountPassword; }; QString password() const
StatusGo::HashedPassword hashedPassword() const { return GoUtils::hashPassword(m_accountPassword); }; {
return m_accountPassword;
};
StatusGo::HashedPassword hashedPassword() const
{
return GoUtils::hashPassword(m_accountPassword);
};
Status::Onboarding::OnboardingController* onboardingController() const; Status::Onboarding::OnboardingController* onboardingController() const;
@ -65,4 +74,4 @@ private:
static constexpr auto defaultAccountPassword = "test_pwd*"; static constexpr auto defaultAccountPassword = "test_pwd*";
}; };
} } // namespace Status::Testing

View File

@ -34,4 +34,4 @@ public:
MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override)); MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override));
}; };
} } // namespace Status::Testing

View File

@ -1,7 +1,7 @@
#include "ServiceMock.h" #include "ServiceMock.h"
#include <IOTestHelpers.h>
#include <Constants.h> #include <Constants.h>
#include <IOTestHelpers.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
@ -15,7 +15,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
class AccountsService : public ::testing::Test class AccountsService : public ::testing::Test
{ {
@ -23,19 +24,20 @@ protected:
std::unique_ptr<Onboarding::AccountsService> m_accountsService; std::unique_ptr<Onboarding::AccountsService> m_accountsService;
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder; std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
void SetUp() override { void SetUp() override
{
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("TestAccountsService"); m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("TestAccountsService");
m_accountsService = std::make_unique<Onboarding::AccountsService>(); m_accountsService = std::make_unique<Onboarding::AccountsService>();
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName); m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
} }
void TearDown() override { void TearDown() override
{
m_fusedTestFolder.reset(); m_fusedTestFolder.reset();
m_accountsService.reset(); m_accountsService.reset();
} }
}; };
TEST_F(AccountsService, GeneratedAccounts) TEST_F(AccountsService, GeneratedAccounts)
{ {
auto genAccounts = m_accountsService->generatedAccounts(); auto genAccounts = m_accountsService->generatedAccounts();
@ -51,13 +53,16 @@ TEST_F(AccountsService, GeneratedAccounts)
} }
} }
TEST_F(AccountsService, DISABLED_GenerateAlias) // temporary disabled till we see what's happening on the status-go side since it doesn't return aliases for any pk TEST_F(
AccountsService,
DISABLED_GenerateAlias) // temporary disabled till we see what's happening on the status-go side since it doesn't return aliases for any pk
{ {
QString testPubKey = "0x04487f44bac3e90825bfa9720148308cb64835bebb7e888f519cebc127223187067629f8b70d0661a35d4af6516b225286"; QString testPubKey =
"0x04487f44bac3e90825bfa9720148308cb64835bebb7e888f519cebc127223187067629f8b70d0661a35d4af6516b225286";
auto alias = m_accountsService->generateAlias(testPubKey); auto alias = m_accountsService->generateAlias(testPubKey);
ASSERT_NE(alias, QString("")); ASSERT_NE(alias, QString(""));
} }
} // namespace } // namespace Status::Testing

View File

@ -17,7 +17,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
class LoginTest : public ::testing::Test class LoginTest : public ::testing::Test
{ {
@ -27,20 +28,24 @@ protected:
std::unique_ptr<Onboarding::AccountsService> m_accountsService; std::unique_ptr<Onboarding::AccountsService> m_accountsService;
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder; std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
static void SetUpTestSuite() { static void SetUpTestSuite()
{
m_accountsServiceMock = std::make_shared<AccountsServiceMock>(); m_accountsServiceMock = std::make_shared<AccountsServiceMock>();
} }
static void TearDownTestSuite() { static void TearDownTestSuite()
{
m_accountsServiceMock.reset(); m_accountsServiceMock.reset();
} }
void SetUp() override { void SetUp() override
{
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("LoginTest"); m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("LoginTest");
m_accountsService = std::make_unique<Onboarding::AccountsService>(); m_accountsService = std::make_unique<Onboarding::AccountsService>();
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName); m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
} }
void TearDown() override { void TearDown() override
{
m_fusedTestFolder.release(); m_fusedTestFolder.release();
m_accountsService.release(); m_accountsService.release();
} }
@ -54,4 +59,4 @@ TEST_F(LoginTest, DISABLED_TestLoginController)
auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock); auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock);
} }
} // namespace } // namespace Status::Testing

View File

@ -7,8 +7,8 @@
#include <Onboarding/Accounts/AccountsService.h> #include <Onboarding/Accounts/AccountsService.h>
#include <Onboarding/OnboardingController.h> #include <Onboarding/OnboardingController.h>
#include <StatusGo/SignalsManager.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/SignalsManager.h>
#include <ScopedTestAccount.h> #include <ScopedTestAccount.h>
@ -21,7 +21,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
static std::unique_ptr<Onboarding::AccountsService> m_accountsServiceMock; static std::unique_ptr<Onboarding::AccountsService> m_accountsServiceMock;
@ -90,7 +91,8 @@ TEST(OnboardingModule, TestCreateAndLoginAccountEndToEnd)
auto maxWaitTime = 2000ms; auto maxWaitTime = 2000ms;
auto iterationSleepTime = 2ms; auto iterationSleepTime = 2ms;
auto remainingIterations = maxWaitTime / iterationSleepTime; auto remainingIterations = maxWaitTime / iterationSleepTime;
while (remainingIterations-- > 0 && accountLoggedInCount == 0) { while(remainingIterations-- > 0 && accountLoggedInCount == 0)
{
std::this_thread::sleep_for(iterationSleepTime); std::this_thread::sleep_for(iterationSleepTime);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
@ -110,20 +112,23 @@ TEST(OnboardingModule, TestLoginEndToEnd)
// Create test account and login // Create test account and login
// //
bool createAndLogin = false; bool createAndLogin = false;
QObject::connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, [&createAndLogin](const QString& error) { QObject::connect(StatusGo::SignalsManager::instance(),
if(error.isEmpty()) { &StatusGo::SignalsManager::nodeLogin,
if(createAndLogin) { [&createAndLogin](const QString& error) {
if(error.isEmpty())
{
if(createAndLogin)
{
createAndLogin = false; createAndLogin = false;
} else }
else
createAndLogin = true; createAndLogin = true;
} }
}); });
constexpr auto accountName = "TestLoginAccountName"; constexpr auto accountName = "TestLoginAccountName";
ScopedTestAccount testAccount(test_info_->name(), accountName); ScopedTestAccount testAccount(test_info_->name(), accountName);
testAccount.processMessages(1000, [createAndLogin]() { testAccount.processMessages(1000, [createAndLogin]() { return !createAndLogin; });
return !createAndLogin;
});
ASSERT_TRUE(createAndLogin); ASSERT_TRUE(createAndLogin);
testAccount.logOut(); testAccount.logOut();
@ -148,14 +153,15 @@ TEST(OnboardingModule, TestLoginEndToEnd)
accountLoggedInCount++; accountLoggedInCount++;
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError, QObject::connect(onboarding.get(),
&Onboarding::OnboardingController::accountLoginError,
[&accountLoggedInError](const QString& error) { [&accountLoggedInError](const QString& error) {
accountLoggedInError = true; accountLoggedInError = true;
qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error; qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error;
} });
);
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [accountName](const auto &a) { return a.name == accountName; }); auto ourAccountRes =
std::find_if(accounts.begin(), accounts.end(), [accountName](const auto& a) { return a.name == accountName; });
auto errorString = accountsService->login(*ourAccountRes, testAccount.password()); auto errorString = accountsService->login(*ourAccountRes, testAccount.password());
ASSERT_EQ(errorString.length(), 0); ASSERT_EQ(errorString.length(), 0);
@ -186,13 +192,16 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QString loginErrorMessage; QString loginErrorMessage;
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError, QObject::connect(onboarding.get(),
&Onboarding::OnboardingController::accountLoginError,
[&loginErrorMessage, &accountLoggedInError](const QString& error) { [&loginErrorMessage, &accountLoggedInError](const QString& error) {
accountLoggedInError = true; accountLoggedInError = true;
loginErrorMessage = error; loginErrorMessage = error;
}); });
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [testRootAccountName](const auto &a) { return a.name == testRootAccountName; }); auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [testRootAccountName](const auto& a) {
return a.name == testRootAccountName;
});
auto errorString = accountsService->login(*ourAccountRes, testAccount.password() + "extra"); auto errorString = accountsService->login(*ourAccountRes, testAccount.password() + "extra");
ASSERT_EQ(errorString.length(), 0); ASSERT_EQ(errorString.length(), 0);
@ -204,4 +213,4 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
ASSERT_EQ(loginErrorMessage, "file is not a database"); ASSERT_EQ(loginErrorMessage, "file is not a database");
} }
} // namespace } // namespace Status::Testing

View File

@ -7,16 +7,15 @@
const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5; const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5;
const int MNEMONIC_PHRASE_LENGTH = 12; const int MNEMONIC_PHRASE_LENGTH = 12;
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths) RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths)
{ {
QJsonObject payload{ QJsonObject payload{{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
{"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH}, {"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH},
{"bip32Passphrase", ""}, {"bip32Passphrase", ""},
{"paths", Utils::toJsonArray(paths)} {"paths", Utils::toJsonArray(paths)}};
};
try try
{ {
@ -64,13 +63,11 @@ RpcResponse<QString> generateAlias(const QString& publicKey)
} }
} }
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPassword& password, const std::vector<Accounts::DerivationPath>& paths) RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id,
const HashedPassword& password,
const std::vector<Accounts::DerivationPath>& paths)
{ {
QJsonObject payload{ QJsonObject payload{{"accountID", id}, {"paths", Utils::toJsonArray(paths)}, {"password", password.get()}};
{"accountID", id},
{"paths", Utils::toJsonArray(paths)},
{"password", password.get()}
};
try try
{ {
@ -102,10 +99,7 @@ RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPas
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password) RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password)
{ {
QJsonObject payload{ QJsonObject payload{{"accountID", id}, {"password", password.get()}};
{"accountID", id},
{"password", password.get()}
};
try try
{ {
@ -135,8 +129,10 @@ RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& p
} }
} }
bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& account, bool saveAccountAndLogin(const HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& nodeConfig) const QJsonObject& nodeConfig)
{ {
try try
@ -154,9 +150,13 @@ bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& acco
} }
return !Utils::getRPCErrorInJson(jsonResult).has_value(); return !Utils::getRPCErrorInJson(jsonResult).has_value();
} catch (std::exception& e) { }
catch(std::exception& e)
{
qWarning() << QString("an error saving account and login occurred, msg: %1").arg(e.what()); qWarning() << QString("an error saving account and login occurred, msg: %1").arg(e.what());
} catch (...) { }
catch(...)
{
qWarning() << "an error saving account and login occurred"; qWarning() << "an error saving account and login occurred";
} }
return false; return false;
@ -167,11 +167,11 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
try try
{ {
auto result = QString(OpenAccounts(const_cast<char*>(dataDirPath))); auto result = QString(OpenAccounts(const_cast<char*>(dataDirPath)));
if(result == "null") if(result == "null") return RpcResponse<QJsonArray>(QJsonArray());
return RpcResponse<QJsonArray>(QJsonArray());
QJsonArray jsonResult; QJsonArray jsonResult;
if(!Utils::checkReceivedResponse(result, jsonResult)) { if(!Utils::checkReceivedResponse(result, jsonResult))
{
throw std::domain_error("parsing response failed"); throw std::domain_error("parsing response failed");
} }
@ -192,14 +192,13 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
} }
} }
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password, RpcResponse<QJsonObject> login(const QString& name,
const QString& thumbnail, const QString& large) const QString& keyUid,
const HashedPassword& password,
const QString& thumbnail,
const QString& large)
{ {
QJsonObject payload{ QJsonObject payload{{"name", name}, {"key-uid", keyUid}, {"identityImage", QJsonValue()}};
{"name", name},
{"key-uid", keyUid},
{"identityImage", QJsonValue()}
};
if(!thumbnail.isEmpty() && !large.isEmpty()) if(!thumbnail.isEmpty() && !large.isEmpty())
{ {
@ -233,8 +232,12 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
} }
} }
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password, RpcResponse<QJsonObject> loginWithConfig(const QString& name,
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig) const QString& keyUid,
const HashedPassword& password,
const QString& thumbnail,
const QString& large,
const QJsonObject& nodeConfig)
{ {
QJsonObject payload{ QJsonObject payload{
{"name", name}, {"name", name},
@ -305,4 +308,4 @@ RpcResponse<QJsonObject> logout()
} }
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -11,21 +11,31 @@ namespace Status::StatusGo::Accounts
RpcResponse<QString> generateAlias(const QString& publicKey); RpcResponse<QString> generateAlias(const QString& publicKey);
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId, const HashedPassword& password, RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId,
const HashedPassword& password,
const std::vector<Accounts::DerivationPath>& paths); const std::vector<Accounts::DerivationPath>& paths);
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password); RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password);
bool saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account, bool saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& nodeConfig); const QJsonObject& nodeConfig);
/// opens database and returns accounts list. /// opens database and returns accounts list.
RpcResponse<QJsonArray> openAccounts(const char* dataDirPath); RpcResponse<QJsonArray> openAccounts(const char* dataDirPath);
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password, RpcResponse<QJsonObject> login(const QString& name,
const QString& thumbnail, const QString& large); const QString& keyUid,
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password, const HashedPassword& password,
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig); const QString& thumbnail,
const QString& large);
RpcResponse<QJsonObject> loginWithConfig(const QString& name,
const QString& keyUid,
const HashedPassword& password,
const QString& thumbnail,
const QString& large,
const QJsonObject& nodeConfig);
RpcResponse<QJsonObject> logout(); RpcResponse<QJsonObject> logout();
} } // namespace Status::StatusGo::Accounts

View File

@ -1,7 +1,7 @@
#include "AccountsAPI.h" #include "AccountsAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -14,13 +14,10 @@ using json = nlohmann::json;
namespace Status::StatusGo::Accounts namespace Status::StatusGo::Accounts
{ {
Accounts::ChatOrWalletAccounts getAccounts() { Accounts::ChatOrWalletAccounts getAccounts()
{
// or even nicer with a raw string literal // or even nicer with a raw string literal
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_getAccounts"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "accounts_getAccounts"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -29,31 +26,30 @@ Accounts::ChatOrWalletAccounts getAccounts() {
return resultJson.get<CallPrivateRpcResponse>().result; return resultJson.get<CallPrivateRpcResponse>().result;
} }
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, const QColor &color, const QString &emoji, void generateAccountWithDerivedPath(const HashedPassword& password,
const DerivationPath &path, const EOAddress &derivedFrom) const QString& name,
const QColor& color,
const QString& emoji,
const DerivationPath& path,
const EOAddress& derivedFrom)
{ {
std::vector<json> params = {password, name, color, emoji, path, derivedFrom}; std::vector<json> params = {password, name, color, emoji, path, derivedFrom};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_generateAccountWithDerivedPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_generateAccountWithDerivedPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
} }
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name, void addAccountWithMnemonicAndPath(const QString& mnemonic,
const QColor &color, const QString &emoji, const DerivationPath &path) const HashedPassword& password,
const QString& name,
const QColor& color,
const QString& emoji,
const DerivationPath& path)
{ {
std::vector<json> params = {mnemonic, password, name, color, emoji, path}; std::vector<json> params = {mnemonic, password, name, color, emoji, path};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWithMnemonicAndPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_addAccountWithMnemonicAndPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -63,11 +59,7 @@ void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword
void addAccountWatch(const EOAddress& address, const QString& name, const QColor& color, const QString& emoji) void addAccountWatch(const EOAddress& address, const QString& name, const QColor& color, const QString& emoji)
{ {
std::vector<json> params = {address, name, color, emoji}; std::vector<json> params = {address, name, color, emoji};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWatch"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_addAccountWatch"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -77,11 +69,7 @@ void addAccountWatch(const EOAddress &address, const QString &name, const QColor
void deleteAccount(const EOAddress& address) void deleteAccount(const EOAddress& address)
{ {
std::vector<json> params = {address}; std::vector<json> params = {address};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_deleteAccount"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_deleteAccount"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -91,9 +79,10 @@ void deleteAccount(const EOAddress &address)
void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir) void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir)
{ {
// We know go bridge won't misbehave with the input arguments // We know go bridge won't misbehave with the input arguments
auto result = DeleteMultiaccount(const_cast<char*>(keyUID.toStdString().c_str()), const_cast<char*>(keyStoreDir.string().c_str())); auto result = DeleteMultiaccount(const_cast<char*>(keyUID.toStdString().c_str()),
const_cast<char*>(keyStoreDir.string().c_str()));
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkApiError(resultJson); checkApiError(resultJson);
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -5,8 +5,8 @@
#include "Accounts/ChatOrWalletAccount.h" #include "Accounts/ChatOrWalletAccount.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include <vector>
#include <filesystem> #include <filesystem>
#include <vector>
namespace Accounts = Status::StatusGo::Accounts; namespace Accounts = Status::StatusGo::Accounts;
@ -28,16 +28,23 @@ Accounts::ChatOrWalletAccounts getAccounts();
/// \note the underlying status-go API, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result /// \note the underlying status-go API, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, void generateAccountWithDerivedPath(const HashedPassword& password,
const QColor &color, const QString &emoji, const QString& name,
const DerivationPath &path, const Accounts::EOAddress &derivedFrom); const QColor& color,
const QString& emoji,
const DerivationPath& path,
const Accounts::EOAddress& derivedFrom);
/// \brief Add a new account from an existing mnemonic /// \brief Add a new account from an existing mnemonic
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result /// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name, void addAccountWithMnemonicAndPath(const QString& mnemonic,
const QColor &color, const QString &emoji, const DerivationPath &path); const HashedPassword& password,
const QString& name,
const QColor& color,
const QString& emoji,
const DerivationPath& path);
/// \brief Add a watch only account /// \brief Add a watch only account
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result /// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
@ -57,4 +64,4 @@ void deleteAccount(const EOAddress &address);
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir); void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir);
} // namespaces } // namespace Status::StatusGo::Accounts

View File

@ -1,9 +1,12 @@
#include "ChatOrWalletAccount.h" #include "ChatOrWalletAccount.h"
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
void to_json(json& j, const ChatOrWalletAccount& d) { void to_json(json& j, const ChatOrWalletAccount& d)
j = {{"address", d.address}, {
j = {
{"address", d.address},
{"chat", d.isChat}, {"chat", d.isChat},
{"clock", d.clock}, {"clock", d.clock},
{"color", d.color}, {"color", d.color},
@ -17,11 +20,11 @@ void to_json(json& j, const ChatOrWalletAccount& d) {
{"wallet", d.isWallet}, {"wallet", d.isWallet},
}; };
if(d.derivedFrom != std::nullopt) if(d.derivedFrom != std::nullopt) j["derived-from"] = d.derivedFrom.value();
j["derived-from"] = d.derivedFrom.value();
} }
void from_json(const json& j, ChatOrWalletAccount& d) { void from_json(const json& j, ChatOrWalletAccount& d)
{
j.at("address").get_to(d.address); j.at("address").get_to(d.address);
j.at("chat").get_to(d.isChat); j.at("chat").get_to(d.isChat);
j.at("clock").get_to(d.clock); j.at("clock").get_to(d.clock);
@ -34,13 +37,11 @@ void from_json(const json& j, ChatOrWalletAccount& d) {
j.at("wallet").get_to(d.isWallet); j.at("wallet").get_to(d.isWallet);
constexpr auto pathKey = "path"; constexpr auto pathKey = "path";
if(j.contains(pathKey)) if(j.contains(pathKey)) j.at(pathKey).get_to(d.path);
j.at(pathKey).get_to(d.path);
constexpr auto publicKeyKey = "public-key"; constexpr auto publicKeyKey = "public-key";
if(j.contains(publicKeyKey)) if(j.contains(publicKeyKey)) j.at(publicKeyKey).get_to(d.publicKey);
j.at(publicKeyKey).get_to(d.publicKey);
if(d.isWallet && !j.at("derived-from").get<std::string>().empty()) if(d.isWallet && !j.at("derived-from").get<std::string>().empty())
d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>(); d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>();
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -12,8 +12,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
/// \brief Unique wallet account entity /// \brief Unique wallet account entity
/// \note equivalent of status-go's accounts.Account@multiaccounts/accounts/database.go /// \note equivalent of status-go's accounts.Account@multiaccounts/accounts/database.go
@ -39,4 +39,4 @@ using ChatOrWalletAccounts = std::vector<ChatOrWalletAccount>;
void to_json(json& j, const ChatOrWalletAccount& d); void to_json(json& j, const ChatOrWalletAccount& d);
void from_json(const json& j, ChatOrWalletAccount& d); void from_json(const json& j, ChatOrWalletAccount& d);
} } // namespace Status::StatusGo::Accounts

View File

@ -7,10 +7,11 @@
using json = nlohmann::json; using json = nlohmann::json;
/// Defines phantom types for strong typing /// Defines phantom types for strong typing
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
/// The 20 byte address of an Ethereum account prefixed with 0x /// The 20 byte address of an Ethereum account prefixed with 0x
using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>; using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>;
using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>; using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>;
} } // namespace Status::StatusGo::Accounts

View File

@ -1,7 +1,7 @@
#include "ChatAPI.h" #include "ChatAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
Chats::AllChannelGroupsDto Chats::getChats() Chats::AllChannelGroupsDto Chats::getChats()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "chat_getChats"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "chat_getChats"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);

View File

@ -6,4 +6,4 @@ namespace Status::StatusGo::Chats
{ {
/// \brief Retrieve all available channel groups /// \brief Retrieve all available channel groups
AllChannelGroupsDto getChats(); AllChannelGroupsDto getChats();
} } // namespace Status::StatusGo::Chats

View File

@ -1,75 +1,87 @@
#include "ChatDto.h" #include "ChatDto.h"
#include <Helpers/conversions.h>
#include <Helpers/JsonMacros.h> #include <Helpers/JsonMacros.h>
#include <Helpers/conversions.h>
using namespace Status::StatusGo; using namespace Status::StatusGo;
void Chats::to_json(json& j, const Category& d) { void Chats::to_json(json& j, const Category& d)
j = {{"id", d.id}, {
j = {
{"id", d.id},
{"name", d.name}, {"name", d.name},
{"position", d.position}, {"position", d.position},
}; };
} }
void Chats::from_json(const json& j, Category& d) { void Chats::from_json(const json& j, Category& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(name) STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
STATUS_READ_NLOHMAN_JSON_PROPERTY(position) STATUS_READ_NLOHMAN_JSON_PROPERTY(position)
STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "category_id", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "category_id", false)
if (!j.contains("category_id")){ if(!j.contains("category_id"))
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "id", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "id", false)
} }
} }
void Chats::to_json(json& j, const Permission& d) { void Chats::to_json(json& j, const Permission& d)
j = {{"access", d.access}, {
j = {
{"access", d.access},
{"ens_only", d.ensOnly}, {"ens_only", d.ensOnly},
}; };
} }
void Chats::from_json(const json& j, Permission& d) { void Chats::from_json(const json& j, Permission& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(access, "access", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(access, "access", false)
STATUS_READ_NLOHMAN_JSON_PROPERTY(ensOnly, "ens_only", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(ensOnly, "ens_only", false)
} }
void Chats::to_json(json& j, const Images& d) { void Chats::to_json(json& j, const Images& d)
j = {{"large", d.large}, {
j = {
{"large", d.large},
{"thumbnail", d.thumbnail}, {"thumbnail", d.thumbnail},
{"banner", d.banner}, {"banner", d.banner},
}; };
} }
void Chats::from_json(const json& j, Images& d) { void Chats::from_json(const json& j, Images& d)
{
constexpr auto large = "large"; constexpr auto large = "large";
if(j.contains(large)) if(j.contains(large)) j[large].at("uri").get_to(d.large);
j[large].at("uri").get_to(d.large);
constexpr auto thumbnail = "thumbnail"; constexpr auto thumbnail = "thumbnail";
if(j.contains(thumbnail)) if(j.contains(thumbnail)) j[thumbnail].at("uri").get_to(d.thumbnail);
j[thumbnail].at("uri").get_to(d.thumbnail);
constexpr auto banner = "banner"; constexpr auto banner = "banner";
if(j.contains(banner)) if(j.contains(banner)) j[banner].at("uri").get_to(d.banner);
j[banner].at("uri").get_to(d.banner);
} }
void Chats::to_json(json& j, const ChatMember& d) { void Chats::to_json(json& j, const ChatMember& d)
j = {{"id", d.id}, {
j = {
{"id", d.id},
{"admin", d.admin}, {"admin", d.admin},
{"joined", d.joined}, {"joined", d.joined},
{"roles", d.roles}, {"roles", d.roles},
}; };
} }
void Chats::from_json(const json& j, ChatMember& d) { void Chats::from_json(const json& j, ChatMember& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(id) STATUS_READ_NLOHMAN_JSON_PROPERTY(id)
STATUS_READ_NLOHMAN_JSON_PROPERTY(joined) STATUS_READ_NLOHMAN_JSON_PROPERTY(joined)
STATUS_READ_NLOHMAN_JSON_PROPERTY(roles) STATUS_READ_NLOHMAN_JSON_PROPERTY(roles)
STATUS_READ_NLOHMAN_JSON_PROPERTY(admin, "admin", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(admin, "admin", false)
} }
void Chats::to_json(json& j, const ChatDto& d) { void Chats::to_json(json& j, const ChatDto& d)
j = {{"id", d.id}, {
j = {
{"id", d.id},
{"name", d.name}, {"name", d.name},
{"description", d.description}, {"description", d.description},
{"color", d.color}, {"color", d.color},
@ -99,7 +111,8 @@ void Chats::to_json(json& j, const ChatDto& d) {
}; };
} }
void Chats::from_json(const json& j, ChatDto& d) { void Chats::from_json(const json& j, ChatDto& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(id) STATUS_READ_NLOHMAN_JSON_PROPERTY(id)
STATUS_READ_NLOHMAN_JSON_PROPERTY(name) STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
STATUS_READ_NLOHMAN_JSON_PROPERTY(description) STATUS_READ_NLOHMAN_JSON_PROPERTY(description)
@ -127,25 +140,31 @@ void Chats::from_json(const json& j, ChatDto& d) {
STATUS_READ_NLOHMAN_JSON_PROPERTY(chatType) STATUS_READ_NLOHMAN_JSON_PROPERTY(chatType)
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryId", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryId", false)
if (!j.contains("categoryId")) { if(!j.contains("categoryId"))
{
// Communities have `categoryID` and chats have `categoryId` // Communities have `categoryID` and chats have `categoryId`
// This should be fixed in status-go, but would be a breaking change // This should be fixed in status-go, but would be a breaking change
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryID", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryID", false)
} }
// Add community ID if needed // Add community ID if needed
if (!d.communityId.isEmpty() && !d.id.contains(d.communityId)) { if(!d.communityId.isEmpty() && !d.id.contains(d.communityId))
{
d.id = d.communityId + d.id; d.id = d.communityId + d.id;
} }
constexpr auto membersKey = "members"; constexpr auto membersKey = "members";
if (j.contains(membersKey)) { if(j.contains(membersKey))
if (j[membersKey].is_array()) { {
if(j[membersKey].is_array())
{
j.at(membersKey).get_to(d.members); j.at(membersKey).get_to(d.members);
} }
else if (j[membersKey].is_object()) { else if(j[membersKey].is_object())
{
auto obj = j[membersKey]; auto obj = j[membersKey];
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) { for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
{
ChatMember chatMember; ChatMember chatMember;
it.value().get_to(chatMember); it.value().get_to(chatMember);
chatMember.id = it.key().c_str(); chatMember.id = it.key().c_str();
@ -155,8 +174,10 @@ void Chats::from_json(const json& j, ChatDto& d) {
} }
} }
void Chats::to_json(json& j, const ChannelGroupDto& d) { void Chats::to_json(json& j, const ChannelGroupDto& d)
j = {{"id", d.id}, {
j = {
{"id", d.id},
{"admin", d.admin}, {"admin", d.admin},
{"verified", d.verified}, {"verified", d.verified},
{"name", d.name}, {"name", d.name},
@ -175,7 +196,8 @@ void Chats::to_json(json& j, const ChannelGroupDto& d) {
}; };
} }
void Chats::from_json(const json& j, ChannelGroupDto& d) { void Chats::from_json(const json& j, ChannelGroupDto& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(admin) STATUS_READ_NLOHMAN_JSON_PROPERTY(admin)
STATUS_READ_NLOHMAN_JSON_PROPERTY(verified) STATUS_READ_NLOHMAN_JSON_PROPERTY(verified)
STATUS_READ_NLOHMAN_JSON_PROPERTY(name) STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
@ -189,13 +211,14 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
STATUS_READ_NLOHMAN_JSON_PROPERTY(permissions, "permissions", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(permissions, "permissions", false)
STATUS_READ_NLOHMAN_JSON_PROPERTY(channelGroupType) STATUS_READ_NLOHMAN_JSON_PROPERTY(channelGroupType)
if (d.channelGroupType.isEmpty()) if(d.channelGroupType.isEmpty()) d.channelGroupType = ChannelGroupTypeUnknown;
d.channelGroupType = ChannelGroupTypeUnknown;
constexpr auto chats = "chats"; constexpr auto chats = "chats";
if (j.contains(chats)) { if(j.contains(chats))
{
auto obj = j[chats]; auto obj = j[chats];
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) { for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
{
ChatDto chatDto; ChatDto chatDto;
it.value().get_to(chatDto); it.value().get_to(chatDto);
d.chats.emplace_back(std::move(chatDto)); d.chats.emplace_back(std::move(chatDto));
@ -203,9 +226,11 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
} }
constexpr auto categories = "categories"; constexpr auto categories = "categories";
if (j.contains(categories)) { if(j.contains(categories))
{
auto obj = j[categories]; auto obj = j[categories];
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) { for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
{
Category category; Category category;
it.value().get_to(category); it.value().get_to(category);
d.categories.emplace_back(std::move(category)); d.categories.emplace_back(std::move(category));
@ -213,10 +238,13 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
} }
constexpr auto membersKey = "members"; constexpr auto membersKey = "members";
if (j.contains(membersKey)) { if(j.contains(membersKey))
if (j[membersKey].is_object()) { {
if(j[membersKey].is_object())
{
auto obj = j[membersKey]; auto obj = j[membersKey];
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) { for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
{
ChatMember chatMember; ChatMember chatMember;
it.value().get_to(chatMember); it.value().get_to(chatMember);
chatMember.id = it.key().c_str(); chatMember.id = it.key().c_str();
@ -226,16 +254,18 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
} }
} }
void Chats::to_json(json& j, const AllChannelGroupsDto& d) { void Chats::to_json(json& j, const AllChannelGroupsDto& d)
{
j = {{"id", d.allChannelGroups}}; j = {{"id", d.allChannelGroups}};
} }
void Chats::from_json(const json& j, AllChannelGroupsDto& d) { void Chats::from_json(const json& j, AllChannelGroupsDto& d)
for (json::const_iterator it = j.cbegin(); it != j.cend(); ++it) { {
for(json::const_iterator it = j.cbegin(); it != j.cend(); ++it)
{
ChannelGroupDto channelGroupDto; ChannelGroupDto channelGroupDto;
it.value().get_to(channelGroupDto); it.value().get_to(channelGroupDto);
channelGroupDto.id = it.key().c_str(); channelGroupDto.id = it.key().c_str();
d.allChannelGroups.emplace_back(std::move(channelGroupDto)); d.allChannelGroups.emplace_back(std::move(channelGroupDto));
} }
} }

View File

@ -8,7 +8,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Chats { namespace Status::StatusGo::Chats
{
constexpr auto ChannelGroupTypeUnknown = "unknown"; constexpr auto ChannelGroupTypeUnknown = "unknown";
constexpr auto ChannelGroupTypePersonal = "personal"; constexpr auto ChannelGroupTypePersonal = "personal";
@ -24,31 +25,36 @@ namespace Status::StatusGo::Chats {
CommunityChat = 6 CommunityChat = 6
}; };
struct Category { struct Category
{
QString id; QString id;
QString name; QString name;
int position; int position;
}; };
struct Permission { struct Permission
{
int access; int access;
bool ensOnly; bool ensOnly;
}; };
struct Images { struct Images
{
QString thumbnail; QString thumbnail;
QString large; QString large;
QString banner; QString banner;
}; };
struct ChatMember { struct ChatMember
{
QString id; QString id;
bool admin; bool admin;
bool joined; bool joined;
std::vector<int> roles; std::vector<int> roles;
}; };
struct ChatDto { struct ChatDto
{
QString id; // ID is the id of the chat, for public chats it is the name e.g. status, QString id; // ID is the id of the chat, for public chats it is the name e.g. status,
// for one-to-one is the hex encoded public key and for group chats is a random // for one-to-one is the hex encoded public key and for group chats is a random
// uuid appended with the hex encoded pk of the creator of the chat // uuid appended with the hex encoded pk of the creator of the chat
@ -60,7 +66,8 @@ namespace Status::StatusGo::Chats {
ChatType chatType; ChatType chatType;
quint64 timestamp; // indicates the last time this chat has received/sent a message quint64 timestamp; // indicates the last time this chat has received/sent a message
quint64 lastClockValue; // indicates the last clock value to be used when sending messages quint64 lastClockValue; // indicates the last clock value to be used when sending messages
quint64 deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded quint64
deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
quint64 readMessagesAtClockValue; quint64 readMessagesAtClockValue;
int unviewedMessagesCount; int unviewedMessagesCount;
int unviewedMentionsCount; int unviewedMentionsCount;
@ -80,7 +87,8 @@ namespace Status::StatusGo::Chats {
Permission permissions; Permission permissions;
}; };
struct ChannelGroupDto { struct ChannelGroupDto
{
QString id; QString id;
QString channelGroupType; QString channelGroupType;
bool admin; bool admin;
@ -102,11 +110,13 @@ namespace Status::StatusGo::Chats {
bool pinMessageAllMembersEnabled; bool pinMessageAllMembersEnabled;
}; };
struct AllChannelGroupsDto { struct AllChannelGroupsDto
{
std::vector<ChannelGroupDto> allChannelGroups; std::vector<ChannelGroupDto> allChannelGroups;
}; };
NLOHMANN_JSON_SERIALIZE_ENUM(ChatType, { NLOHMANN_JSON_SERIALIZE_ENUM(ChatType,
{
{Unknown, "Unknown"}, {Unknown, "Unknown"},
{OneToOne, "OneToOne"}, {OneToOne, "OneToOne"},
{Public, "Public"}, {Public, "Public"},
@ -129,4 +139,4 @@ namespace Status::StatusGo::Chats {
void from_json(const json& j, ChannelGroupDto& d); void from_json(const json& j, ChannelGroupDto& d);
void to_json(json& j, const AllChannelGroupsDto& d); void to_json(json& j, const AllChannelGroupsDto& d);
void from_json(const json& j, AllChannelGroupsDto& d); void from_json(const json& j, AllChannelGroupsDto& d);
} } // namespace Status::StatusGo::Chats

View File

@ -13,7 +13,8 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
{ {
auto result = InitKeystore(const_cast<char*>(keystoreDir)); auto result = InitKeystore(const_cast<char*>(keystoreDir));
QJsonObject jsonResult; QJsonObject jsonResult;
if(!Utils::checkReceivedResponse(result, jsonResult)) { if(!Utils::checkReceivedResponse(result, jsonResult))
{
throw std::domain_error("parsing response failed"); throw std::domain_error("parsing response failed");
} }
@ -35,4 +36,4 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
} }
} }
} } // namespace Status::StatusGo::General

View File

@ -7,11 +7,7 @@ namespace Status::StatusGo::Messenger
bool startMessenger() bool startMessenger()
{ {
QJsonObject payload{ QJsonObject payload{{"jsonrpc", "2.0"}, {"method", "wakuext_startMessenger"}, {"params", QJsonArray()}};
{"jsonrpc", "2.0"},
{"method", "wakuext_startMessenger"},
{"params", QJsonArray()}
};
auto callResult = Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(payload)); auto callResult = Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(payload));
if(callResult.containsError()) if(callResult.containsError())
@ -19,4 +15,4 @@ bool startMessenger()
return !callResult.containsError(); return !callResult.containsError();
} }
} } // namespace Status::StatusGo::Messenger

View File

@ -1,25 +1,28 @@
#include "api_response.h" #include "api_response.h"
namespace Status::StatusGo { namespace Status::StatusGo
{
void checkApiError(const json &response) { void checkApiError(const json& response)
if(response.contains("error")) { {
if(response.contains("error"))
{
const auto& error = response["error"]; const auto& error = response["error"];
if(error.is_object()) { if(error.is_object())
{
const auto apiErr = response["error"].get<ApiErrorResponseWithCode>(); const auto apiErr = response["error"].get<ApiErrorResponseWithCode>();
throw CallGenericPrepareJsonError(apiErr); throw CallGenericPrepareJsonError(apiErr);
} }
assert(error.is_string()); assert(error.is_string());
const auto apiError = response.get<ApiErrorResponse>(); const auto apiError = response.get<ApiErrorResponse>();
if(!apiError.error.empty()) if(!apiError.error.empty()) throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
} }
} }
/// \throws \c CallPrivateRpcError, \c nlohmann::exception /// \throws \c CallPrivateRpcError, \c nlohmann::exception
void checkPrivateRpcCallResultAndReportError(const json &response) { void checkPrivateRpcCallResultAndReportError(const json& response)
if(response.contains("error")) {
throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>()); if(response.contains("error")) throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>());
} }
} // namespace } // namespace Status::StatusGo

View File

@ -8,7 +8,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo { namespace Status::StatusGo
{
/*! /*!
* \brief General API response if an internal status-go error occured * \brief General API response if an internal status-go error occured
@ -18,7 +19,8 @@ namespace Status::StatusGo {
* *
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiErrorResponse { struct ApiErrorResponse
{
std::string error; std::string error;
}; };
@ -31,7 +33,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ApiErrorResponse, error)
* *
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct JsonError { struct JsonError
{
int code{0}; int code{0};
std::string message; std::string message;
}; };
@ -45,7 +48,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(JsonError, code, message)
* \see jsonrpcSuccessfulResponse@response.go * \see jsonrpcSuccessfulResponse@response.go
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiErrorResponseWithCode { struct ApiErrorResponseWithCode
{
JsonError error; JsonError error;
}; };
@ -60,7 +64,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ApiErrorResponseWithCode, error)
* *
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiResponse { struct ApiResponse
{
json result; json result;
}; };
@ -116,38 +121,53 @@ void checkApiError(const json& response);
constexpr int defaultErrorCode = -32000; constexpr int defaultErrorCode = -32000;
class CallGenericMakeJsonError: public std::runtime_error { class CallGenericMakeJsonError : public std::runtime_error
{
public: public:
CallGenericMakeJsonError(const ApiErrorResponse error) CallGenericMakeJsonError(const ApiErrorResponse error)
: std::runtime_error("CallGenericMakeJsonError@status-go failed") : std::runtime_error("CallGenericMakeJsonError@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{ } { }
const ApiErrorResponse &errorResponse() const { return m_error; }; const ApiErrorResponse& errorResponse() const
{
return m_error;
};
private: private:
const ApiErrorResponse m_error; const ApiErrorResponse m_error;
}; };
class CallGenericPrepareJsonError: public std::runtime_error { class CallGenericPrepareJsonError : public std::runtime_error
{
public: public:
CallGenericPrepareJsonError(const ApiErrorResponseWithCode error) CallGenericPrepareJsonError(const ApiErrorResponseWithCode error)
: std::runtime_error("CallGenericPrepareJsonError@status-go failed") : std::runtime_error("CallGenericPrepareJsonError@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{ } { }
const ApiErrorResponseWithCode &errorResponse() const { return m_error; }; const ApiErrorResponseWithCode& errorResponse() const
{
return m_error;
};
private: private:
const ApiErrorResponseWithCode m_error; const ApiErrorResponseWithCode m_error;
}; };
class CallPrivateRpcError: public std::runtime_error { class CallPrivateRpcError : public std::runtime_error
{
public: public:
CallPrivateRpcError(const CallPrivateRpcErrorResponse error) CallPrivateRpcError(const CallPrivateRpcErrorResponse error)
: std::runtime_error("CallPrivateRPC@status-go failed") : std::runtime_error("CallPrivateRPC@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{ } { }
const CallPrivateRpcErrorResponse &errorResponse() const { return m_error; }; const CallPrivateRpcErrorResponse& errorResponse() const
{
return m_error;
};
private: private:
const CallPrivateRpcErrorResponse m_error; const CallPrivateRpcErrorResponse m_error;
}; };
@ -160,4 +180,4 @@ private:
*/ */
void checkPrivateRpcCallResultAndReportError(const json& response); void checkPrivateRpcCallResultAndReportError(const json& response);
} } // namespace Status::StatusGo

View File

@ -1,7 +1,7 @@
#include "SettingsAPI.h" #include "SettingsAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
Settings::SettingsDto Settings::getSettings() Settings::SettingsDto Settings::getSettings()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "settings_getSettings"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "settings_getSettings"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);

View File

@ -6,4 +6,4 @@ namespace Status::StatusGo::Settings
{ {
/// \brief Retrieve settings /// \brief Retrieve settings
SettingsDto getSettings(); SettingsDto getSettings();
} } // namespace Status::StatusGo::Settings

View File

@ -1,12 +1,14 @@
#include "SettingsDto.h" #include "SettingsDto.h"
#include <Helpers/conversions.h>
#include <Helpers/JsonMacros.h> #include <Helpers/JsonMacros.h>
#include <Helpers/conversions.h>
using namespace Status::StatusGo; using namespace Status::StatusGo;
void Settings::to_json(json& j, const SettingsDto& d) { void Settings::to_json(json& j, const SettingsDto& d)
j = {{"address", d.address}, {
j = {
{"address", d.address},
{"display-name", d.displayName}, {"display-name", d.displayName},
{"preferred-name", d.preferredName}, {"preferred-name", d.preferredName},
{"key-uid", d.keyUid}, {"key-uid", d.keyUid},
@ -14,7 +16,8 @@ void Settings::to_json(json& j, const SettingsDto& d) {
}; };
} }
void Settings::from_json(const json& j, SettingsDto& d) { void Settings::from_json(const json& j, SettingsDto& d)
{
STATUS_READ_NLOHMAN_JSON_PROPERTY(address) STATUS_READ_NLOHMAN_JSON_PROPERTY(address)
STATUS_READ_NLOHMAN_JSON_PROPERTY(displayName, "display-name") STATUS_READ_NLOHMAN_JSON_PROPERTY(displayName, "display-name")
STATUS_READ_NLOHMAN_JSON_PROPERTY(preferredName, "preferred-name", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(preferredName, "preferred-name", false)

View File

@ -8,9 +8,11 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Settings { namespace Status::StatusGo::Settings
{
struct SettingsDto { struct SettingsDto
{
QString address; QString address;
QString displayName; QString displayName;
QString preferredName; QString preferredName;
@ -20,4 +22,4 @@ namespace Status::StatusGo::Settings {
void to_json(json& j, const SettingsDto& d); void to_json(json& j, const SettingsDto& d);
void from_json(const json& j, SettingsDto& d); void from_json(const json& j, SettingsDto& d);
} } // namespace Status::StatusGo::Settings

View File

@ -6,7 +6,8 @@
using namespace std::string_literals; using namespace std::string_literals;
namespace Status::StatusGo { namespace Status::StatusGo
{
std::map<std::string, SignalType> SignalsManager::signalMap; std::map<std::string, SignalType> SignalsManager::signalMap;
@ -22,8 +23,7 @@ SignalsManager::SignalsManager()
{ {
SetSignalEventCallback((void*)&SignalsManager::signalCallback); SetSignalEventCallback((void*)&SignalsManager::signalCallback);
signalMap = { signalMap = {{"node.ready"s, SignalType::NodeReady},
{"node.ready"s, SignalType::NodeReady},
{"node.started"s, SignalType::NodeStarted}, {"node.started"s, SignalType::NodeStarted},
{"node.stopped"s, SignalType::NodeStopped}, {"node.stopped"s, SignalType::NodeStopped},
{"node.login"s, SignalType::NodeLogin}, {"node.login"s, SignalType::NodeLogin},
@ -38,13 +38,10 @@ SignalsManager::SignalsManager()
{"history.request.started"s, SignalType::HistoryRequestStarted}, {"history.request.started"s, SignalType::HistoryRequestStarted},
{"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed}, {"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed},
{"history.request.completed"s, SignalType::HistoryRequestCompleted} {"history.request.completed"s, SignalType::HistoryRequestCompleted}};
};
} }
SignalsManager::~SignalsManager() SignalsManager::~SignalsManager() { }
{
}
void SignalsManager::processSignal(const QString& statusSignal) void SignalsManager::processSignal(const QString& statusSignal)
{ {
@ -82,46 +79,22 @@ void SignalsManager::decode(const QJsonObject& signalEvent)
switch(signalType) switch(signalType)
{ {
// TODO: create extractor functions like in nim // TODO: create extractor functions like in nim
case NodeLogin: case NodeLogin: emit nodeLogin(signalError); break;
emit nodeLogin(signalError); case NodeReady: emit nodeReady(signalError); break;
break; case NodeStarted: emit nodeStarted(signalError); break;
case NodeReady: case NodeStopped: emit nodeStopped(signalError); break;
emit nodeReady(signalError);
break;
case NodeStarted:
emit nodeStarted(signalError);
break;
case NodeStopped:
emit nodeStopped(signalError);
break;
case NodeCrashed: case NodeCrashed:
qWarning() << "node.crashed, error: " << signalError; qWarning() << "node.crashed, error: " << signalError;
emit nodeCrashed(signalError); emit nodeCrashed(signalError);
break; break;
case DiscoveryStarted: case DiscoveryStarted: emit discoveryStarted(signalError); break;
emit discoveryStarted(signalError); case DiscoveryStopped: emit discoveryStopped(signalError); break;
break; case DiscoverySummary: emit discoverySummary(signalEvent["event"].toArray().count(), signalError); break;
case DiscoveryStopped: case MailserverChanged: emit mailserverChanged(signalError); break;
emit discoveryStopped(signalError); case MailserverAvailable: emit mailserverAvailable(signalError); break;
break; case HistoryRequestStarted: emit historyRequestStarted(signalError); break;
case DiscoverySummary: case HistoryRequestBatchProcessed: emit historyRequestBatchProcessed(signalError); break;
emit discoverySummary(signalEvent["event"].toArray().count(), signalError); case HistoryRequestCompleted: emit historyRequestCompleted(signalError); break;
break;
case MailserverChanged:
emit mailserverChanged(signalError);
break;
case MailserverAvailable:
emit mailserverAvailable(signalError);
break;
case HistoryRequestStarted:
emit historyRequestStarted(signalError);
break;
case HistoryRequestBatchProcessed:
emit historyRequestBatchProcessed(signalError);
break;
case HistoryRequestCompleted:
emit historyRequestCompleted(signalError);
break;
case Unknown: assert(false); break; case Unknown: assert(false); break;
} }
} }
@ -130,9 +103,8 @@ void SignalsManager::signalCallback(const char* data)
{ {
// TODO: overkill, use some kind of message broker // TODO: overkill, use some kind of message broker
auto dataStrPtr = std::make_shared<QString>(data); auto dataStrPtr = std::make_shared<QString>(data);
QFuture<void> future = QtConcurrent::run([dataStrPtr](){ QFuture<void> future =
SignalsManager::instance()->processSignal(*dataStrPtr); QtConcurrent::run([dataStrPtr]() { SignalsManager::instance()->processSignal(*dataStrPtr); });
});
} }
} } // namespace Status::StatusGo

View File

@ -2,7 +2,8 @@
#include <QObject> #include <QObject>
namespace Status::StatusGo { namespace Status::StatusGo
{
enum SignalType enum SignalType
{ {
@ -35,7 +36,6 @@ class SignalsManager final : public QObject
Q_OBJECT Q_OBJECT
public: public:
static SignalsManager* instance(); static SignalsManager* instance();
void processSignal(const QString& ev); void processSignal(const QString& ev);
@ -57,6 +57,7 @@ signals:
void historyRequestStarted(const QString& error); void historyRequestStarted(const QString& error);
void historyRequestBatchProcessed(const QString& error); void historyRequestBatchProcessed(const QString& error);
void historyRequestCompleted(const QString& error); void historyRequestCompleted(const QString& error);
private: private:
explicit SignalsManager(); explicit SignalsManager();
~SignalsManager(); ~SignalsManager();
@ -67,4 +68,4 @@ private:
void decode(const QJsonObject& signalEvent); void decode(const QJsonObject& signalEvent);
}; };
} } // namespace Status::StatusGo

View File

@ -30,8 +30,9 @@ struct RpcResponse
int id; int id;
RpcError error; RpcError error;
explicit explicit RpcResponse(T result,
RpcResponse(T result, QString version = RpcError::UnknownVersion, int id = RpcError::UnknownId, QString version = RpcError::UnknownVersion,
int id = RpcError::UnknownId,
RpcError error = RpcError()) RpcError error = RpcError())
: result(std::move(result)) : result(std::move(result))
, jsonRpcVersion(std::move(version)) , jsonRpcVersion(std::move(version))
@ -39,9 +40,10 @@ struct RpcResponse
, error(std::move(error)) , error(std::move(error))
{ } { }
bool containsError() const { bool containsError() const
{
return !error.message.isEmpty() || error.code != RpcError::NoError; return !error.message.isEmpty() || error.code != RpcError::NoError;
} }
}; };
} } // namespace Status::StatusGo

View File

@ -15,7 +15,8 @@ QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value)
return array; return array;
} }
const char* statusGoCallPrivateRPC(const char* inputJSON) { const char* statusGoCallPrivateRPC(const char* inputJSON)
{
// Evil done here! status-go API doesn't follow the proper const conventions // Evil done here! status-go API doesn't follow the proper const conventions
return CallPrivateRPC(const_cast<char*>(inputJSON)); return CallPrivateRPC(const_cast<char*>(inputJSON));
} }
@ -23,17 +24,16 @@ const char* statusGoCallPrivateRPC(const char* inputJSON) {
HashedPassword hashPassword(const QString& str) HashedPassword hashPassword(const QString& str)
{ {
// TODO: is utf8 the standard used by NIM also? Will it unlock DBs encrypted with NIM password hashing? // TODO: is utf8 the standard used by NIM also? Will it unlock DBs encrypted with NIM password hashing?
return HashedPassword("0x" + QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(), return HashedPassword(
QCryptographicHash::Keccak_256).toHex().toUpper())); "0x" +
QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Keccak_256).toHex().toUpper()));
} }
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json) std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json)
{ {
auto errVal = json[Param::Error]; auto errVal = json[Param::Error];
if (errVal.isNull() || errVal.isUndefined()) if(errVal.isNull() || errVal.isUndefined()) return std::nullopt;
return std::nullopt; if(errVal.isString() && errVal.toString().length() == 0) return std::nullopt;
if(errVal.isString() && errVal.toString().length() == 0)
return std::nullopt;
RpcError response; RpcError response;
auto errObj = json[Param::Id].toObject(); auto errObj = json[Param::Id].toObject();
@ -46,4 +46,4 @@ std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json)
return response; return response;
} }
} } // namespace Status::StatusGo::Utils

View File

@ -1,29 +1,30 @@
#pragma once #pragma once
#include "Types.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include "Types.h"
#include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray>
namespace Status::StatusGo::Utils namespace Status::StatusGo::Utils
{ {
namespace Param { namespace Param
{
static constexpr auto Id{"id"}; static constexpr auto Id{"id"};
static constexpr auto JsonRpc{"jsonrpc"}; static constexpr auto JsonRpc{"jsonrpc"};
static constexpr auto Result{"result"}; static constexpr auto Result{"result"};
static constexpr auto Error{"error"}; static constexpr auto Error{"error"};
static constexpr auto ErrorMessage{"message"}; static constexpr auto ErrorMessage{"message"};
static constexpr auto ErrorCode{"code"}; static constexpr auto ErrorCode{"code"};
} } // namespace Param
template <class T> template <class T>
QByteArray jsonToByteArray(const T& json) QByteArray jsonToByteArray(const T& json)
{ {
static_assert(std::is_same_v<T, QJsonObject> || static_assert(std::is_same_v<T, QJsonObject> || std::is_same_v<T, QJsonArray>,
std::is_same_v<T, QJsonArray>, "Wrong Json type. Supported: Object, Array"); "Wrong Json type. Supported: Object, Array");
return QJsonDocument(json).toJson(QJsonDocument::Compact); return QJsonDocument(json).toJson(QJsonDocument::Compact);
} }
@ -37,8 +38,7 @@ bool checkReceivedResponse(const QString& response, T& json)
{ {
QJsonParseError error; QJsonParseError error;
auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error); auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) if(error.error != QJsonParseError::NoError) return false;
return false;
if constexpr(std::is_same_v<T, QJsonObject>) if constexpr(std::is_same_v<T, QJsonObject>)
{ {
@ -62,8 +62,7 @@ RpcResponse<T> buildPrivateRPCResponse(const T& json)
if constexpr(std::is_same_v<T, QJsonObject>) if constexpr(std::is_same_v<T, QJsonObject>)
{ {
if (!json[Param::Id].isNull() && !json[Param::Id].isUndefined()) if(!json[Param::Id].isNull() && !json[Param::Id].isUndefined()) response.id = json[Param::Id].toInt();
response.id = json[Param::Id].toInt();
if(!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined()) if(!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined())
response.jsonRpcVersion = json[Param::JsonRpc].toString(); response.jsonRpcVersion = json[Param::JsonRpc].toString();
@ -114,4 +113,4 @@ RpcResponse<T> callPrivateRpc(const QByteArray& payload)
HashedPassword hashPassword(const QString& str); HashedPassword hashPassword(const QString& str);
} } // namespace Status::StatusGo::Utils

View File

@ -1,36 +1,36 @@
#include "BigInt.h" #include "BigInt.h"
#include <locale>
#include <iostream> #include <iostream>
#include <locale>
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
namespace Status { namespace Status
namespace StatusGo::Wallet { {
namespace StatusGo::Wallet
{
std::string toHexData(const BigInt& num, bool uppercase) std::string toHexData(const BigInt& num, bool uppercase)
{ {
return num.str(0, std::ios_base::showbase | std::ios_base::hex | (uppercase ? std::ios_base::uppercase : std::ios_base::fmtflags(0))); return num.str(0,
std::ios_base::showbase | std::ios_base::hex |
(uppercase ? std::ios_base::uppercase : std::ios_base::fmtflags(0)));
} }
using namespace QtLiterals; using namespace QtLiterals;
bool has0xPrefix(const QByteArray &in) { bool has0xPrefix(const QByteArray& in)
{
return in.size() >= 2 && Helpers::iequals(in.first(2), "0x"_qba); return in.size() >= 2 && Helpers::iequals(in.first(2), "0x"_qba);
} }
BigInt parseHex(const std::string& value) BigInt parseHex(const std::string& value)
{ {
auto data = QByteArray::fromRawData(value.c_str(), value.size()); auto data = QByteArray::fromRawData(value.c_str(), value.size());
if (!has0xPrefix(data)) if(!has0xPrefix(data)) throw std::runtime_error("BigInt::parseHex missing 0x prefix");
throw std::runtime_error("BigInt::parseHex missing 0x prefix"); if(data.size() == 2) throw std::runtime_error("BigInt::parseHex empty number");
if (data.size() == 2) if(data.size() > 3 && data[2] == '0') throw std::runtime_error("BigInt::parseHex leading zero");
throw std::runtime_error("BigInt::parseHex empty number"); if(data.size() > 66) throw std::runtime_error("BigInt::parseHex more than 256 bits");
if (data.size() > 3 && data[2] == '0')
throw std::runtime_error("BigInt::parseHex leading zero");
if (data.size() > 66)
throw std::runtime_error("BigInt::parseHex more than 256 bits");
return BigInt{data.data()}; return BigInt{data.data()};
} }

View File

@ -11,8 +11,10 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status { namespace Status
namespace StatusGo::Wallet { {
namespace StatusGo::Wallet
{
using BigInt = boost::multiprecision::uint256_t; using BigInt = boost::multiprecision::uint256_t;
@ -24,24 +26,28 @@ std::string toHexData(const BigInt &num, bool uppercase = false);
/// \see toHexData /// \see toHexData
BigInt parseHex(const std::string& value); BigInt parseHex(const std::string& value);
} } // namespace StatusGo::Wallet
/// Human readable form /// Human readable form
QString toQString(const StatusGo::Wallet::BigInt& num); QString toQString(const StatusGo::Wallet::BigInt& num);
} // Status::StatusGo::Wallet } // namespace Status
namespace nlohmann { namespace nlohmann
{
namespace GoWallet = Status::StatusGo::Wallet; namespace GoWallet = Status::StatusGo::Wallet;
template <> template <>
struct adl_serializer<GoWallet::BigInt> { struct adl_serializer<GoWallet::BigInt>
static void to_json(json& j, const GoWallet::BigInt& num) { {
static void to_json(json& j, const GoWallet::BigInt& num)
{
j = GoWallet::toHexData(num); j = GoWallet::toHexData(num);
} }
static void from_json(const json& j, GoWallet::BigInt& num) { static void from_json(const json& j, GoWallet::BigInt& num)
{
num = GoWallet::BigInt(j.get<std::string>()); num = GoWallet::BigInt(j.get<std::string>());
} }
}; };

View File

@ -14,7 +14,8 @@ namespace Accounts = Status::StatusGo::Accounts;
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \brief Define a derived address as returned by the corresponding API /// \brief Define a derived address as returned by the corresponding API
/// \note equivalent of status-go's DerivedAddress@api.go /// \note equivalent of status-go's DerivedAddress@api.go
@ -31,4 +32,4 @@ using DerivedAddresses = std::vector<DerivedAddress>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DerivedAddress, address, path, hasActivity, alreadyCreated); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DerivedAddress, address, path, hasActivity, alreadyCreated);
} } // namespace Status::StatusGo::Wallet

View File

@ -12,7 +12,8 @@
using json = nlohmann::json; using json = nlohmann::json;
/// \note not sure if this is the best namespace, ok for now /// \note not sure if this is the best namespace, ok for now
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \note equivalent of status-go's Network@config.go (params package) /// \note equivalent of status-go's Network@config.go (params package)
struct NetworkConfiguration struct NetworkConfiguration
@ -34,9 +35,19 @@ struct NetworkConfiguration
using NetworkConfigurations = std::vector<NetworkConfiguration>; using NetworkConfigurations = std::vector<NetworkConfiguration>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration, chainId, chainName, rpcUrl, blockExplorerUrl, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration,
iconUrl, nativeCurrencyName, nativeCurrencySymbol, chainId,
nativeCurrencyDecimals, isTest, layer, enabled, chainColor, chainName,
rpcUrl,
blockExplorerUrl,
iconUrl,
nativeCurrencyName,
nativeCurrencySymbol,
nativeCurrencyDecimals,
isTest,
layer,
enabled,
chainColor,
shortName); shortName);
} } // namespace Status::StatusGo::Wallet

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "wallet_types.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include "wallet_types.h"
#include <Helpers/conversions.h> #include <Helpers/conversions.h>
@ -11,7 +11,8 @@
namespace Accounts = Status::StatusGo::Accounts; namespace Accounts = Status::StatusGo::Accounts;
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \brief Define a saved wallet address as returned by the corresponding API /// \brief Define a saved wallet address as returned by the corresponding API
/// \note equivalent of status-go's SavedAddress@api.go /// \note equivalent of status-go's SavedAddress@api.go
@ -28,4 +29,4 @@ using SavedAddresses = std::vector<SavedAddress>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SavedAddress, address, name, favourite, chainId); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SavedAddress, address, name, favourite, chainId);
} } // namespace Status::StatusGo::Wallet

View File

@ -14,7 +14,8 @@ namespace Accounts = Status::StatusGo::Accounts;
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \note equivalent of status-go's Token@token.go /// \note equivalent of status-go's Token@token.go
/// \see \c getDerivedAddressesForPath /// \see \c getDerivedAddressesForPath
@ -31,7 +32,6 @@ struct Token
using TokenPtr = std::shared_ptr<Token>; using TokenPtr = std::shared_ptr<Token>;
using Tokens = std::vector<Token>; using Tokens = std::vector<Token>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name,symbol, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name, symbol, color, decimals, chainId);
color, decimals, chainId);
} } // namespace Status::StatusGo::Wallet

View File

@ -1,7 +1,7 @@
#include "WalletApi.h" #include "WalletApi.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
@ -18,14 +18,14 @@ using json = nlohmann::json;
namespace Status::StatusGo::Wallet namespace Status::StatusGo::Wallet
{ {
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, const Accounts::EOAddress &derivedFrom, const Accounts::DerivationPath &path, int pageSize, int pageNumber) DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password,
const Accounts::EOAddress& derivedFrom,
const Accounts::DerivationPath& path,
int pageSize,
int pageNumber)
{ {
std::vector<json> params = {password, derivedFrom, path, pageSize, pageNumber}; std::vector<json> params = {password, derivedFrom, path, pageSize, pageNumber};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getDerivedAddressesForPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getDerivedAddressesForPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -36,10 +36,7 @@ DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, cons
SavedAddresses getSavedAddresses() SavedAddresses getSavedAddresses()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getSavedAddresses"}};
{"jsonrpc", "2.0"},
{"method", "wallet_getSavedAddresses"}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -52,11 +49,7 @@ SavedAddresses getSavedAddresses()
void saveAddress(const SavedAddress& address) void saveAddress(const SavedAddress& address)
{ {
std::vector<json> params = {address}; std::vector<json> params = {address};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wakuext_upsertSavedAddress"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wakuext_upsertSavedAddress"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -66,11 +59,7 @@ void saveAddress(const SavedAddress &address)
NetworkConfigurations getEthereumChains(bool onlyEnabled) NetworkConfigurations getEthereumChains(bool onlyEnabled)
{ {
std::vector<json> params = {onlyEnabled}; std::vector<json> params = {onlyEnabled};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getEthereumChains"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getEthereumChains"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -83,11 +72,7 @@ NetworkConfigurations getEthereumChains(bool onlyEnabled)
Tokens getTokens(const ChainID& chainId) Tokens getTokens(const ChainID& chainId)
{ {
std::vector<json> params = {chainId}; std::vector<json> params = {chainId};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokens"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getTokens"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -102,11 +87,7 @@ TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID> &chainIds,
const std::vector<Accounts::EOAddress> tokens) const std::vector<Accounts::EOAddress> tokens)
{ {
std::vector<json> params = {chainIds, accounts, tokens}; std::vector<json> params = {chainIds, accounts, tokens};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokensBalancesForChainIDs"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getTokensBalancesForChainIDs"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -117,7 +98,8 @@ TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID> &chainIds,
// Workaround to exception "type must be array, but is object" for custom key-types // Workaround to exception "type must be array, but is object" for custom key-types
// TODO: find out why // TODO: find out why
std::map<std::string, std::map<std::string, BigInt>> dataMap = data.is_null() ? nlohmann::json() : data; std::map<std::string, std::map<std::string, BigInt>> dataMap = data.is_null() ? nlohmann::json() : data;
for(const auto &keyIt : dataMap) { for(const auto& keyIt : dataMap)
{
std::map<Accounts::EOAddress, BigInt> val; std::map<Accounts::EOAddress, BigInt> val;
for(const auto& valIt : keyIt.second) for(const auto& valIt : keyIt.second)
val.emplace(QString::fromStdString(valIt.first), valIt.second); val.emplace(QString::fromStdString(valIt.first), valIt.second);
@ -126,4 +108,4 @@ TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID> &chainIds,
return resultData; return resultData;
} }
} // namespaces } // namespace Status::StatusGo::Wallet

View File

@ -6,8 +6,8 @@
#include "DerivedAddress.h" #include "DerivedAddress.h"
#include "NetworkConfiguration.h" #include "NetworkConfiguration.h"
#include "Token.h"
#include "SavedAddress.h" #include "SavedAddress.h"
#include "Token.h"
#include "Types.h" #include "Types.h"
@ -23,7 +23,8 @@ namespace Status::StatusGo::Wallet
DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password, DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password,
const Accounts::EOAddress& derivedFrom, const Accounts::EOAddress& derivedFrom,
const Accounts::DerivationPath& path, const Accounts::DerivationPath& path,
int pageSize, int pageNumber); int pageSize,
int pageNumber);
/// \brief Retrieve a list of saved wallet addresses /// \brief Retrieve a list of saved wallet addresses
/// \see \c getSavedAddresses /// \see \c getSavedAddresses
@ -46,7 +47,6 @@ NetworkConfigurations getEthereumChains(bool onlyEnabled);
/// \throws \c CallPrivateRpcError for general RPC call failure /// \throws \c CallPrivateRpcError for general RPC call failure
NetworkConfigurations getEthereumChains(bool onlyEnabled); NetworkConfigurations getEthereumChains(bool onlyEnabled);
/// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go /// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go
/// \throws \c CallPrivateRpcError with /// \throws \c CallPrivateRpcError with
Tokens getTokens(const ChainID& chainId); Tokens getTokens(const ChainID& chainId);
@ -57,4 +57,4 @@ using TokenBalances = std::map<Accounts::EOAddress, std::map<Accounts::EOAddress
TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID>& chainIds, TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID>& chainIds,
const std::vector<Accounts::EOAddress> accounts, const std::vector<Accounts::EOAddress> accounts,
const std::vector<Accounts::EOAddress> tokens); const std::vector<Accounts::EOAddress> tokens);
} // namespaces } // namespace Status::StatusGo::Wallet

View File

@ -3,13 +3,13 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <QString> #include <QString>
using json = nlohmann::json; using json = nlohmann::json;
/// Defines phantom types for strong typing /// Defines phantom types for strong typing
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
using ChainID = Helpers::NamedType<unsigned long long int, struct ChainIDTag>; using ChainID = Helpers::NamedType<unsigned long long int, struct ChainIDTag>;

View File

@ -6,7 +6,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace StatusGo = Status::StatusGo; namespace StatusGo = Status::StatusGo;
namespace Status::Testing { namespace Status::Testing
{
TEST(StatusGoQt, TestJsonParsing) TEST(StatusGoQt, TestJsonParsing)
{ {
@ -19,13 +20,15 @@ TEST(StatusGoQt, TestJsonParsing)
ASSERT_EQ(callRawRPCJson.error.message, expectedJsonError.message); ASSERT_EQ(callRawRPCJson.error.message, expectedJsonError.message);
auto callRawRPCBadJsonKeyStr = R"({"unknown":"2.0","id":42,"error":{"code":-32601,"message":"Method not found"}})"; auto callRawRPCBadJsonKeyStr = R"({"unknown":"2.0","id":42,"error":{"code":-32601,"message":"Method not found"}})";
ASSERT_THROW(json::parse(callRawRPCBadJsonKeyStr).get<StatusGo::CallPrivateRpcErrorResponse>(), nlohmann::detail::out_of_range); ASSERT_THROW(json::parse(callRawRPCBadJsonKeyStr).get<StatusGo::CallPrivateRpcErrorResponse>(),
nlohmann::detail::out_of_range);
auto callRawRPCBadJsonValStr = R"({"jsonrpc":"2.0","id":42,"error":23})"; auto callRawRPCBadJsonValStr = R"({"jsonrpc":"2.0","id":42,"error":23})";
ASSERT_THROW(json::parse(callRawRPCBadJsonValStr).get<StatusGo::CallPrivateRpcErrorResponse>(), nlohmann::detail::type_error); ASSERT_THROW(json::parse(callRawRPCBadJsonValStr).get<StatusGo::CallPrivateRpcErrorResponse>(),
nlohmann::detail::type_error);
auto statusGoWithResultJsonStr = R"({"result":"0x123"})"; auto statusGoWithResultJsonStr = R"({"result":"0x123"})";
auto statusGoWithResultJson = json::parse(statusGoWithResultJsonStr).get<StatusGo::ApiResponse>(); auto statusGoWithResultJson = json::parse(statusGoWithResultJsonStr).get<StatusGo::ApiResponse>();
ASSERT_EQ(statusGoWithResultJson.result, "0x123"); ASSERT_EQ(statusGoWithResultJson.result, "0x123");
} }
} // namespace } // namespace Status::Testing

View File

@ -4,7 +4,8 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
fs::path createTestFolder(const std::string& testName) fs::path createTestFolder(const std::string& testName)
{ {
@ -18,8 +19,7 @@ fs::path createTestFolder(const std::string& testName)
AutoCleanTempTestDir::AutoCleanTempTestDir(const std::string& testName, bool createDir) AutoCleanTempTestDir::AutoCleanTempTestDir(const std::string& testName, bool createDir)
: m_testFolder(createTestFolder(testName)) : m_testFolder(createTestFolder(testName))
{ {
if(createDir) if(createDir) fs::create_directories(m_testFolder);
fs::create_directories(m_testFolder);
} }
AutoCleanTempTestDir::~AutoCleanTempTestDir() AutoCleanTempTestDir::~AutoCleanTempTestDir()
@ -33,4 +33,4 @@ const std::filesystem::path& AutoCleanTempTestDir::tempFolder()
return m_testFolder; return m_testFolder;
} }
} } // namespace Status::Testing

View File

@ -4,9 +4,11 @@
#include <string> #include <string>
namespace Status::Testing { namespace Status::Testing
{
class AutoCleanTempTestDir { class AutoCleanTempTestDir
{
public: public:
/// Creates a temporary folder to be used in tests. The folder content's will /// Creates a temporary folder to be used in tests. The folder content's will
/// be removed when out of scope /// be removed when out of scope
@ -19,4 +21,4 @@ private:
const std::filesystem::path m_testFolder; const std::filesystem::path m_testFolder;
}; };
} } // namespace Status::Testing

View File

@ -3,13 +3,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
namespace Status::Testing { namespace Status::Testing
{
std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing; std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing;
std::mutex MonitorQtOutput::m_mutex; std::mutex MonitorQtOutput::m_mutex;
QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr; QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr;
MonitorQtOutput::MonitorQtOutput() MonitorQtOutput::MonitorQtOutput()
{ {
// Ensure only one instance registers a handler // Ensure only one instance registers a handler
@ -17,13 +17,14 @@ MonitorQtOutput::MonitorQtOutput()
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
auto globalMsgOut = m_qtMessageOutputForSharing.lock(); auto globalMsgOut = m_qtMessageOutputForSharing.lock();
auto prev = qInstallMessageHandler(qtMessageOutput); auto prev = qInstallMessageHandler(qtMessageOutput);
if(prev != qtMessageOutput) if(prev != qtMessageOutput) m_previousHandler = prev;
m_previousHandler = prev; if(!globalMsgOut)
if(!globalMsgOut) { {
m_thisMessageOutput = std::make_shared<QString>(); m_thisMessageOutput = std::make_shared<QString>();
m_qtMessageOutputForSharing = m_thisMessageOutput; m_qtMessageOutputForSharing = m_thisMessageOutput;
} }
else { else
{
m_thisMessageOutput = globalMsgOut; m_thisMessageOutput = globalMsgOut;
m_start = m_thisMessageOutput->length(); m_start = m_thisMessageOutput->length();
} }
@ -32,15 +33,15 @@ MonitorQtOutput::MonitorQtOutput()
MonitorQtOutput::~MonitorQtOutput() MonitorQtOutput::~MonitorQtOutput()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
if(m_thisMessageOutput.use_count() == 1) { if(m_thisMessageOutput.use_count() == 1)
{
// Last instance, deregister the handler // Last instance, deregister the handler
qInstallMessageHandler(0); qInstallMessageHandler(0);
m_thisMessageOutput.reset(); m_thisMessageOutput.reset();
} }
} }
void void MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
auto globalMsgOut = m_qtMessageOutputForSharing.lock(); auto globalMsgOut = m_qtMessageOutputForSharing.lock();
@ -50,23 +51,20 @@ MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &conte
m_previousHandler(type, context, msg); m_previousHandler(type, context, msg);
} }
QString QString MonitorQtOutput::qtOuput()
MonitorQtOutput::qtOuput()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
assert(m_thisMessageOutput->length() >= m_start); assert(m_thisMessageOutput->length() >= m_start);
return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start); return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start);
} }
void void MonitorQtOutput::restartCapturing()
MonitorQtOutput::restartCapturing()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
// Ensure the messageHandler is installed. Foun to be reset at test initializaiton // Ensure the messageHandler is installed. Foun to be reset at test initializaiton
auto prev = qInstallMessageHandler(qtMessageOutput); auto prev = qInstallMessageHandler(qtMessageOutput);
if(prev != qtMessageOutput) if(prev != qtMessageOutput) m_previousHandler = prev;
m_previousHandler = prev;
m_start = m_thisMessageOutput->length(); m_start = m_thisMessageOutput->length();
} }
} } // namespace Status::Testing

View File

@ -6,7 +6,8 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
namespace Status::Testing { namespace Status::Testing
{
/// ///
/// \brief Monitor output for tests and declaratively control message handler availability /// \brief Monitor output for tests and declaratively control message handler availability
@ -46,4 +47,4 @@ private:
int m_start = 0; int m_start = 0;
}; };
} } // namespace Status::Testing

View File

@ -7,7 +7,8 @@
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
/// Controlls asset for an account using hardcoded network and token lists /// Controlls asset for an account using hardcoded network and token lists
/// ///

View File

@ -6,7 +6,8 @@
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
class DerivedWalletAddress : public QObject class DerivedWalletAddress : public QObject
{ {
@ -22,7 +23,10 @@ public:
QString address() const; QString address() const;
const WalletGo::DerivedAddress &data() const { return m_derivedAddress; }; const WalletGo::DerivedAddress& data() const
{
return m_derivedAddress;
};
bool alreadyCreated() const; bool alreadyCreated() const;
@ -32,4 +36,4 @@ private:
using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>; using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>;
} } // namespace Status::Wallet

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
#include "Status/Wallet/WalletAccount.h"
#include "Status/Wallet/DerivedWalletAddress.h" #include "Status/Wallet/DerivedWalletAddress.h"
#include "Status/Wallet/WalletAccount.h"
#include <Helpers/QObjectVectorModel.h> #include <Helpers/QObjectVectorModel.h>
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
/// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath /// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath
/// and \c customDerivationPath; \see connascence.io/value /// and \c customDerivationPath; \see connascence.io/value
@ -20,7 +21,8 @@ class NewWalletAccountController: public QObject
Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT) Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel* currentDerivedAddressModel READ currentDerivedAddressModel CONSTANT) Q_PROPERTY(QAbstractItemModel* currentDerivedAddressModel READ currentDerivedAddressModel CONSTANT)
Q_PROPERTY(DerivedWalletAddress* selectedDerivedAddress READ selectedDerivedAddress WRITE setSelectedDerivedAddress NOTIFY selectedDerivedAddressChanged) Q_PROPERTY(DerivedWalletAddress* selectedDerivedAddress READ selectedDerivedAddress WRITE setSelectedDerivedAddress
NOTIFY selectedDerivedAddressChanged)
Q_PROPERTY(int derivedAddressIndex MEMBER m_derivedAddressIndex NOTIFY selectedDerivedAddressChanged) Q_PROPERTY(int derivedAddressIndex MEMBER m_derivedAddressIndex NOTIFY selectedDerivedAddressChanged)
Q_PROPERTY(QString derivationPath READ derivationPath WRITE setDerivationPath NOTIFY derivationPathChanged) Q_PROPERTY(QString derivationPath READ derivationPath WRITE setDerivationPath NOTIFY derivationPathChanged)
@ -39,14 +41,14 @@ public:
void setDerivationPath(const QString& newDerivationPath); void setDerivationPath(const QString& newDerivationPath);
/// \see \c accountCreatedStatus for async result /// \see \c accountCreatedStatus for async result
Q_INVOKABLE void createAccountAsync(const QString &password, const QString &name, Q_INVOKABLE void createAccountAsync(const QString& password,
const QColor &color, const QString &path, const QString& name,
const QColor& color,
const QString& path,
const Status::Wallet::WalletAccount* derivedFrom); const Status::Wallet::WalletAccount* derivedFrom);
/// \see \c accountCreatedStatus for async result /// \see \c accountCreatedStatus for async result
Q_INVOKABLE void addWatchOnlyAccountAsync(const QString &address, const QString &name, Q_INVOKABLE void addWatchOnlyAccountAsync(const QString& address, const QString& name, const QColor& color);
const QColor &color);
/// \returns \c false if fails (due to incomplete user input) /// \returns \c false if fails (due to incomplete user input)
Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString& password, Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString& password,

View File

@ -4,7 +4,8 @@
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
class SavedAddress : public QObject class SavedAddress : public QObject
{ {
@ -16,8 +17,7 @@ class SavedAddress : public QObject
Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
public: public:
SavedAddress(const QString &address = QString(), const QString &name = QString(), SavedAddress(const QString& address = QString(), const QString& name = QString(), QObject* parent = nullptr);
QObject *parent = nullptr);
const QString& address() const; const QString& address() const;
const QString& name() const; const QString& name() const;
@ -28,4 +28,4 @@ private:
}; };
using SavedAddressPtr = std::shared_ptr<SavedAddress>; using SavedAddressPtr = std::shared_ptr<SavedAddress>;
} } // namespace Status::Wallet

View File

@ -6,7 +6,8 @@
namespace GoAccounts = Status::StatusGo::Accounts; namespace GoAccounts = Status::StatusGo::Accounts;
namespace Status::Wallet { namespace Status::Wallet
{
class WalletAccount : public QObject class WalletAccount : public QObject
{ {
@ -27,7 +28,10 @@ public:
QColor color() const; QColor color() const;
const GoAccounts::ChatOrWalletAccount &data() const { return m_data; }; const GoAccounts::ChatOrWalletAccount& data() const
{
return m_data;
};
private: private:
const GoAccounts::ChatOrWalletAccount m_data; const GoAccounts::ChatOrWalletAccount m_data;
@ -36,4 +40,4 @@ private:
using WalletAccountPtr = std::shared_ptr<WalletAccount>; using WalletAccountPtr = std::shared_ptr<WalletAccount>;
using WalletAccounts = std::vector<WalletAccount>; using WalletAccounts = std::vector<WalletAccount>;
} } // namespace Status::Wallet

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <StatusGo/Wallet/Token.h>
#include <StatusGo/Wallet/BigInt.h> #include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Wallet/Token.h>
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
class WalletAsset : public QObject class WalletAsset : public QObject
{ {
@ -42,4 +43,4 @@ private:
int m_count; int m_count;
}; };
} } // namespace Status::Wallet

View File

@ -11,7 +11,8 @@
class QQmlEngine; class QQmlEngine;
class QJSEngine; class QJSEngine;
namespace Status::Wallet { namespace Status::Wallet
{
class NewWalletAccountController; class NewWalletAccountController;
class AccountAssetsController; class AccountAssetsController;
@ -50,7 +51,8 @@ public:
Q_INVOKABLE void setCurrentAccountIndex(int index); Q_INVOKABLE void setCurrentAccountIndex(int index);
/// \note caller (QML) takes ownership of the returned instance /// \note caller (QML) takes ownership of the returned instance
Q_INVOKABLE Status::Wallet::AccountAssetsController* createAccountAssetsController(Status::Wallet::WalletAccount* account); Q_INVOKABLE Status::Wallet::AccountAssetsController*
createAccountAssetsController(Status::Wallet::WalletAccount* account);
signals: signals:
void currentAccountChanged(); void currentAccountChanged();

View File

@ -1,8 +1,8 @@
#include "Status/Wallet/AccountAssetsController.h" #include "Status/Wallet/AccountAssetsController.h"
#include <StatusGo/Wallet/WalletApi.h>
#include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Metadata/api_response.h> #include <StatusGo/Metadata/api_response.h>
#include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Wallet/WalletApi.h>
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
@ -10,7 +10,8 @@
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent) AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent)
: QObject(parent) : QObject(parent)
@ -30,49 +31,61 @@ AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject
}) })
.onFailed([this] { .onFailed([this] {
emit assetsReadyChanged(); emit assetsReadyChanged();
qWarning() << "Unexpected failure while executing updateBalances for account" << m_address->data().address.get(); qWarning() << "Unexpected failure while executing updateBalances for account"
<< m_address->data().address.get();
}); });
} }
void AccountAssetsController::updateBalances() void AccountAssetsController::updateBalances()
{ {
const StatusGo::Accounts::EOAddress& address = m_address->data().address; const StatusGo::Accounts::EOAddress& address = m_address->data().address;
if(m_assets->size() > 0) if(m_assets->size() > 0) m_assets->clear();
m_assets->clear();
// TODO: this should be moved to status-go and exposed as "get balances for account and tokens with currency" // TODO: this should be moved to status-go and exposed as "get balances for account and tokens with currency"
std::map<Accounts::EOAddress, StatusGo::Wallet::Token> tokens; std::map<Accounts::EOAddress, StatusGo::Wallet::Token> tokens;
std::vector<WalletGo::ChainID> chainIds; std::vector<WalletGo::ChainID> chainIds;
auto allNets = WalletGo::getEthereumChains(false); auto allNets = WalletGo::getEthereumChains(false);
for(const auto &net : allNets) { for(const auto& net : allNets)
if(net.enabled && !net.isTest) { {
try { if(net.enabled && !net.isTest)
{
try
{
const auto allTokens = WalletGo::getTokens(net.chainId); const auto allTokens = WalletGo::getTokens(net.chainId);
for(const auto& tokenToMove : allTokens) { for(const auto& tokenToMove : allTokens)
if(isTokenEnabled(tokenToMove)) { {
if(isTokenEnabled(tokenToMove))
{
auto address = tokenToMove.address; auto address = tokenToMove.address;
tokens.emplace(std::move(address), std::move(tokenToMove)); tokens.emplace(std::move(address), std::move(tokenToMove));
} }
} }
chainIds.push_back(net.chainId); chainIds.push_back(net.chainId);
} }
catch (const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
// Most probably "no tokens for this network" // Most probably "no tokens for this network"
if(e.errorResponse().error.message.compare("no tokens for this network") != 0) if(e.errorResponse().error.message.compare("no tokens for this network") != 0)
qWarning() << "Failed retrieving tokens for network" << net.chainId.get() << "; error" << e.errorResponse().error.message.c_str(); qWarning() << "Failed retrieving tokens for network" << net.chainId.get() << "; error"
<< e.errorResponse().error.message.c_str();
continue; continue;
} }
} }
} }
auto accountBalances = WalletGo::getTokensBalancesForChainIDs(chainIds, { address }, std::move(Helpers::getKeys(tokens))); auto accountBalances =
if(accountBalances.size() == 1) { WalletGo::getTokensBalancesForChainIDs(chainIds, {address}, std::move(Helpers::getKeys(tokens)));
for(const auto& accountAndBalance : accountBalances.begin()->second) { if(accountBalances.size() == 1)
auto asset = Helpers::makeSharedQObject<WalletAsset>(std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second); {
for(const auto& accountAndBalance : accountBalances.begin()->second)
{
auto asset = Helpers::makeSharedQObject<WalletAsset>(
std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second);
m_assets->push_back(asset); m_assets->push_back(asset);
} }
} }
else else
qWarning() << "Failed fetching balances for account" << address.get() << "; balances count" << accountBalances.size(); qWarning() << "Failed fetching balances for account" << address.get() << "; balances count"
<< accountBalances.size();
} }
bool AccountAssetsController::isTokenEnabled(const StatusGo::Wallet::Token& token) const bool AccountAssetsController::isTokenEnabled(const StatusGo::Wallet::Token& token) const
@ -97,4 +110,4 @@ bool AccountAssetsController::assetsReady() const
return m_assetsReady; return m_assetsReady;
} }
} } // namespace Status::Wallet

View File

@ -1,12 +1,12 @@
#include "DerivedWalletAddress.h" #include "DerivedWalletAddress.h"
namespace Status::Wallet { namespace Status::Wallet
{
DerivedWalletAddress::DerivedWalletAddress(WalletGo::DerivedAddress address, QObject* parent) DerivedWalletAddress::DerivedWalletAddress(WalletGo::DerivedAddress address, QObject* parent)
: QObject{parent} : QObject{parent}
, m_derivedAddress{std::move(address)} , m_derivedAddress{std::move(address)}
{ { }
}
QString DerivedWalletAddress::address() const QString DerivedWalletAddress::address() const
{ {
@ -18,4 +18,4 @@ bool DerivedWalletAddress::alreadyCreated() const
return m_derivedAddress.alreadyCreated; return m_derivedAddress.alreadyCreated;
} }
} } // namespace Status::Wallet

View File

@ -2,17 +2,17 @@
#include <StatusGo/Wallet/WalletApi.h> #include <StatusGo/Wallet/WalletApi.h>
#include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
#include <StatusGo/Metadata/api_response.h> #include <StatusGo/Metadata/api_response.h>
#include <StatusGo/Utils.h>
#include <StatusGo/Types.h> #include <StatusGo/Types.h>
#include <StatusGo/Utils.h>
#include <Onboarding/Common/Constants.h> #include <Onboarding/Common/Constants.h>
#include <QQmlEngine>
#include <QJSEngine> #include <QJSEngine>
#include <QQmlEngine>
#include <ranges> #include <ranges>
@ -21,15 +21,16 @@ namespace WalletGo = Status::StatusGo::Wallet;
namespace UtilsSG = Status::StatusGo::Utils; namespace UtilsSG = Status::StatusGo::Utils;
namespace StatusGo = Status::StatusGo; namespace StatusGo = Status::StatusGo;
namespace Status::Wallet { namespace Status::Wallet
{
NewWalletAccountController::NewWalletAccountController(std::shared_ptr<Helpers::QObjectVectorModel<WalletAccount>> accounts) NewWalletAccountController::NewWalletAccountController(
std::shared_ptr<Helpers::QObjectVectorModel<WalletAccount>> accounts)
: m_accounts(accounts) : m_accounts(accounts)
, m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account") , m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account")
, m_derivedAddress("derivedAddress") , m_derivedAddress("derivedAddress")
, m_derivationPath(Status::Constants::General::PathWalletRoot) , m_derivationPath(Status::Constants::General::PathWalletRoot)
{ { }
}
QAbstractListModel* NewWalletAccountController::mainAccountsModel() QAbstractListModel* NewWalletAccountController::mainAccountsModel()
{ {
@ -48,8 +49,7 @@ QString NewWalletAccountController::derivationPath() const
void NewWalletAccountController::setDerivationPath(const QString& newDerivationPath) void NewWalletAccountController::setDerivationPath(const QString& newDerivationPath)
{ {
if (m_derivationPath.get() == newDerivationPath) if(m_derivationPath.get() == newDerivationPath) return;
return;
m_derivationPath = GoAccounts::DerivationPath(newDerivationPath); m_derivationPath = GoAccounts::DerivationPath(newDerivationPath);
emit derivationPathChanged(); emit derivationPathChanged();
@ -59,36 +59,46 @@ void NewWalletAccountController::setDerivationPath(const QString &newDerivationP
if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated()) if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated())
updateSelectedDerivedAddress(index, derivedPath); updateSelectedDerivedAddress(index, derivedPath);
if(m_customDerivationPath != oldCustom) if(m_customDerivationPath != oldCustom) emit customDerivationPathChanged();
emit customDerivationPathChanged();
} }
void NewWalletAccountController::createAccountAsync(const QString &password, const QString &name, void NewWalletAccountController::createAccountAsync(const QString& password,
const QColor &color, const QString &path, const QString& name,
const QColor& color,
const QString& path,
const WalletAccount* derivedFrom) const WalletAccount* derivedFrom)
{ {
try { try
{
GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)), GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
name, color, "", GoAccounts::DerivationPath(path), name,
color,
"",
GoAccounts::DerivationPath(path),
derivedFrom->data().derivedFrom.value()); derivedFrom->data().derivedFrom.value());
addNewlyCreatedAccount(findMissingAccount()); addNewlyCreatedAccount(findMissingAccount());
} }
catch(const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str(); qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false); emit accountCreatedStatus(false);
} }
} }
void NewWalletAccountController::addWatchOnlyAccountAsync(const QString &address, const QString &name, const QColor &color) void NewWalletAccountController::addWatchOnlyAccountAsync(const QString& address,
const QString& name,
const QColor& color)
{
try
{ {
try {
GoAccounts::addAccountWatch(Accounts::EOAddress(address), name, color, u""_qs); GoAccounts::addAccountWatch(Accounts::EOAddress(address), name, color, u""_qs);
addNewlyCreatedAccount(findMissingAccount()); addNewlyCreatedAccount(findMissingAccount());
} }
catch(const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str(); qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false); emit accountCreatedStatus(false);
@ -99,24 +109,30 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
const WalletAccount* derivedFrom) const WalletAccount* derivedFrom)
{ {
assert(derivedFrom->data().derivedFrom.has_value()); assert(derivedFrom->data().derivedFrom.has_value());
try { try
{
int currentPage = 1; int currentPage = 1;
int foundIndex = -1; int foundIndex = -1;
int currentIndex = 0; int currentIndex = 0;
auto maxPageCount = static_cast<int>(std::ceil(static_cast<double>(m_maxDerivedAddresses)/static_cast<double>(m_derivedAddressesPageSize))); auto maxPageCount = static_cast<int>(
std::ceil(static_cast<double>(m_maxDerivedAddresses) / static_cast<double>(m_derivedAddressesPageSize)));
std::shared_ptr<DerivedWalletAddress> foundEntry; std::shared_ptr<DerivedWalletAddress> foundEntry;
while(currentPage <= maxPageCount && foundIndex < 0) { while(currentPage <= maxPageCount && foundIndex < 0)
{
auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)), auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
derivedFrom->data().derivedFrom.value(), derivedFrom->data().derivedFrom.value(),
Status::Constants::General::PathWalletRoot, Status::Constants::General::PathWalletRoot,
m_derivedAddressesPageSize, currentPage); m_derivedAddressesPageSize,
currentPage);
if((currentIndex + all.size()) > m_derivedAddress.size()) if((currentIndex + all.size()) > m_derivedAddress.size())
m_derivedAddress.resize(currentIndex + all.size()); m_derivedAddress.resize(currentIndex + all.size());
for(auto newDerived : all) { for(auto newDerived : all)
{
auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived)); auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived));
m_derivedAddress.set(currentIndex, newEntry); m_derivedAddress.set(currentIndex, newEntry);
if(foundIndex < 0 && !newEntry->data().alreadyCreated) { if(foundIndex < 0 && !newEntry->data().alreadyCreated)
{
foundIndex = currentIndex; foundIndex = currentIndex;
foundEntry = newEntry; foundEntry = newEntry;
} }
@ -124,11 +140,12 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
} }
currentPage++; currentPage++;
} }
if(foundIndex > 0) if(foundIndex > 0) updateSelectedDerivedAddress(foundIndex, foundEntry);
updateSelectedDerivedAddress(foundIndex, foundEntry);
return true; return true;
} catch(const StatusGo::CallPrivateRpcError &e) { }
catch(const StatusGo::CallPrivateRpcError& e)
{
return false; return false;
} }
} }
@ -143,8 +160,9 @@ WalletAccountPtr NewWalletAccountController::findMissingAccount()
auto accounts = GoAccounts::getAccounts(); auto accounts = GoAccounts::getAccounts();
// TODO: consider using a QObjectSetModel and a proxy sort model on top instead // TODO: consider using a QObjectSetModel and a proxy sort model on top instead
auto it = std::find_if(accounts.begin(), accounts.end(), [this](const auto& a) { auto it = std::find_if(accounts.begin(), accounts.end(), [this](const auto& a) {
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(), return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(), [&a](const auto& eA) {
[&a](const auto &eA) { return a.address == eA->data().address; }); return a.address == eA->data().address;
});
}); });
return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr; return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr;
} }
@ -175,29 +193,34 @@ DerivedWalletAddress *NewWalletAccountController::selectedDerivedAddress() const
void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress) void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress)
{ {
if (m_selectedDerivedAddress.get() == newSelectedDerivedAddress) if(m_selectedDerivedAddress.get() == newSelectedDerivedAddress) return;
return;
auto& objs = m_derivedAddress.objects(); auto& objs = m_derivedAddress.objects();
auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto &a) { return a.get() == newSelectedDerivedAddress; }); auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto& a) {
return a.get() == newSelectedDerivedAddress;
});
updateSelectedDerivedAddress(std::distance(objs.begin(), foundIt), *foundIt); updateSelectedDerivedAddress(std::distance(objs.begin(), foundIt), *foundIt);
} }
void NewWalletAccountController::updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry) { void NewWalletAccountController::updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry)
{
m_derivedAddressIndex = index; m_derivedAddressIndex = index;
m_selectedDerivedAddress = newEntry; m_selectedDerivedAddress = newEntry;
emit selectedDerivedAddressChanged(); emit selectedDerivedAddressChanged();
if(m_derivationPath != newEntry->data().path) { if(m_derivationPath != newEntry->data().path)
{
m_derivationPath = newEntry->data().path; m_derivationPath = newEntry->data().path;
emit derivationPathChanged(); emit derivationPathChanged();
} }
} }
std::tuple<DerivedWalletAddressPtr, int> NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath &derivationPath) { std::tuple<DerivedWalletAddressPtr, int>
NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath& derivationPath)
{
const auto& c = m_derivedAddress.objects(); const auto& c = m_derivedAddress.objects();
auto foundIt = find_if(c.begin(), c.end(), [&derivationPath](const auto &a) { return a->data().path == derivationPath; }); auto foundIt =
if(foundIt != c.end()) find_if(c.begin(), c.end(), [&derivationPath](const auto& a) { return a->data().path == derivationPath; });
return {*foundIt, std::distance(c.begin(), foundIt)}; if(foundIt != c.end()) return {*foundIt, std::distance(c.begin(), foundIt)};
return {nullptr, -1}; return {nullptr, -1};
} }
} } // namespace Status::Wallet

View File

@ -7,8 +7,7 @@ SavedAddress::SavedAddress(const QString &address, const QString &name, QObject
: QObject(parent) : QObject(parent)
, m_address(address) , m_address(address)
, m_name(name) , m_name(name)
{ { }
}
const QString& SavedAddress::address() const const QString& SavedAddress::address() const
{ {
@ -20,4 +19,4 @@ const QString& SavedAddress::name() const
return m_name; return m_name;
} }
} } // namespace Status::Wallet

View File

@ -10,8 +10,7 @@ namespace Status::Wallet
SavedAddressesController::SavedAddressesController(QObject* parent) SavedAddressesController::SavedAddressesController(QObject* parent)
: QObject(parent) : QObject(parent)
, m_savedAddresses(Helpers::makeSharedQObject<SavedAddressesModel>("savedAddress")) , m_savedAddresses(Helpers::makeSharedQObject<SavedAddressesModel>("savedAddress"))
{ { }
}
QAbstractListModel* SavedAddressesController::savedAddresses() const QAbstractListModel* SavedAddressesController::savedAddresses() const
{ {
@ -28,8 +27,7 @@ void SavedAddressesController::saveAddress(const QString &address, const QString
} }
catch(const StatusGo::CallPrivateRpcError& rpcError) catch(const StatusGo::CallPrivateRpcError& rpcError)
{ {
qWarning() << "StatusGoQt.saveAddress error: " << qWarning() << "StatusGoQt.saveAddress error: " << rpcError.errorResponse().error.message.c_str();
rpcError.errorResponse().error.message.c_str();
emit error(SaveAddressError); emit error(SaveAddressError);
} }
@ -50,8 +48,7 @@ void SavedAddressesController::refresh()
} }
catch(const StatusGo::CallPrivateRpcError& rpcError) catch(const StatusGo::CallPrivateRpcError& rpcError)
{ {
qWarning() << "StatusGoQt.getSavedAddresses error: " << qWarning() << "StatusGoQt.getSavedAddresses error: " << rpcError.errorResponse().error.message.c_str();
rpcError.errorResponse().error.message.c_str();
emit error(RetrieveSavedAddressesError); emit error(RetrieveSavedAddressesError);
} }
m_savedAddresses->reset(savedAddresses); m_savedAddresses->reset(savedAddresses);

Some files were not shown because too many files have changed in this diff Show More