210 lines
8.7 KiB
C++
210 lines
8.7 KiB
C++
#include <QApplication>
|
||
#include <QThread>
|
||
|
||
#include "dao/AccountDAO.h"
|
||
#include "views/MainWindow.h"
|
||
|
||
#include "database/DatabaseManager.h"
|
||
#include "database/dao/CommonDataDAO.h"
|
||
#include "services/DeviceScreener.h"
|
||
|
||
#include <iostream>
|
||
#include <QStyleFactory>
|
||
#include <thread>
|
||
#include <chrono>
|
||
#include <QFile>
|
||
#include <QSettings>
|
||
|
||
#include "EventHandler.h"
|
||
#include "adb/AdbUtils.h"
|
||
#include "net/NetworkService.h"
|
||
#include "rshb/GetLastDaysHistoryScript.h"
|
||
#include "rshb/HomeScreenScript.h"
|
||
#include "rshb/PayByPhoneScript.h"
|
||
#include "widget/loader/ErrorWindow.h"
|
||
#include "widget/loader/LoaderWindow.h"
|
||
#include "widget/loader/RegistrationWindow.h"
|
||
|
||
void startDeviceScreener(const QCoreApplication &app) {
|
||
auto *thread = new QThread();
|
||
auto *deviceScreenerWorker = new DeviceScreener;
|
||
|
||
// Перемещаем worker в новый поток thread.
|
||
// Это значит, что все слоты worker, вызываемые через connect(), теперь будут исполняться в этом фоне-потоке.
|
||
deviceScreenerWorker->moveToThread(thread);
|
||
|
||
// Когда поток запустится, автоматически вызовется worker->start() внутри фонового потока.
|
||
QObject::connect(thread, &QThread::started, deviceScreenerWorker, &DeviceScreener::start);
|
||
|
||
// 🔁 Эти 3 строки делают автоматическую зачистку:
|
||
// Когда worker закончит работу (emit finished()), мы:
|
||
// - останавливаем поток (thread->quit())
|
||
// - удаляем worker (deleteLater)
|
||
// - удаляем thread (deleteLater)
|
||
// Это защищает от утечек памяти и оставшихся потоков после завершения.
|
||
QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, thread, &QThread::quit);
|
||
QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, deviceScreenerWorker, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
|
||
// Когда пользователь закрывает приложение (Ctrl+C, exit() и т.п.), мы вызываем worker->stop() — ты сам пишешь, что в этом методе.
|
||
//Обычно он просто ставит флаг m_running = false, чтобы остановить бесконечный цикл в start()
|
||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||
deviceScreenerWorker->stop();
|
||
});
|
||
|
||
thread->start();
|
||
}
|
||
|
||
void startEventHandler(const QCoreApplication &app) {
|
||
auto *thread = new QThread;
|
||
auto *eventHandler = new EventHandler;
|
||
eventHandler->moveToThread(thread);
|
||
QObject::connect(thread, &QThread::started, eventHandler, &EventHandler::start);
|
||
QObject::connect(eventHandler, &EventHandler::finished, thread, &QThread::quit);
|
||
QObject::connect(eventHandler, &EventHandler::finished, eventHandler, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||
eventHandler->stop();
|
||
});
|
||
thread->start();
|
||
}
|
||
|
||
void startNetworkService(const QCoreApplication &app) {
|
||
auto *paymentThread = new QThread;
|
||
auto *networkService = new NetworkService;
|
||
networkService->moveToThread(paymentThread);
|
||
QObject::connect(paymentThread, &QThread::started, networkService, &NetworkService::start);
|
||
QObject::connect(networkService, &NetworkService::finished, paymentThread, &QThread::quit);
|
||
QObject::connect(networkService, &NetworkService::finished, networkService, &QObject::deleteLater);
|
||
QObject::connect(paymentThread, &QThread::finished, paymentThread, &QThread::deleteLater);
|
||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||
networkService->stop();
|
||
});
|
||
paymentThread->start();
|
||
}
|
||
|
||
static QFile logFile;
|
||
static QMutex logMutex;
|
||
|
||
void messageHandler(
|
||
const QtMsgType type,
|
||
const QMessageLogContext &context,
|
||
const QString &msg
|
||
) {
|
||
Q_UNUSED(context) // можно раскомментировать, если нужны file/line/function
|
||
// Формируем строку с типом и временем
|
||
const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
|
||
QString level;
|
||
switch (type) {
|
||
case QtDebugMsg: level = "DEBUG";
|
||
break;
|
||
case QtInfoMsg: level = "INFO";
|
||
break;
|
||
case QtWarningMsg: level = "WARNING";
|
||
break;
|
||
case QtCriticalMsg: level = "CRITICAL";
|
||
break;
|
||
case QtFatalMsg: level = "FATAL";
|
||
break;
|
||
}
|
||
|
||
|
||
const QString line = QString("%1 [%2] [%3:%4] %5\n")
|
||
.arg(timestamp, level, context.function, QString::number(context.line), msg);
|
||
// Записываем в файл (потокобезопасно)
|
||
{
|
||
QMutexLocker locker(&logMutex);
|
||
if (logFile.isOpen()) {
|
||
QTextStream(&logFile) << line;
|
||
logFile.flush();
|
||
}
|
||
}
|
||
|
||
// По желанию — дублировать в консоль
|
||
const QByteArray localMsg = line.toLocal8Bit();
|
||
fprintf(stderr, "%s", localMsg.constData());
|
||
|
||
if (type == QtFatalMsg) {
|
||
abort();
|
||
}
|
||
}
|
||
|
||
int main(int argc, char *argv[]) {
|
||
QApplication app(argc, argv);
|
||
|
||
// Выбрать стиль Fusion
|
||
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
||
|
||
logFile.setFileName("application.log");
|
||
if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
|
||
qWarning() << "Не удалось открыть лог-файл для записи";
|
||
}
|
||
// Устанавливаем свой обработчик
|
||
qInstallMessageHandler(messageHandler);
|
||
|
||
|
||
// 1. Если есть токен, проверяем его
|
||
// - ошибка сети или сайта [code -1]
|
||
// - протух токен, надо заново [code 0]
|
||
// - все ок, запуск программы [code 1]
|
||
// 2. Если нет токена, выводим, что нет и надо зарегаться [code 0]
|
||
const QSettings settings("config.ini", QSettings::IniFormat);
|
||
const QString token = settings.value("common/token").toString();
|
||
|
||
if (false) {
|
||
auto *mainWindow = new MainWindow();
|
||
mainWindow->show();
|
||
} else {
|
||
if (token.isEmpty()) {
|
||
auto *registrationWindow = new RegistrationWindow();
|
||
registrationWindow->show();
|
||
|
||
QObject::connect(
|
||
registrationWindow, &RegistrationWindow::onRegisteredSuccess, registrationWindow,
|
||
[registrationWindow, &app]() {
|
||
auto *mainWindow = new MainWindow();
|
||
mainWindow->show();
|
||
registrationWindow->close();
|
||
startNetworkService(app);
|
||
startDeviceScreener(app);
|
||
startEventHandler(app);
|
||
}, Qt::QueuedConnection);
|
||
} else {
|
||
auto *loader = new LoaderWindow(token);
|
||
loader->show();
|
||
|
||
QObject::connect(loader, &LoaderWindow::loadingFinished, loader, [loader, &app](const int result) {
|
||
if (result == -1) {
|
||
auto *errorWindow = new ErrorWindow(
|
||
"Нет подключения к интернету или сервер не отвечает.\n\nПожалуйста, попробуйте позже."
|
||
);
|
||
errorWindow->show();
|
||
} else if (result == 1) {
|
||
auto *mainWindow = new MainWindow();
|
||
mainWindow->show();
|
||
startNetworkService(app);
|
||
startDeviceScreener(app);
|
||
startEventHandler(app);
|
||
} else if (result == 0) {
|
||
auto *registrationWindow = new RegistrationWindow();
|
||
registrationWindow->show();
|
||
|
||
QObject::connect(
|
||
registrationWindow, &RegistrationWindow::onRegisteredSuccess, registrationWindow,
|
||
[registrationWindow, &app]() {
|
||
auto *mainWindow = new MainWindow();
|
||
mainWindow->show();
|
||
registrationWindow->close();
|
||
startNetworkService(app);
|
||
startDeviceScreener(app);
|
||
startEventHandler(app);
|
||
}, Qt::QueuedConnection);
|
||
}
|
||
loader->close();
|
||
}, Qt::QueuedConnection);
|
||
// loader.show();
|
||
}
|
||
}
|
||
return QApplication::exec();
|
||
}
|