2020-10-07 10:36:04 +00:00
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2020-12-26 19:56:06 +00:00
|
|
|
// Copyright (c) 2020-2021, The Monero Project.
|
2020-10-07 10:36:04 +00:00
|
|
|
|
|
|
|
#include <QObject>
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QScreen>
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
#include "wsclient.h"
|
|
|
|
#include "appcontext.h"
|
|
|
|
|
2022-03-14 16:55:27 +00:00
|
|
|
WSClient::WSClient(AppContext *ctx, QObject *parent) :
|
2020-10-07 10:36:04 +00:00
|
|
|
QObject(parent),
|
|
|
|
m_ctx(ctx) {
|
2022-03-14 16:55:27 +00:00
|
|
|
// this class connects to `https://git.wownero.com/wowlet/wowlet-backend/`
|
2020-10-07 10:36:04 +00:00
|
|
|
connect(&this->webSocket, &QWebSocket::binaryMessageReceived, this, &WSClient::onbinaryMessageReceived);
|
|
|
|
connect(&this->webSocket, &QWebSocket::connected, this, &WSClient::onConnected);
|
|
|
|
connect(&this->webSocket, &QWebSocket::disconnected, this, &WSClient::closed);
|
|
|
|
connect(&this->webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WSClient::onError);
|
|
|
|
|
2022-03-14 16:55:27 +00:00
|
|
|
m_tor = m_ctx->backendHost.contains(".onion");
|
2020-12-22 22:46:01 +00:00
|
|
|
|
2022-03-14 16:55:27 +00:00
|
|
|
// keep-alive
|
2020-12-22 22:46:01 +00:00
|
|
|
connect(&m_pingTimer, &QTimer::timeout, [this]{
|
|
|
|
if (this->webSocket.state() == QAbstractSocket::ConnectedState)
|
|
|
|
this->webSocket.ping();
|
|
|
|
});
|
|
|
|
m_pingTimer.setInterval(30 * 1000);
|
|
|
|
m_pingTimer.start();
|
2020-10-07 10:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::sendMsg(const QByteArray &data) {
|
|
|
|
auto state = this->webSocket.state();
|
|
|
|
if(state == QAbstractSocket::ConnectedState)
|
|
|
|
this->webSocket.sendBinaryMessage(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::start() {
|
|
|
|
// connect & reconnect on errors/close
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
qDebug() << "WebSocket connect:" << url.url();
|
|
|
|
#endif
|
|
|
|
if((m_tor && this->m_ctx->tor->torConnected) || !m_tor)
|
2022-03-14 16:55:27 +00:00
|
|
|
this->webSocket.open(QString("%1/ws").arg(m_ctx->backendWSUrl));
|
2020-10-07 10:36:04 +00:00
|
|
|
|
|
|
|
if(!this->m_connectionTimer.isActive()) {
|
|
|
|
connect(&this->m_connectionTimer, &QTimer::timeout, this, &WSClient::checkConnection);
|
|
|
|
this->m_connectionTimer.start(2000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::checkConnection() {
|
|
|
|
if(m_tor && !this->m_ctx->tor->torConnected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto state = this->webSocket.state();
|
|
|
|
if(state == QAbstractSocket::UnconnectedState) {
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
qDebug() << "WebSocket reconnect";
|
|
|
|
#endif
|
|
|
|
this->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::onConnected() {
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
qDebug() << "WebSocket connected";
|
|
|
|
#endif
|
|
|
|
emit connectionEstablished();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::onError(QAbstractSocket::SocketError error) {
|
|
|
|
qCritical() << "WebSocket error: " << error;
|
|
|
|
auto state = this->webSocket.state();
|
|
|
|
if(state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState)
|
|
|
|
this->webSocket.abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSClient::onbinaryMessageReceived(const QByteArray &message) {
|
|
|
|
#ifdef QT_DEBUG
|
2021-03-27 18:59:21 +00:00
|
|
|
qDebug() << "WebSocket (client) received:" << message;
|
2020-10-07 10:36:04 +00:00
|
|
|
#endif
|
|
|
|
if (!Utils::validateJSON(message)) {
|
|
|
|
qCritical() << "Could not interpret WebSocket message as JSON";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(message);
|
|
|
|
QJsonObject object = doc.object();
|
|
|
|
if(!object.contains("cmd") || !object.contains("data")) {
|
|
|
|
qCritical() << "Invalid WebSocket message received";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit WSMessage(object);
|
|
|
|
}
|