#include #include #include "dao/AccountDAO.h" #include "views/MainWindow.h" #include "database/DatabaseManager.h" #include "database/dao/CommonDataDAO.h" #include "db/AccountInfoScreener.h" #include "services/DeviceScreener.h" #include #include #include #include #include #include "EventHandler.h" #include "net/NetworkService.h" #include "rshb/GetLastDaysHistoryScript.h" #include "rshb/HomeScreenScript.h" #include "rshb/PayByPhoneScript.h" void startDeviceScreener(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 setupWorkerAndThreadHistory(QCoreApplication &app) { const QString appName = "rshb"; const QString lastNumber = "7183"; const QString deviceId = "6edc4a47"; AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumber); auto *thread = new QThread; auto *deviceScreenerWorker = new GetLastDaysHistoryScript(account); deviceScreenerWorker->moveToThread(thread); QObject::connect(thread, &QThread::started, deviceScreenerWorker, &GetLastDaysHistoryScript::start); QObject::connect(deviceScreenerWorker, &GetLastDaysHistoryScript::finished, thread, &QThread::quit); QObject::connect(deviceScreenerWorker, &GetLastDaysHistoryScript::finished, deviceScreenerWorker, &QObject::deleteLater); QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() { deviceScreenerWorker->stop(); }); thread->start(); } void setupScriptAutoPaymentAndThread(QCoreApplication &app) { const QString appName = "rshb"; const QString lastNumber = "7183"; const QString phoneNumber = "79641815146"; const QString deviceId = "6edc4a47"; const QString bankName = "Альфа-Банк"; // const QString bankName = "Сбербанк"; const double amount = 320; const AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumber); if (account.id != -1) { // Функция для подключения потоков к завершению приложения auto connectStopOnQuit = [&](QObject *worker, QThread *thread) { QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() { if (thread->isRunning()) { qDebug() << "Завершаем поток:" << thread; thread->quit(); thread->wait(); // Ожидаем завершения потока } worker->deleteLater(); thread->deleteLater(); }); }; // Первый поток auto *thread = new QThread; auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, amount); scriptWorker->moveToThread(thread); // Запуск первого потока QObject::connect(thread, &QThread::started, scriptWorker, &PayByPhoneScript::start); QObject::connect(scriptWorker, &PayByPhoneScript::finished, thread, &QThread::quit); QObject::connect(scriptWorker, &PayByPhoneScript::finished, scriptWorker, &QObject::deleteLater); QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Обработка результата первого потока QObject::connect(scriptWorker, &PayByPhoneScript::finishedWithResult, &app, [account, connectStopOnQuit](const QString &result) { qDebug() << "Получен результат: [" << result << "]"; // Создаем второй поток после завершения первого auto *thread2 = new QThread; auto *scriptWorker2 = new GetLastDaysHistoryScript(account); scriptWorker2->moveToThread(thread2); // Запуск второго потока QObject::connect(thread2, &QThread::started, scriptWorker2, &GetLastDaysHistoryScript::start); QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, thread2, &QThread::quit); QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, scriptWorker2, &QObject::deleteLater); QObject::connect(thread2, &QThread::finished, thread2, &QThread::deleteLater); // Остановка второго потока при завершении приложения connectStopOnQuit(scriptWorker2, thread2); thread2->start(); }); // Остановка первого потока при завершении приложения connectStopOnQuit(scriptWorker, thread); // Запуск первого потока thread->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 app.setStyle(QStyleFactory::create("Fusion")); logFile.setFileName("application.log"); if (!logFile.open(QIODevice::Append | QIODevice::Text)) { qWarning() << "Не удалось открыть лог-файл для записи"; } // Устанавливаем свой обработчик qInstallMessageHandler(messageHandler); // // auto *thread = new QThread; // auto *worker = new EventHandler; // worker->moveToThread(thread); // QObject::connect(thread, &QThread::started, worker, &EventHandler::start); // QObject::connect(worker, &EventHandler::finished, thread, &QThread::quit); // QObject::connect(worker, &EventHandler::finished, worker, &QObject::deleteLater); // QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); // thread->start(); // // auto *paymentThread = new QThread; // auto *networkService = new NetworkService; // // // FIXME доставить десктоп ид из настроеек // networkService->setDeviceData("DT88bokcwQ", ""); // 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); // paymentThread->start(); // startDeviceScreener(app); MainWindow window; window.show(); return QApplication::exec(); }