1
0
forked from BRT/arc
arc/services/net/NetworkService.cpp
slava 5cb32ec4f1 Refactor and enhance device and event handling logic
Refactored `DeviceScreener`, `NetworkService`, and event-related logic for improved maintainability and flexibility. Introduced `EventHandler` for thread management and made changes to include configurable URLs via `config.ini`. Modified database schema to support device-level event linking.
2025-05-22 21:33:25 +07:00

214 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "NetworkService.h"
#include <QUrlQuery>
#include <QHttpPart>
#include <QNetworkReply>
#include <QJsonObject>
#include <QJsonArray>
#include <QThread>
#include <QSettings>
#include <QTimer>
#include "dao/AccountDAO.h"
#include "dao/EventDAO.h"
#include "dao/TransactionDAO.h"
#include "db/EventInfo.h"
NetworkService::NetworkService(QObject *parent) : QObject(parent) {
const QSettings settings("config.ini", QSettings::IniFormat);
m_urlAccountUpdate = settings.value("net/accountUpdate").toString();
m_urlPaymentsGet = settings.value("net/paymentsGet").toString();
m_urlTransactionUpdate = settings.value("net/transactionUpdate").toString();
m_urlTransactionInsert = settings.value("net/transactionInsert").toString();
m_manager = new QNetworkAccessManager(this);
}
NetworkService::~NetworkService() = default;
// FIXME доделать работу с экстра
void NetworkService::addExtra(const QString &key, const QVariant &value) {
m_extraData[key] = value;
}
void addFormField(QHttpMultiPart *multiPart, const QString &fieldName, const QString &fieldValue) {
QHttpPart formField;
formField.setHeader(
QNetworkRequest::ContentDispositionHeader,QStringLiteral("form-data; name=\"%1\"").arg(fieldName)
);
formField.setBody(fieldValue.toUtf8());
multiPart->append(formField);
}
void addFormMetadata(QHttpMultiPart *multiPart, const QByteArray &fieldValue) {
QHttpPart jsonPart;
jsonPart.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="metadata")");
jsonPart.setBody(fieldValue);
multiPart->append(jsonPart);
}
QJsonValue NetworkService::post(QHttpMultiPart *multiPart, const QString &path) {
const QUrl url(path);
const QNetworkRequest request(url);
QNetworkReply *reply = m_manager->post(request, multiPart);
multiPart->setParent(reply);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::errorOccurred, [&loop](QNetworkReply::NetworkError) {
loop.quit();
});
loop.exec(); // <- здесь и запускается event-loop потока
QJsonValue result;
if (reply->error() == QNetworkReply::NoError) {
const QByteArray raw = reply->readAll();
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
if (err.error == QJsonParseError::NoError && doc.isObject()) {
const QJsonObject root = doc.object();
if (root.value("success").toBool()) {
result = root.value("data");
} else {
qCritical() << "Ошибка:" << root;
}
}
} else {
qCritical() << "Ошибка:" << reply->errorString() << path;
}
reply->deleteLater();
return result;
}
QJsonArray NetworkService::get(const QString &path, const QMap<QString, QString> &params) {
QUrl url(path);
QUrlQuery query;
for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
query.addQueryItem(it.key(), it.value());
}
url.setQuery(query);
const QNetworkRequest request(url);
QNetworkReply *reply = m_manager->get(request);
QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> guard(reply);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::errorOccurred, [&loop](QNetworkReply::NetworkError) {
loop.quit();
});
loop.exec(); // <- здесь и запускается event-loop потока
QJsonArray result;
if (reply->error() == QNetworkReply::NoError) {
const QByteArray raw = reply->readAll();
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
if (err.error == QJsonParseError::NoError && doc.isObject()) {
const QJsonObject root = doc.object();
if (root.value("success").toBool()) {
result = root.value("data").toArray();
} else {
qWarning() << "Ошибка:" << root;
}
}
} else {
qWarning() << "Ошибка:" << reply->errorString();
}
reply->deleteLater();
return result;
}
void NetworkService::postAccountsData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
const bool isSuccess = post(multiPart, m_urlAccountUpdate).toBool();
if (!isSuccess) {
qCritical() << "Cant post accounts data";
}
emit finished();
}
void NetworkService::getPayments() {
QMap<QString, QString> params;
params["desktopUniqueName"] = m_desktopId;
const QJsonArray data = get(m_urlPaymentsGet, params);
for (QJsonValue item: data) {
QJsonObject obj = item.toObject();
EventInfo eventInfo;
eventInfo.status = EventStatus::Wait;
eventInfo.externalId = obj["id"].toInt();
eventInfo.amount = obj["amount"].toDouble();
eventInfo.bankName = obj["bankName"].toString();
eventInfo.phone = obj["phone"].toString();
QString deviceId = obj["deviceId"].toString();
QString appName = obj["appName"].toString();
QString lastNumbers = obj["lastNumbers"].toString();
AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumbers);
eventInfo.accountId = account.id;
eventInfo.deviceId = account.deviceId;
if (int id = EventDAO::insertEvent(eventInfo); id == -1) {
qCritical() << "Cant insert event: " << eventInfo.externalId;
}
}
if (!m_running) {
emit finished();
}
}
void NetworkService::updateTransactionData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
const bool isSuccess = post(multiPart, m_urlTransactionUpdate).toBool();
if (!isSuccess) {
qCritical() << "Cant update transaction: updateTransactionData";
}
emit finished();
}
void NetworkService::insertTransactionData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
const int id = post(multiPart, m_urlTransactionInsert).toInt();
if (id > 0) {
const int transactionId = m_extraData["transactionId"].toInt();
if (!TransactionDAO::updateExternalTransactionId(transactionId, id)) {
qCritical() << "Cant update transaction id: " << id;
}
}
emit finished();
}
void NetworkService::start() {
QTimer *poller = new QTimer(this);
poller->setInterval(1000);
connect(poller, &QTimer::timeout, this, &NetworkService::getPayments);
poller->start();
}
void NetworkService::stop() {
m_running = false;
}