1
0
forked from BRT/arc
arc/services/DeviceScreener.cpp
slava b1876bc3b9 Refactor includes and add AccountInfoScreener functionality
Updated include paths for consistent structure under the `db` directory. Added `AccountInfoScreener` for parsing card data using Tesseract OCR and enhanced related models. Removed unused code and simplified main workflow.
2025-04-21 23:12:21 +07:00

165 lines
5.5 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.

#include "DeviceScreener.h"
#include <QRegularExpression>
#include <QProcess>
#include <QFile>
#include <QBuffer>
#include <QThread>
#include <QImage>
#include <dao/DeviceDAO.h>
#include <db/DeviceInfo.h>
DeviceScreener::DeviceScreener(QObject *parent) : QObject(parent) {
}
DeviceScreener::~DeviceScreener() = default;
void DeviceScreener::start() {
qDebug() << "Worker started in thread:" << QThread::currentThread();
while (m_running) {
QList<QPair<QString, QString>> devices = readAdbDevices();
QStringList onlineIds;
for (const auto&[id, status] : devices) {
qDebug() << "Id:" << id << ", Status:" << status;
DeviceInfo device;
device.id = id;
if (status == "device") {
onlineIds << device.id;
device = readDeviceInfo(id);
takeScreenshot(id);
}
device.status = status;
device.updateTime = QDateTime::currentDateTime();
qDebug() << "Update device: " << DeviceDAO::upsertDevice(device);
}
qDebug() << "All devices offline: " << DeviceDAO::markDevicesOfflineExcept(onlineIds);
QThread::sleep(3);
}
emit finished();
}
QByteArray convertPngToJpeg(const QByteArray& pngData, const int quality = 90) {
QImage image;
if (!image.loadFromData(pngData, "PNG")) {
qWarning() << "Не удалось загрузить PNG из байт";
return {};
}
// if (!image.save("test.jpg", "JPG", quality)) {
// qWarning() << "Не удалось сохранить как JPG:" << "test.jpg";
// return {};
// }
QByteArray jpgData;
QBuffer buffer(&jpgData);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG", quality);
return jpgData;
}
bool DeviceScreener::takeScreenshot(const QString& deviceId) {
QProcess process;
QStringList arguments;
arguments << "-s" << deviceId << "exec-out" << "screencap" << "-p";
process.start("adb", arguments);
if (!process.waitForFinished(5000)) {
qWarning() << "ADB скриншот не завершился для" << deviceId;
return false;
}
const QByteArray imageData = process.readAllStandardOutput();
if (imageData.isEmpty()) {
qWarning() << "Скриншот пустой для " << deviceId;
return false;
}
// Обновляем изображение в БД
if (!DeviceDAO::updateImage(deviceId, convertPngToJpeg(imageData, 90))) {
qWarning() << "Не удалось записать изображение в БД для" << deviceId;
return false;
}
qDebug() << "Screenshot saved, device: " << deviceId;
return true;
}
QList<QPair<QString, QString>> DeviceScreener::readAdbDevices() {
QProcess process;
process.start("adb", QStringList() << "devices");
process.waitForFinished();
const QString output = process.readAllStandardOutput();
// qDebug() << "[adb devices output]:\n" << output;
QList<QPair<QString, QString>> devices;
const QStringList lines = output.split('\n');
for (int i = 1; i < lines.size(); ++i) {
QString line = lines.at(i).trimmed();
if (line.isEmpty()) {
continue;
}
/**
* device — устройство готово к использованию.
* offline — устройство подключено, но не может быть использовано.
* unauthorized — устройство не авторизовано для работы с ADB (нужно подтвердить запрос на подключение на самом устройстве).
* recovery — устройство в режиме восстановления.
*/
// Разделяем строку на id и type по табуляции
if (QStringList parts = line.split('\t'); parts.size() == 2) {
const QString& id = parts.at(0);
const QString& status = parts.at(1);
devices.append(qMakePair(id, status));
}
}
return devices;
}
static const QRegularExpression screenRegex(R"(Physical size: (\d+)x(\d+))");
static const QRegularExpression batteryRegex(R"(level:\s*(\d+))");
DeviceInfo DeviceScreener::readDeviceInfo(const QString& deviceId) {
DeviceInfo info;
info.id = deviceId;
info.screenWidth = 0;
info.screenHeight = 0;
info.battery = 0;
auto runAdbCommand = [&](const QStringList& args) -> QString {
QProcess process;
process.start("adb", QStringList{"-s", deviceId} + args);
process.waitForFinished();
return QString::fromUtf8(process.readAllStandardOutput()).trimmed();
};
info.name = runAdbCommand({"shell", "getprop", "ro.product.model"});
info.android = runAdbCommand({"shell", "getprop", "ro.build.version.release"});
// Размер экрана
const QString screenOutput = runAdbCommand({"shell", "wm", "size"});
QRegularExpressionMatch match = screenRegex.match(screenOutput);
if (match.hasMatch()) {
info.screenWidth = match.captured(1).toInt();
info.screenHeight = match.captured(2).toInt();
}
// Уровень батареи
const QString batteryOutput = runAdbCommand({"shell", "dumpsys", "battery"});
match = batteryRegex.match(batteryOutput);
if (match.hasMatch()) {
info.battery = match.captured(1).toInt();
}
info.updateTime = QDateTime::currentDateTime();
return info;
}
void DeviceScreener::stop() {
m_running = false;
}