You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wowlet/src/utils/nodes.h

138 lines
3.9 KiB

// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
#ifndef WOWLET_NODES_H
#define WOWLET_NODES_H
#include <QTimer>
#include <QRegExp>
#include <QApplication>
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "model/NodeModel.h"
#include "utils/utils.h"
#include "utils/config.h"
enum NodeSource {
websocket = 0,
custom
};
struct WowletNode {
explicit WowletNode(QString _address = "", int height = 0, int target_height = 0, bool online = false)
: height(height), target_height(target_height), online(online){
// wonky ipv4/host parsing, should be fine(tm)(c).
if(_address.isEmpty()) return;
if(_address.contains("https://")) {
this->isHttps = true;
}
_address = _address.replace("https://", "");
_address = _address.replace("http://", "");
if(_address.contains("@")){ // authentication, user/pass
const auto spl = _address.split("@");
const auto &creds = spl.at(0);
if(creds.contains(":")) {
const auto _spl = creds.split(":");
this->username = _spl.at(0).trimmed().replace(" ", "");
this->password = _spl.at(1).trimmed().replace(" ", "");
}
_address = spl.at(1);
}
if(!_address.contains(":"))
_address += ":18081";
this->address = _address;
if(this->address.contains(".onion"))
tor = true;
this->full = this->generateFull();
};
QString address;
QString full;
int height;
int target_height;
bool online = false;
QString username;
QString password;
bool cached = false;
bool custom = false;
bool tor = false;
bool isConnecting = false;
bool isActive = false;
bool isHttps = false;
QString generateFull() {
QString auth;
if(!this->username.isEmpty() && !this->password.isEmpty())
auth = QString("%1:%2@").arg(this->username).arg(this->password);
return QString("%1%2").arg(auth).arg(this->address);
}
QString as_url() {
return QString("%1://%2/get_info").arg(this->isHttps ? "https": "http",this->full);
}
bool operator == (const WowletNode &other) const {
return this->full == other.full;
}
};
class Nodes : public QObject {
Q_OBJECT
public:
explicit Nodes(AppContext *ctx, QNetworkAccessManager *networkAccessManager, QObject *parent = nullptr);
void loadConfig();
void writeConfig();
NodeSource source();
WowletNode connection();
QList<WowletNode> customNodes();
NodeModel *modelWebsocket;
NodeModel *modelCustom;
public slots:
void connectToNode();
void connectToNode(const WowletNode &node);
void onWSNodesReceived(const QList<QSharedPointer<WowletNode>>& nodes);
void onNodeSourceChanged(NodeSource nodeSource);
void setCustomNodes(const QList<WowletNode>& nodes);
void autoConnect(bool forceReconnect = false);
signals:
void WSNodeExhausted();
void nodeExhausted();
void updateStatus(const QString &msg);
private:
AppContext *m_ctx = nullptr;
NodeSource m_source = NodeSource::websocket;
QNetworkAccessManager *m_networkAccessManager = nullptr;
QJsonObject m_configJson;
QStringList m_recentFailures;
QList<WowletNode> m_customNodes;
QList<WowletNode> m_websocketNodes;
WowletNode m_connection; // current active connection, if any
bool m_wsNodesReceived = false;
bool m_wsExhaustedWarningEmitted = true;
bool m_customExhaustedWarningEmitted = true;
bool m_enableAutoconnect = true;
WowletNode pickEligibleNode();
void updateModels();
void resetLocalState();
void exhausted();
void WSNodeExhaustedWarning();
void nodeExhaustedWarning();
int modeHeight(const QList<WowletNode> &nodes);
};
#endif //WOWLET_NODES_H