#pragma once #include #include #include #include #include "android/xml/Node.h" class QJSEngine; namespace Black { class ScreenXmlParser; } namespace Ozon { class ScreenXmlParser; } namespace Scripting { // Лог из JS попадает в qDebug/qWarning с префиксом банка/скрипта. class LogBridge final : public QObject { Q_OBJECT public: LogBridge(QString tag, QObject *parent = nullptr) : QObject(parent), m_tag(std::move(tag)) {} public slots: void debug(const QString &message); void info(const QString &message); void warn(const QString &message); void error(const QString &message); private: QString m_tag; }; // Sleep + проверка interrupt (скрипт крутится в worker-потоке EventHandler'а). class TimerBridge final : public QObject { Q_OBJECT public: explicit TimerBridge(QObject *parent = nullptr) : QObject(parent) {} public slots: void sleep(int ms); // блокирующий, проверяет interrupt bool isInterrupted() const; // ручная проверка из JS }; // Прокси над AdbUtils. Все методы статические в C++ — здесь оборачиваем как Q_INVOKABLE, // чтобы JS видел их как host.adb.. class AdbBridge final : public QObject { Q_OBJECT public: explicit AdbBridge(QObject *parent = nullptr) : QObject(parent) {} public slots: QString getScreenDumpAsXml(const QString &deviceId, int idx); QString getRawScreenDumpAsXml(const QString &deviceId); bool makeTap(const QString &deviceId, int x, int y); bool makeSwipe(const QString &deviceId, int x1, int y1, int x2, int y2); bool makeSwipeWithDuration(const QString &deviceId, int x1, int y1, int x2, int y2, int durationMs); bool tryToStartApplication(const QString &deviceId, const QString &packageName); bool tryToKillApplication(const QString &deviceId, const QString &packageName); QString tryToGetRunningAppPid(const QString &deviceId, const QString &packageName); bool takeScreenshot(const QString &deviceId, const QString &name); bool inputText(const QString &deviceId, const QString &text); bool inputAdbIMEText(const QString &deviceId, const QString &text); bool enableAdbIMEKeyboard(const QString &deviceId); bool disableAdbIMEKeyboard(const QString &deviceId); bool hideKeyboard(const QString &deviceId); bool goBack(const QString &deviceId); void unlockScreen(const QString &deviceId, int screenWidth, int screenHeight); QString getDeviceTimezone(const QString &deviceId); QString captureScreenshotBase64(const QString &deviceId); }; // DAO-прокси: read для устройства/профиля/материалов, write для баланса/профиля. class DaoBridge final : public QObject { Q_OBJECT public: explicit DaoBridge(QObject *parent = nullptr) : QObject(parent) {} public slots: // DeviceDAO QVariantMap deviceGetById(const QString &id); QVariantMap deviceFindByAdbSerial(const QString &serial); // BankProfileDAO QVariantMap bankProfileGet(const QString &deviceId, const QString &appCode); bool bankProfileUpdateAmount(int profileId, double amount); bool bankProfileUpdateProfileInfo(int profileId, const QString &fullName, const QString &phone, const QString &email); bool bankProfileUpdateComment(int profileId, const QString &comment); // MaterialDAO QVariantList materialGetAccounts(const QString &deviceId, const QString &appCode); QVariantMap materialFindAppAccount(const QString &deviceId, const QString &appCode, const QString &lastNumbers); bool materialUpsert(const QVariantMap &material); bool materialUpdateCardNumber(int accountId, const QString &cardNumber); bool materialUpdateAccountById(int id, const QString &status, const QString &description, const QString ¤cy); // SettingsDAO QString settingsGet(const QString &key); // TransactionDAO — для платёжных скриптов и сборщика транзакций. // tx map: {accountId, amount, fee, name, phone, bankName, type, status, // timestamp (ISO UTC string), completeTime (ISO local string), // bankTime, description, updatedDescription, bankTrExternalId} // Возвращает id вставленной транзакции (-1 при ошибке). int transactionInsert(const QVariantMap &tx); bool transactionUpdateBankTrExternalId(int id, const QString &externalId); }; // Скоуп дампа задачи. JS-style API: begin/end вместо RAII (вешаем на try/finally). class DumpBridge final : public QObject { Q_OBJECT public: explicit DumpBridge(QObject *parent = nullptr) : QObject(parent) {} ~DumpBridge() override { endScope(QString()); } public slots: void beginScope(const QString &bank, const QString &taskKind, const QString &adbDeviceId, const QVariantMap &meta); void endScope(const QString &errorMessage); // пусто = success private: void *m_scope = nullptr; QString *m_errorPtr = nullptr; }; // Прокси к C++ скрипту-родителю: позволяет JS эмитить Qt-сигналы на исходном // скрипте (например, transactionParsed → EventHandler). Если signalSink не // передан в ScriptRuntime::run — методы no-op (но не throw). class ScriptObjectBridge final : public QObject { Q_OBJECT public: explicit ScriptObjectBridge(QObject *sink = nullptr, QObject *parent = nullptr) : QObject(parent), m_sink(sink) {} public slots: // Парсит jsonStr и вызывает на m_sink сигнал/слот `transactionParsed(QJsonObject)`. // Если sink нет или JSON битый — лог warning, продолжение работы. void emitTransactionParsed(const QString &jsonStr); private: QObject *m_sink; }; // OCR-хелперы: распознавание текста на скриншоте и извлечение ID транзакции. // Реализация в android/ocr/OcrUtils — здесь чистый wrapper для JS. class OcrBridge final : public QObject { Q_OBJECT public: explicit OcrBridge(QObject *parent = nullptr) : QObject(parent) {} public slots: // Захватывает экран и прогоняет через OCR (grayscale + 300dpi, rus+eng). QString recognizeFromScreen(const QString &deviceId); // Извлекает "ID операции ..." / "№ Ф-..." из распознанного OCR-текста. QString extractTransactionId(const QString &ocrText); }; // Парсер экрана для банка Black. Каждый запуск скрипта получает свой инстанс, // поэтому m_xml/m_nodes не разделяются между задачами. class BlackParserBridge final : public QObject { Q_OBJECT public: explicit BlackParserBridge(QObject *parent = nullptr); ~BlackParserBridge() override; Black::ScreenXmlParser *parser() const { return m_parser; } public slots: void parseAndSaveXml(const QString &xml); bool isHomeScreen(); bool isSideMenu(); bool isPinCodeScreen(); bool isProfilePage(); bool isCVUScreen(); bool isTransactionLoadingScreen(); bool isTransactionListScreen(); bool isPayInputCardNumberScreen(); bool isPayTransferConfirmScreen(); bool isPayInputSumScreen(); bool isPayConfirmScreen(); bool isPaySuccessScreen(); QVariantMap findHolaButton(); QVariantMap findTextNode(const QString &text); QVariantMap findNodeByContentDesc(const QString &contentDesc); QVariantMap findNodeByContentDescContains(const QString &contentDesc); QVariantMap findButtonNode(const QString &text, bool contains); QVariantMap findFirstEditText(); QVariantMap findPinCodeEditText(); QVariantMap findVerMasAfterTuActividad(); QVariantMap findEditTextByHint(const QString &hint); QString parseUserNameFromHomeScreen(); double parseBalanceFromHomeScreen(); QString parseProfileNombre(); QString parseProfileApellido(); QString parseProfileEmail(); QString parseProfilePhone(); QString parseCVUNumber(); QString parseRecipientNameFromConfirm(); QString parsePaySuccessDateTime(); QString parsePaySuccessCoelsaId(); private: Black::ScreenXmlParser *m_parser; }; // Высокоуровневые операции, повторяющие методы Black::CommonScript: // runAppAndGoToHomeScreen, postAccountsData, createBankProfileIfNeeded. // Используют ТОТ ЖЕ парсер, что и BlackParserBridge — состояние (XML) общее. class BlackHelpersBridge final : public QObject { Q_OBJECT public: BlackHelpersBridge(BlackParserBridge *parser, QObject *parent = nullptr) : QObject(parent), m_parserBridge(parser) {} public slots: bool runAppAndGoToHomeScreen(const QString &deviceId, const QString &packageName, const QString &pinCode, int width, int height); void postAccountsData(const QVariantList &accountsWithEmptyMaterialId); void createBankProfileIfNeeded(const QString &deviceId, const QString &appCode, double parsedBalance); private: BlackParserBridge *m_parserBridge; }; // Парсер экрана для банка Ozon. Минимальный набор для get_profile_info — при // миграции login_and_check / get_card_info добавлять методы сюда же. class OzonParserBridge final : public QObject { Q_OBJECT public: explicit OzonParserBridge(QObject *parent = nullptr); ~OzonParserBridge() override; Ozon::ScreenXmlParser *parser() const { return m_parser; } public slots: void parseAndSaveXml(const QString &xml); bool isHomeScreen(); bool isProfileScreen(); QVariantMap tryToFindAdBanner(); QVariantMap tryToFindGooglePlayBanner(int screenWidth, int screenHeight); QVariantMap findUserNameOnHomeScreen(int screenHeight); QVariantMap findCardButtonByLastNumbers(const QString &lastNumbers); QVariantMap findButtonNode(const QString &text, bool contains); QVariantMap findTextNode(const QString &text); QVariantMap findFirstEditText(); QVariantMap findEditTextByHint(const QString &hintPrefix); QVariantMap findPanCardNumberInput(); QVariantMap findMainAccountButton(); QVariantMap findNodeByContentDesc(const QString &contentDesc); // Все Node'ы текущего дампа как массив map — нужно для JS-итерации в // payment-скриптах (поиск EditText'ов с input___ rid, других банков по // content-desc="other-bank-item" и т.д.). QVariantList findAllNodes(); QVariantList findAllButtons(); // pinCode + title — возвращает массив node-маn в порядке цифр для тапа. QVariantList tryToFindPinCode(const QString &pinCode, const QString &title); // Карточки с главного экрана: lastNumbers, amount, description, currency. // id == -1, materialId пусто — это стабы (используются для парсинга баланса). QVariantList parseCardsOnHomeScreen(); // Аккаунты на экране "Все продукты" — массив {material: {...}, node: {...}}. QVariantList parseAccountsInfo(); // Для GetLastTransactionsScript: bool isTransactionListScreen(); bool hasCollapsedTransactionsBelow(int screenHeight); QVariantList findTransactionButtons(int maxCount); QVariantList getLast2DaysTransactions(); QVariantList parseTodayAndYesterdayHistory(); QVariantList parseTodayAndYesterdayReportHistory(); QVariantMap parseTransactionInfo(int screenWidth, int screenHeight); QVariantMap parseTransactionInfoHistory(int screenWidth, int screenHeight); QVariantMap parseTransactionDetail(); QVariantMap parseTransactionButtonText(const QString &text); QString parseProfileFullName(); QString parseProfilePhone(); QString findFullCardNumber(); private: Ozon::ScreenXmlParser *m_parser; }; // Высокоуровневые операции, повторяющие Ozon::CommonScript: фактический // запуск приложения, закрытие баннеров, регистрация bank_profile на сервере, // постинг аккаунтов. Используют parser() из OzonParserBridge — состояние XML // общее, как и у Black. class OzonHelpersBridge final : public QObject { Q_OBJECT public: OzonHelpersBridge(OzonParserBridge *parser, QObject *parent = nullptr) : QObject(parent), m_parserBridge(parser) {} public slots: bool runAppAndGoToHomeScreen(const QString &deviceId, const QString &packageName, const QString &pinCode, int width, int height); bool tryToCloseAllBannersOnHomePage(const QString &deviceId, int width, int height); bool closeGooglePlayBannerIfVisible(const QString &deviceId, int width, int height); bool goToAllProducts(const QString &deviceId, int width, int height); void createBankProfileIfNeeded(const QString &deviceId, const QString &appCode, double parsedBalance); void postAccountsData(const QVariantList &accountsWithEmptyMaterialId); // POST /api/v1/device — создаёт устройство на сервере, если apiId пуст. // deviceObj: { id, name, screenWidth, screenHeight, battery, apiId } (как из dao.deviceGetById). void createDeviceIfNeeded(const QVariantMap &deviceObj); // POST /api/v1/profile/material — отправляет одну карту на сервер. // material: полный MaterialInfo-объект как из dao.materialFindAppAccount. void postMaterial(const QVariantMap &material, const QString &bankProfileId, const QString &fullName); // Для платёжных скриптов: bool isAppRunning(const QString &deviceId, const QString &packageName); // pincodeNodes: список node-map из parser.tryToFindPinCode. bool inputPinCode(const QString &deviceId, const QVariantList &pincodeNodes); // FreezeDetector::isUsefulDump — статически-чистая проверка. bool isUsefulDump(const QString &xml); // Захват скриншота + сохранение в TransactionDAO как receipt-image. void saveTransactionReceipt(const QString &deviceId, int transactionId); // POST /api/v1/profile/transaction — вставка новой транзакции (для GetLastTx). // tx: как в dao.transactionInsert + account: {appCode, deviceId, lastNumbers}. void postNewTransaction(const QVariantMap &account, const QVariantMap &tx); private: OzonParserBridge *m_parserBridge; }; // Утилиты конверсии Node ↔ QVariantMap. Объявлены здесь чтобы парсер-бридж // мог их использовать без зависимости от QJSEngine. QVariantMap nodeToVariantMap(const Node &node); } // namespace Scripting