1
0
forked from BRT/arc
arc/services/scripting/ScriptBridges.h
slava cae345cf61 Implement JS-based remote scripting framework for dynamic script updates:
- Add Proof of Concept (PoC) for executing JavaScript scripts fetched remotely.
- Integrate `Black::GetProfileInfoScript` logic into a JS version with fallback to C++ on errors.
- Extend `ScreenXmlParser` with additional JS-to-C++ bridge methods.
- Update `config.ini` for scripting configuration.
- Ensure scripts are securely fetched with SHA-256 validation and use an atomic caching mechanism.
- Add developer tools for debugging JS scripts and enable easier script updates without app re-deployment.
2026-05-13 15:42:10 +07:00

175 lines
7.1 KiB
C++
Raw 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 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);
};
// Скоуп дампа задачи. 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;
};
// Парсер экрана для банка 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;
};
// Утилиты конверсии Node ↔ QVariantMap. Объявлены здесь чтобы парсер-бридж
// мог их использовать без зависимости от QJSEngine.
QVariantMap nodeToVariantMap(const Node &node);
} // namespace Scripting