| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- #include "processthread.h"
- #include <QProcess>
- #include <QSettings>
- #include <QTemporaryFile>
- #include "api/configapi.h"
- #include "appevent.h"
- #include "processmodel.h"
- #include "qjsonarray.h"
- #include "qjsonobject.h"
- #include <cwf/sqldatabasestorage.h>
- #include <optional>
- #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);
- }
- static QVariant config()
- {
- QSettings settings(QSettings::NativeFormat,
- QSettings::UserScope,
- QCoreApplication::organizationName(),
- QCoreApplication::applicationName());
- settings.beginGroup("config");
- QVariant value;
- if (settings.contains("serverConfig")) {
- value = settings.value("serverConfig");
- } else {
- value = R"Raw([
- {
- "uuid": "3d8a0525-76fa-45bb-b0db-ed7260e31bdc",
- "name": "sldworks.exe",
- "chinese_name": "SolidWorks",
- "pid_type": "学习",
- "is_confirmed": 1,
- "is_prompt": 2,
- "prompt_type": "",
- "prompt_time": 2400,
- "path": "",
- "notes": "",
- "c_time": 1734346737,
- "u_time": 0
- },
- {
- "uuid": "daa98539-fb91-4eb6-a59f-0fd4509e926c",
- "name": "sldworks_fs.exe",
- "chinese_name": "SolidWorks",
- "pid_type": "学习",
- "is_confirmed": 2,
- "is_prompt": 1,
- "prompt_type": "",
- "prompt_time": 120,
- "path": "",
- "notes": "",
- "c_time": 1733906424,
- "u_time": 0
- },
- {
- "uuid": "d09df0b1-2386-4527-afa7-3f1fb37b6171",
- "name": "SLDWORKS.exe",
- "chinese_name": "SolidWorks",
- "pid_type": "学习",
- "is_confirmed": 1,
- "is_prompt": 2,
- "prompt_type": "",
- "prompt_time": 2400,
- "path": "",
- "notes": "",
- "c_time": 1733652641,
- "u_time": 0
- },
- {
- "uuid": "c4de744f-0afe-4e0f-a39e-7ee59f46c042",
- "name": "WeChat.exe",
- "chinese_name": "微信",
- "pid_type": "日常",
- "is_confirmed": 1,
- "is_prompt": 2,
- "prompt_type": "",
- "prompt_time": 15,
- "path": "2",
- "notes": "测试",
- "c_time": 1733455089,
- "u_time": 0
- }
- ])Raw";
- }
- settings.endGroup();
- return value;
- }
- const QJsonArray processNameArray()
- {
- TC::ProcessNameApi processNameApi;
- QJsonArray serverArray = processNameApi.get();
- if (serverArray.isEmpty()) {
- // 读取本地配置 转 QJsonArray
- const QString configText = config().toString();
- QJsonDocument jsonDoc = QJsonDocument::fromJson(configText.toUtf8());
- if (jsonDoc.isArray()) {
- serverArray = jsonDoc.array();
- } else if (jsonDoc.isObject()) {
- // If the config is a single object, we can wrap it in an array
- serverArray.append(jsonDoc.object());
- }
- } else {
- // 写入本地配置
- QSettings settings(QSettings::NativeFormat,
- QSettings::UserScope,
- QCoreApplication::organizationName(),
- QCoreApplication::applicationName());
- settings.beginGroup("config");
- settings.setValue("serverArray",
- QString(QJsonDocument(serverArray).toJson(QJsonDocument::Compact)));
- settings.endGroup();
- }
- return serverArray;
- }
- void ProcessThread::sendExitTime(qint64 updataTime)
- {
- serverConfig();
- QJsonArray serverArray = processNameArray();
- // 获取过滤名单
- QSet<QString> filter;
- QSet<QString> 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);
- }
- }
- }
- // 发送数据到服务器
- sendToServer(filter, updataTime);
- ProcessModel processModel{storage};
- // 获取服务器 对应的时间信息
- 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()));
- 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();
- 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();
- }
- }
- }
- }
- }
- void ProcessThread::sendToServer(const QSet<QString> &filter, qint64 updataTime)
- {
- 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();
- }
- }
- }
- bool ProcessThread::upDataProcessSql()
- {
- std::vector<std::shared_ptr<ProcessMonitor::ProcessInfo>> 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}
- , messageBoxPointX(QVariant())
- , messageBoxPointY(QVariant())
- , messageText(QVariant(""))
- , gameMessageText(QVariant(""))
- , messageTitle(QVariant(Tr::tr("Tips")))
- {}
- bool ProcessThread::serverConfig()
- {
- QSettings settings(QSettings::NativeFormat,
- QSettings::UserScope,
- QCoreApplication::organizationName(),
- QCoreApplication::applicationName());
- settings.beginGroup("config");
- // 获取配置
- // QVariant messageBoxPointX = QVariant();
- // QVariant messageBoxPointY = QVariant();
- // QVariant messageText = QVariant("");
- // QVariant gameMessageText = QVariant("");
- // QVariant messageTitle = QVariant(Tr::tr("Tips"));
- {
- TC::ConfigApi configApi("messageBoxPointX");
- std::optional<QVariant> value = configApi.get();
- if (value.has_value()) {
- messageBoxPointX = value.value();
- settings.setValue("messageBoxPointX", messageBoxPointX);
- } else {
- if (settings.contains("messageBoxPointX")) {
- messageBoxPointX = settings.value("messageBoxPointX");
- }
- }
- }
- {
- TC::ConfigApi configApi("messageBoxPointY");
- std::optional<QVariant> value = configApi.get();
- if (value.has_value()) {
- messageBoxPointY = value.value();
- settings.setValue("messageBoxPointY", messageBoxPointY);
- } else {
- if (settings.contains("messageBoxPointX")) {
- messageBoxPointY = settings.value("messageBoxPointY");
- }
- }
- }
- {
- TC::ConfigApi configApi("messageText");
- std::optional<QVariant> value = configApi.get();
- if (value.has_value()) {
- messageText = value.value();
- settings.setValue("messageText", messageText);
- } else {
- if (settings.contains("messageText")) {
- messageText = settings.value("messageText");
- } else {
- messageText = ", 请运动一下";
- }
- }
- }
- {
- TC::ConfigApi configApi("messageTitle");
- std::optional<QVariant> value = configApi.get();
- if (value.has_value()) {
- messageTitle = value.value();
- settings.setValue("messageTitle", messageTitle);
- } else {
- if (settings.contains("messageTitle")) {
- messageTitle = settings.value("messageTitle");
- } else {
- messageTitle = "提示";
- }
- }
- }
- {
- TC::ConfigApi configApi("gameMessageText");
- std::optional<QVariant> value = configApi.get();
- if (value.has_value()) {
- gameMessageText = value.value();
- settings.setValue("gameMessageText", gameMessageText);
- } else {
- if (settings.contains("gameMessageText")) {
- gameMessageText = settings.value("gameMessageText");
- } else {
- gameMessageText = "请不要玩游戏";
- }
- }
- }
- settings.endGroup();
- return true;
- };
- 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秒
- }
- }
|