#include "processthread.h" #include #include #include "api/configapi.h" #include "appevent.h" #include "processmodel.h" #include "qjsonarray.h" #include "qjsonobject.h" #include #include #include "api/processapi.h" #include "qjsonvalue.h" #include "qlist.h" #include "qmessagebox.h" #include "qnamespace.h" #include "basemainTr.h" CWF::SqlDatabaseStorage storage("QSQLITE", "localhost", "postgres", "postgres", "1234", 5432); // 将 FILETIME 转换为 Unix 时间戳 static qint64 fileTimeToUnixTimestamp(FILETIME ft) { // FILETIME 是自 1601 年以来的 100 毫微秒数 ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; // FILETIME 和 时间戳的 基础时间不一样 // 转换为秒,并减去 1601 到 1970 年之间的秒数 if (ull.QuadPart / 10000000LL > 11644473600LL) { qint64 timestamp = ull.QuadPart / 10000000LL - 11644473600LL; return timestamp; } return ull.QuadPart / 10000000LL; } QString convertSecondsToTimeFormat(int totalSeconds) { int days = totalSeconds / (24 * 3600); // 计算天数 int hours = (totalSeconds % (24 * 3600)) / 3600; // 计算小时 int minutes = (totalSeconds % 3600) / 60; // 计算分钟 int seconds = totalSeconds % 60; // 计算秒数 // 返回格式化后的字符串,并使用 tr() 标记可翻译的文本 return QString(Tr::tr("%1days%2hours%3minutes%4seconds")) .arg(days) .arg(hours) .arg(minutes) .arg(seconds); } /// /// \brief 转换到分钟 /// \param totalSeconds /// \return /// QString convertSecondsToMinutesTimeFormat(int totalSeconds) { // 只计算分钟 int minutes = totalSeconds / 60; return QString::number(minutes); } void ProcessThread::sendExitTime(qint64 updataTime) { TC::ProcessNameApi processNameApi; QJsonArray serverArray = processNameApi.get(); // 获取过滤名单 QSet filter; QSet gameFilter; for (const QJsonValue &item : serverArray) { if (!item.isObject()) { return; } const QJsonObject object = item.toObject(); const QString name = object["name"].toString(); if (object.contains("is_confirmed")) { if (object["is_confirmed"].toInt() == 2) { filter.insert(name); } } if (object.contains("pid_type")) { const QString type = object["pid_type"].toString(); if (type == "游戏" || type == "game") { gameFilter.insert(name); } } } ProcessModel processModel{storage}; // 在数据库 获取 不是这个更新日期的数据 CWF::SqlQueryManager qry(storage); qry.select("*", processModel.getTableName()) .where(QString("updataTime != '%1' OR updataTime IS NULL").arg(updataTime)); qry.prepare(); QJsonObject jsonObject = qry.exec(); QJsonArray jsonArray = qry.toJson(); QJsonArray sendJsonArray; if (jsonArray.size() > 0) { for (const auto &json : jsonArray) { const QJsonObject object = json.toObject(); const QString name = object["processName"].toString(); QJsonObject sendObject; sendObject.insert("pid", object["pid"]); sendObject.insert("pid_name", object["processName"]); sendObject.insert("begin_time", object["creationTime"]); sendObject.insert("end_time", object["exitTime"]); sendObject.insert("last_check_time", object["updataTime"]); sendObject.insert("status", 1); sendObject.insert("notes", ""); // 存在过滤里面的 不发送数据 if (!filter.contains(name)) { sendJsonArray.append(sendObject); } } } // 上传 后 删除 if (sendJsonArray.size() > 0) { TC::ProcessApi processApi(sendJsonArray); bool isSendok = processApi.post(); if (isSendok) { // 移除发送到服务器的本地数据 CWF::SqlQueryManager qry(storage); qry.remove(processModel.getTableName(), QString("updataTime != '%1' OR updataTime IS NULL").arg(updataTime)); qry.prepare(); QJsonObject jsonObject = qry.exec(); QJsonArray jsonArray = qry.toJson(); } } // 获取配置 QVariant messageBoxPointX = QVariant(); QVariant messageBoxPointY = QVariant(); QVariant messageText = QVariant(""); QVariant gameMessageText = QVariant(""); QVariant messageTitle = QVariant(Tr::tr("Tips")); { TC::ConfigApi configApi("messageBoxPointX"); std::optional value = configApi.get(); if (value.has_value()) { messageBoxPointX = value.value(); } } { TC::ConfigApi configApi("messageBoxPointY"); std::optional value = configApi.get(); if (value.has_value()) { messageBoxPointY = value.value(); } } { TC::ConfigApi configApi("messageText"); std::optional value = configApi.get(); if (value.has_value()) { messageText = value.value(); } } { TC::ConfigApi configApi("messageTitle"); std::optional value = configApi.get(); if (value.has_value()) { messageTitle = value.value(); } } { TC::ConfigApi configApi("gameMessageText"); std::optional value = configApi.get(); if (value.has_value()) { gameMessageText = value.value(); } } // 获取服务器 对应的时间信息 for (const QJsonValue &item : serverArray) { if (!item.isObject()) { return; } const QJsonObject object = item.toObject(); const QString name = object["name"].toString(); const QString zhName = object["chinese_name"].toString(); const QString type = object["pid_type"].toString(); // 2 提示 1 不提示 0 未知 if (object.contains("is_prompt")) { // 提示 if (object["is_prompt"].toInt() == 2) { if (type == "游戏" || type == "game") { } else { // const QString name = object["name"].toString(); // const QString zhName = object["chinese_name"].toString(); const int time = object["prompt_time"].toInt(); if (time > 0) { const QString whereTime = QString("(updataTime - lastAlertTime) > %1") .arg(time); const QString whereProcessName = QString("processName = '%1'").arg(name); const QString whereUpdataTime = QString("updataTime = '%1'").arg(updataTime); CWF::SqlQueryManager qry(storage); qry.select("*", processModel.getTableName()) .where(QString("%1 AND %2 AND %3") .arg(whereTime) .arg(whereProcessName) .arg(whereUpdataTime)); qry.prepare(); QJsonObject jsonObject = qry.exec(); QJsonArray jsonArray = qry.toJson(); qDebug() << jsonArray; for (const auto &value : jsonArray) { const QJsonObject object = value.toObject(); const QString processName = object["processName"].toString(); const qint64 runTime = object["exitTime"].toVariant().toLongLong() - object["creationTime"].toVariant().toLongLong(); const QString text = QString( tr("Program %1 has been used for %2 minutes%3") .arg(zhName) .arg(convertSecondsToMinutesTimeFormat(runTime)) .arg(messageText.toString())); emit messageBox(text, messageBoxPointX, messageBoxPointY, messageTitle); // 更新 lastAlertTime ProcessModel processModel{storage}; processModel.buildFromJson(object); // 更新 消息时间 processModel.setLastAlertTime(updataTime); processModel.save(); } } } } } if (object.contains("pid_type")) { if (type == "游戏" || type == "game") { const QString whereTime = QString("(updataTime - lastAlertTime) > %1").arg(1); const QString whereProcessName = QString("processName = '%1'").arg(name); const QString whereUpdataTime = QString("updataTime = '%1'").arg(updataTime); CWF::SqlQueryManager qry(storage); qry.select("*", processModel.getTableName()) .where(QString("%1 AND %2 AND %3") .arg(whereTime) .arg(whereProcessName) .arg(whereUpdataTime)); qry.prepare(); QJsonObject jsonObject = qry.exec(); QJsonArray jsonArray = qry.toJson(); for (const auto &value : jsonArray) { const QJsonObject object = value.toObject(); const QString processName = object["processName"].toString(); const qint64 runTime = object["exitTime"].toVariant().toLongLong() - object["creationTime"].toVariant().toLongLong(); const QString text = QString(tr("Program %1 has been used for %2 minutes%3") .arg(zhName) .arg(convertSecondsToMinutesTimeFormat(runTime)) .arg(messageText.toString())); qDebug() << "玩游戏?" << text; QTemporaryFile tempFile("tempfile_XXXXXX.png"); tempFile.setAutoRemove(true); tempFile.open(); AppEvent::captureDesktop(&tempFile, "PNG"); // qDebug() << "发送截图" << tempFile.fileName(); TC::ProcessImageApi processImageApi; qDebug() << "发送截图" << processImageApi.post({tempFile.fileName()}); tempFile.close(); qDebug() << "发送截图" << tempFile.remove() << tempFile.errorString(); // if (object.contains("is_prompt")) { // 提示 // if (object["is_prompt"].toInt() == 2) { // } // } const QString message = gameMessageText.toString().isEmpty() ? text : gameMessageText.toString(); emit messageBox(message, messageBoxPointX, messageBoxPointY, messageTitle); QProcess p; p.startDetached("taskkill", {"/im", name, "/f"}); p.waitForFinished(3000); p.close(); // 更新 lastAlertTime ProcessModel processModel{storage}; processModel.buildFromJson(object); // 更新 消息时间 processModel.setLastAlertTime(updataTime); processModel.save(); } // 获取游戏 截图 并关闭进程 // QTemporaryFile tempFile("tempfile_XXXXXX.png"); // tempFile.setAutoRemove(true); // tempFile.open(); // AppEvent::captureDesktop(&tempFile, "PNG"); // qDebug() << "发送截图" << tempFile.fileName(); // TC::ProcessImageApi processImageApi; // qDebug() << "发送截图" << processImageApi.post({tempFile.fileName()}); // tempFile.close(); // qDebug() << "发送截图" << tempFile.remove() << tempFile.errorString(); // if (object.contains("is_prompt")) { // 提示 // if (object["is_prompt"].toInt() == 2) { // } // } } } } } bool ProcessThread::upDataProcessSql() { std::vector> timeProcessVector = processMonitor.checkProcesses(); // 退出时间默认当前时间 然后更新 auto exitTimestamp = QDateTime::currentSecsSinceEpoch(); auto updataTimestamp = QDateTime::currentSecsSinceEpoch(); QStringList sqlValues; for (auto timeProcess : timeProcessVector) { qint64 timestamp = fileTimeToUnixTimestamp(timeProcess->creationTime); ProcessModel processModel{storage}; CWF::SqlQueryManager qry(storage); qry.select("*", processModel.getTableName()) .where(QString("pid == '%1' AND processName == '%2'") .arg(timeProcess->pid) .arg(timeProcess->processName.c_str())); qry.prepare(); QJsonObject jsonObject = qry.exec(); if (jsonObject["success"].toBool()) { // 查询或者替换 ? QJsonArray array = qry.toJson(); if (array.size() > 0) { // 替换 for (const QJsonValue &info : array) { const QJsonObject object = info.toObject(); //数据还原到 结构体 processModel.buildFromJson(object); // 更新 结束时间 processModel.setExitTime(exitTimestamp); processModel.setUpdataTime(updataTimestamp); processModel.save(); } } else { // 插入数据 processModel.setProcessName(timeProcess->processName.c_str()); processModel.setPid(timeProcess->pid); processModel.setCreationTime(timestamp); processModel.setExitTime(exitTimestamp); processModel.setUpdataTime(updataTimestamp); processModel.setLastAlertTime(updataTimestamp); processModel.save(); } } } // 发送更新后的数据 sendExitTime(updataTimestamp); return false; } ProcessThread::ProcessThread( QObject *parent) : QThread{parent} {} void ProcessThread::run() { ProcessModel processModel{storage}; processModel.updateDB(); { const QString query = QString("CREATE UNIQUE INDEX %2_%3_unique ON %1 (%2, %3);") .arg(processModel.getTableName()) .arg("pid") .arg("processName"); CWF::SqlQuery qry(storage); qry.exec(query); } QElapsedTimer timer; // 创建高精度计时器 timer.start(); // 启动计时器 upDataProcessSql(); while (true) { // 校验网络 if (timer.elapsed() >= 10 * 1000) { // 检查是否经过1分钟 timer.restart(); // 重新启动计时器 upDataProcessSql(); } msleep(1000); // 休息1秒 } }