244 lines
8.7 KiB
C++
244 lines
8.7 KiB
C++
#include "EventHandler.h"
|
|
|
|
#include <QJsonObject>
|
|
#include <QMap>
|
|
#include <QThread>
|
|
#include <QTimer>
|
|
|
|
#include "dao/AccountDAO.h"
|
|
#include "dao/ApplicationDAO.h"
|
|
#include "dao/DeviceDAO.h"
|
|
#include "dao/EventDAO.h"
|
|
#include "db/ApplicationInfo.h"
|
|
#include "net/NetworkService.h"
|
|
#include "birbank/GetLastDaysHistoryBirbankScript.h"
|
|
#include "ozon/LoginAndCheckAccountsScript.h"
|
|
#include "rshb/CommonScript.h"
|
|
#include "rshb/GetLastDaysHistoryScript.h"
|
|
#include "rshb/LoginAndCheckAccountsScript.h"
|
|
#include "rshb/PayByPhoneScript.h"
|
|
|
|
EventHandler::EventHandler(QObject *parent) : QObject(parent) {
|
|
m_checkTimer = new QTimer(this);
|
|
m_checkTimer->setInterval(1000);
|
|
connect(m_checkTimer, &QTimer::timeout, this, &EventHandler::checkAndRestart);
|
|
}
|
|
|
|
EventHandler::~EventHandler() = default;
|
|
|
|
void EventHandler::start() {
|
|
m_devices = DeviceDAO::getOnlineDeviceCodes();
|
|
|
|
clearAll();
|
|
// Запустим сразу потоки для всех ключей
|
|
for (auto &key: m_devices) {
|
|
startThreadForKey(key);
|
|
}
|
|
|
|
m_checkTimer->start();
|
|
}
|
|
|
|
void EventHandler::checkAndRestart() {
|
|
if (!m_running) {
|
|
return;
|
|
}
|
|
m_devices = DeviceDAO::getOnlineDeviceCodes();
|
|
|
|
for (const auto &key: m_devices) {
|
|
const QThread *thr = m_threads.value(key, nullptr);
|
|
if (!thr || !thr->isRunning()) {
|
|
startThreadForKey(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sendEventStatus(const QString &deviceId, const int externalId, const int eventId, const QString &status,
|
|
const QString &error) {
|
|
QJsonObject obj;
|
|
obj["id"] = externalId;
|
|
obj["externalId"] = eventId;
|
|
obj["status"] = status;
|
|
obj["error"] = error;
|
|
|
|
auto *paymentThread = new QThread;
|
|
auto *networkService = new NetworkService;
|
|
networkService->moveToThread(paymentThread);
|
|
networkService->setDeviceId(deviceId);
|
|
networkService->setPayload(QJsonDocument(obj).toJson());
|
|
QObject::connect(paymentThread, &QThread::started, networkService, &NetworkService::postEventStatus);
|
|
QObject::connect(networkService, &NetworkService::finished, paymentThread, &QThread::quit);
|
|
QObject::connect(networkService, &NetworkService::finished, networkService, &QObject::deleteLater);
|
|
QObject::connect(paymentThread, &QThread::finished, paymentThread, &QThread::deleteLater);
|
|
paymentThread->start();
|
|
}
|
|
|
|
void EventHandler::updateEventThread(const QString &key, const EventInfo &event, const QString &result) {
|
|
if (!result.isEmpty()) {
|
|
if (!EventDAO::updateEvent(event.id, EventStatus::Error, result)) {
|
|
qCritical() << "Cant update event: " << event.id;
|
|
} else {
|
|
sendEventStatus(
|
|
event.deviceId,
|
|
event.externalId,
|
|
event.id,
|
|
eventStatusToString(EventStatus::Error),
|
|
result
|
|
);
|
|
}
|
|
} else {
|
|
if (!EventDAO::updateEvent(event.id, EventStatus::Complete, "")) {
|
|
qCritical() << "Cant update event: " << event.id;
|
|
} else {
|
|
sendEventStatus(
|
|
event.deviceId,
|
|
event.externalId,
|
|
event.id,
|
|
eventStatusToString(EventStatus::Complete),
|
|
""
|
|
);
|
|
}
|
|
}
|
|
|
|
if (const auto tm = m_timers.take(key)) {
|
|
tm->stop();
|
|
tm->deleteLater();
|
|
}
|
|
m_threads.remove(key);
|
|
}
|
|
|
|
void EventHandler::startThreadForKey(const QString &key) {
|
|
const EventInfo event = EventDAO::getFirstWaitEventByDeviceId(key);
|
|
if (event.id == -1) {
|
|
return;
|
|
}
|
|
|
|
const AccountInfo account = AccountDAO::getAccountById(event.accountId);
|
|
const ApplicationInfo app = ApplicationDAO::getApplication(event.deviceId, account.appCode);
|
|
if (app.status != "active") {
|
|
return;
|
|
}
|
|
|
|
if (!EventDAO::updateEvent(event.id, EventStatus::InProgress, "")) {
|
|
qCritical() << "Cant update event: " << event.id;
|
|
return;
|
|
}
|
|
|
|
const auto thr = new QThread(this);
|
|
// qDebug() << "Start thread for key" << eventTypeToString(event.type);
|
|
if (event.type == EventType::History) {
|
|
if ("birbank" == account.appCode) {
|
|
auto *worker = new GetLastDaysHistoryBirbankScript(account);
|
|
worker->moveToThread(thr);
|
|
|
|
connect(thr, &QThread::started, worker, &GetLastDaysHistoryBirbankScript::start);
|
|
connect(worker, &GetLastDaysHistoryBirbankScript::finished, thr, &QThread::quit);
|
|
connect(worker, &GetLastDaysHistoryBirbankScript::finished, worker, &QObject::deleteLater);
|
|
connect(thr, &QThread::finished, thr, &QObject::deleteLater);
|
|
|
|
connect(worker, &GetLastDaysHistoryBirbankScript::finishedWithResult, this,
|
|
[this, key, event](const QString &result) {
|
|
updateEventThread(key, event, result);
|
|
}
|
|
);
|
|
}
|
|
// auto *worker = new Rshb::GetLastDaysHistoryScript(account);
|
|
// worker->moveToThread(thr);
|
|
//
|
|
// connect(thr, &QThread::started, worker, &Rshb::GetLastDaysHistoryScript::start);
|
|
// connect(worker, &Rshb::GetLastDaysHistoryScript::finished, thr, &QThread::quit);
|
|
// connect(worker, &Rshb::GetLastDaysHistoryScript::finished, worker, &QObject::deleteLater);
|
|
// connect(thr, &QThread::finished, thr, &QObject::deleteLater);
|
|
//
|
|
// connect(worker, &Rshb::GetLastDaysHistoryScript::finishedWithResult, this,
|
|
// [this, key, event](const QString &result) {
|
|
// updateEventThread(key, event, result);
|
|
// }
|
|
// );
|
|
}
|
|
|
|
if (event.type == EventType::FetchProfile) {
|
|
if ("ozon" == account.appCode) {
|
|
auto *worker = new Ozon::LoginAndCheckAccountsScript(event.deviceId, account.appCode);
|
|
worker->moveToThread(thr);
|
|
|
|
connect(thr, &QThread::started, worker, &Ozon::LoginAndCheckAccountsScript::start);
|
|
connect(worker, &Ozon::LoginAndCheckAccountsScript::finished, thr, &QThread::quit);
|
|
connect(worker, &Ozon::LoginAndCheckAccountsScript::finished, worker, &QObject::deleteLater);
|
|
connect(thr, &QThread::finished, thr, &QObject::deleteLater);
|
|
|
|
connect(worker, &Ozon::LoginAndCheckAccountsScript::finishedWithResult, this,
|
|
[this, key, event](const QString &result) {
|
|
updateEventThread(key, event, result);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
if (event.type == EventType::Phone) {
|
|
// auto *worker = new Rshb::PayByPhoneScript(account, event.phone, event.bankName, event.amount);
|
|
// worker->moveToThread(thr);
|
|
//
|
|
// connect(thr, &QThread::started, worker, &Rshb::PayByPhoneScript::start);
|
|
// connect(worker, &Rshb::PayByPhoneScript::finished, thr, &QThread::quit);
|
|
// connect(worker, &Rshb::PayByPhoneScript::finished, worker, &QObject::deleteLater);
|
|
// connect(thr, &QThread::finished, thr, &QObject::deleteLater);
|
|
//
|
|
// connect(worker, &Rshb::PayByPhoneScript::finishedWithResult, this,
|
|
// [this, key, event](const QString &result) {
|
|
// updateEventThread(key, event, result);
|
|
// }
|
|
// );
|
|
}
|
|
|
|
// Таймер на 5 минут — если не успел finish(), убить и перезапустить
|
|
const auto timer = new QTimer(this);
|
|
timer->setSingleShot(true);
|
|
connect(timer, &QTimer::timeout, this, [this, key]() {
|
|
qWarning() << "Timeout for key" << key << "- killing stuck thread.";
|
|
if (QThread *thread = m_threads.value(key); thread && thread->isRunning()) {
|
|
thread->requestInterruption(); // мягкое прерывание
|
|
if (!thread->wait(500)) {
|
|
qWarning() << "Hard terminate for key" << key;
|
|
thread->terminate();
|
|
thread->wait();
|
|
}
|
|
}
|
|
if (const auto tm = m_timers.take(key)) {
|
|
tm->deleteLater();
|
|
}
|
|
m_threads.remove(key);
|
|
});
|
|
|
|
// Сохраняем и запускаем
|
|
m_threads[key] = thr;
|
|
m_timers[key] = timer;
|
|
|
|
timer->start(5 * 60 * 1000);
|
|
thr->start();
|
|
}
|
|
|
|
void EventHandler::clearAll() {
|
|
// Останавливаем и удаляем старые
|
|
for (QThread *thread: m_threads) {
|
|
if (thread->isRunning()) {
|
|
thread->requestInterruption();
|
|
thread->terminate();
|
|
thread->wait();
|
|
}
|
|
thread->deleteLater();
|
|
}
|
|
m_threads.clear();
|
|
|
|
for (QTimer *timer: m_timers) {
|
|
timer->stop();
|
|
timer->deleteLater();
|
|
}
|
|
m_timers.clear();
|
|
}
|
|
|
|
void EventHandler::stop() {
|
|
m_running = false;
|
|
m_checkTimer->stop();
|
|
clearAll();
|
|
}
|