1
0
forked from BRT/arc
arc/docs/events.md
slava 73e23f437d Add Ozon pay_to_new_number and pay_to_old_number XML assets
Included XML files for the "pay to new number" and "pay to old number" features in the Ozon platform.
2026-03-01 12:02:37 +07:00

7.4 KiB
Raw Permalink Blame History

События и задачи

← Главная

Описание полного цикла задачи: от получения из 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)