1
0
forked from BRT/arc
arc/services/scripting/ScriptBridges.h

324 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <QObject>
#include <QString>
#include <QVariantList>
#include <QVariantMap>
#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.<method>.
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 &currency);
// 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