Included XML files for the "pay to new number" and "pay to old number" features in the Ozon platform.
7.4 KiB
7.4 KiB
События и задачи
Описание полного цикла задачи: от получения из API до завершения и отчёта.
Ключевые файлы
| Файл | Роль |
|---|---|
services/EventHandler.h/cpp |
Оркестратор: поллинг, сохранение в БД, запуск потоков |
services/net/NetworkService.h/cpp |
HTTP-клиент: getTasks(), postTaskResult() |
database/dao/EventDAO.h/cpp |
CRUD для таблицы events |
models/db/EventInfo.h |
Модель задачи |
Жизненный цикл задачи
Wait → InProgress → Complete
↘ Error
Схема работы
1. Получение задач (каждые 5 секунд)
QTimer (5s)
└─→ NetworkService::getTasks()
└─→ GET /api/v1/task/get_tasks (Bearer token)
└─→ signal tasksReceived(QJsonArray)
└─→ EventHandler::onTasksReceived()
Формат ответа API:
{
"success": true,
"data": [
{ "bank_name": "ozon", "material_id": "c340cd2e-cefd-48d6-a813-c4be097ae493", "type": "FETCH_PROFILE", "body": {} },
{ "bank_name": "birbank", "material_id": "a1b2c3d4-0000-0000-0000-000000000001", "type": "FETCH_TRANSACTIONS", "body": {} },
{ "bank_name": "ozon", "material_id": "a1b2c3d4-0000-0000-0000-000000000002", "type": "CREATE_TRANSACTION", "body": { "amount": 1000, "currency": 643 } }
]
}
material_id— UUID строка. Поддерживается также числовой формат для совместимости (парсится черезtask["material_id"].isString() ? toString() : QString::number(toInt())).
2. Обработка задачи (onTasksReceived)
Для каждой задачи из API:
├─ existsActiveByExternalId(material_id)?
│ YES → пропустить (дедупликация)
│ NO → продолжить
│
├─ AccountDAO::findByMaterialId(material_id)
│ прямой SELECT WHERE material_id = ?
│ НЕ НАЙДЕН → sendTaskResult(status=error) и пропустить
│
└─ EventDAO::insertEvent(status=Wait)
Маппинг типов задач:
| Тип в API | EventType в коде |
Скрипт |
|---|---|---|
FETCH_PROFILE |
FetchProfile |
Ozon::LoginAndCheckAccountsScript |
FETCH_TRANSACTIONS |
FetchTransactions |
GetLastDaysHistoryBirbankScript |
CREATE_TRANSACTION |
CreateTransaction |
(не реализован) |
3. Запуск задач (тот же onTasksReceived)
Для каждого онлайн устройства:
├─ m_threads[deviceId] запущен? → пропустить
│ (одно устройство = один поток одновременно)
│
├─ EventDAO::getFirstWaitEventByDeviceId(deviceId)
│ самая старая Wait-задача (ORDER BY timestamp ASC)
│
├─ ApplicationDAO::getApplication() → статус == "active"?
│
├─ EventDAO::updateEvent(id, InProgress)
│
└─ startThreadForTask(account, event)
4. Выполнение скрипта (QThread)
QThread
└─→ Script::start()
├─ ADB команды (adb shell, screenshot, xml dump)
├─ ScreenXmlParser (парсинг UI)
├─ Tesseract OCR (при необходимости)
└─ emit finishedWithResult(error или "")
└─→ EventHandler::updateEventThread()
Watchdog: если скрипт не завершился за 5 минут — поток принудительно завершается.
5. Завершение задачи (updateEventThread)
result == "" → EventDAO::updateEvent(Complete)
result != "" → EventDAO::updateEvent(Error, message)
└─→ sendEventStatus() (новый QThread)
└─→ POST /api/v1/event/status ⚠️ устаревший эндпоинт, требует замены на task_result
Отправка результата задачи
Используется POST /api/v1/task/task_result через NetworkService::postTaskResult().
При ненайденном аккаунте (material_id не в БД)
{
"type": "FETCH_PROFILE",
"material_id": "c340cd2e-cefd-48d6-a813-c4be097ae493",
"bank_name": "ozon",
"data": {
"status": "error",
"description": "Account not found for material_id: c340cd2e-cefd-48d6-a813-c4be097ae493"
}
}
При успешном выполнении — FETCH_PROFILE
{
"type": "FETCH_PROFILE",
"material_id": "c340cd2e-cefd-48d6-a813-c4be097ae493",
"bank_name": "ozon",
"data": {
"bank_account_id": "string",
"currency": 643,
"amount": 15000,
"extra": {}
}
}
При успешном выполнении — FETCH_TRANSACTIONS
{
"type": "FETCH_TRANSACTIONS",
"material_id": "a1b2c3d4-0000-0000-0000-000000000001",
"bank_name": "birbank",
"data": [
{
"bank_transaction_id": "string",
"amount": 500,
"currency": 944,
"transaction_type": "bank",
"bank_participator_id": "string",
"status": "completed",
"extra": {},
"created_at": "2024-01-01T12:00:00"
}
]
}
При ошибке выполнения скрипта
{
"type": "FETCH_PROFILE",
"material_id": "c340cd2e-cefd-48d6-a813-c4be097ae493",
"bank_name": "ozon",
"data": {
"status": "error",
"description": "Cant open the home screen: emulator-5554 ozon"
}
}
Модель EventInfo
struct EventInfo {
int id; // локальный ID в SQLite
QString externalId; // material_id из API (UUID строка)
int accountId; // FK → accounts
QString deviceId; // ADB device id
double amount;
QString phone;
QString bankName;
QString comment;
QByteArray screenshot; // последний скриншот экрана
EventStatus status; // Wait / InProgress / Complete / Error
EventType type; // FetchProfile / FetchTransactions / CreateTransaction
QDateTime timestamp;
QDateTime updateTime;
QDateTime completeTime;
};
Дедупликация
EventDAO::existsActiveByExternalId(const QString &externalId) — проверяет наличие записи
с status IN ('wait', 'inprogress') для данного external_id.
Гарантирует что одна и та же задача не попадёт в очередь дважды
пока не завершится предыдущее выполнение.
Ограничения
- 1 поток на устройство — пока устройство занято, остальные задачи ждут следующего поллинга
- Очерёдность — внутри устройства задачи выполняются по
timestamp ASC - Интервал поллинга — 5 секунд (
m_pollTimer->setInterval) - Пути API — настраиваются в
config.ini:net/pathGetTasks(дефолт/api/v1/task/get_tasks)net/pathTaskResult(дефолт/api/v1/task/task_result)