#include #include #include #include #include #include #include #include "UpdateLogic.h" #include "../Common/ConfigHelper.h" #include "../Common/PolicyHelper.h" #include "../Common/LocalStateHelper.h" int main(int argc, char* argv[]) { SetConsoleOutputCP(65001); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); QApplication app(argc, argv); QApplication::setApplicationName("Marsco Launcher"); QProgressDialog progress("正在检查软件更新...", QString(), 0, 0); progress.setWindowTitle("Marsco 软件启动器"); progress.setCancelButton(nullptr); progress.setWindowModality(Qt::ApplicationModal); progress.setMinimumDuration(0); progress.setAutoClose(false); progress.show(); QApplication::processEvents(); UpdateLogic logic; logic.checkUpdate(); const bool needUpdate = logic.getNeedUpdate(); const bool networkOk = logic.isNetworkOk(); const QString latestVer = logic.getLatestVersion(); const QJsonObject response = logic.getCheckResult(); const int targetVersionId = response.value("version_id").toInt(); const QString appId = logic.getAppId(); const QString channel = logic.getChannel(); ConfigHelper& config = ConfigHelper::instance(); const QString launchToken = config.getValue("App", "launch_token"); const QString currentVersion = config.getValue("App", "current_version"); const QString appDir = QApplication::applicationDirPath(); const QString mainAppPath = appDir + "/MainApp.exe"; const QString updaterPath = appDir + "/Updater.exe"; const QStringList mainArgs{QString("--launcher-token=%1").arg(launchToken)}; progress.setLabelText("正在验证本地运行策略..."); QApplication::processEvents(); PolicyHelper policy(appDir); if (!policy.loadPolicy("config/version_policy.dat") || !policy.isValid()) { progress.close(); QMessageBox::critical(nullptr, "无法启动", QString("本地版本策略无效:%1").arg(policy.errorString())); return -1; } if (policy.isExpired()) { progress.close(); QMessageBox::critical(nullptr, "无法启动", "本地版本策略已过期,请连接网络或联系管理员。"); return -1; } if ((!policy.allowRun() || !policy.isVersionAllowed(currentVersion)) && !(networkOk && needUpdate)) { progress.close(); QMessageBox::critical(nullptr, "当前版本不可运行", policy.message().isEmpty() ? QString("当前版本 %1 已被管理员停用。").arg(currentVersion) : policy.message()); return -1; } LocalStateHelper state(appDir); if (!state.loadState()) { progress.close(); QMessageBox::critical(nullptr, "无法启动", QString("无法读取本地状态:%1").arg(state.errorString())); return -1; } if (state.isPolicySeqRolledBack(policy.policySeq())) { progress.close(); QMessageBox::critical(nullptr, "安全检查失败", "检测到版本策略序列回退,已阻止启动。"); return -1; } if (state.isSystemTimeRewound()) { progress.close(); QMessageBox::critical(nullptr, "安全检查失败", "检测到系统时间可能被回拨,已阻止启动。"); return -1; } if (networkOk && needUpdate) { progress.close(); const bool rollbackOperation = response.value("action").toString() == "rollback_allowed"; const QString dialogTitle = rollbackOperation ? "版本回退" : (policy.forceUpdate() ? "必须更新" : "发现新版本"); const QString prompt = policy.message().isEmpty() ? QString(rollbackOperation ? "管理员提供了版本 %1 作为回退目标,是否现在降级?" : "发现新版本 %1,是否现在更新?").arg(latestVer) : policy.message() + QString("\n目标版本:%1").arg(latestVer); bool accepted = true; if (policy.forceUpdate()) { QMessageBox::information(nullptr, dialogTitle, prompt); } else { accepted = QMessageBox::question(nullptr, dialogTitle, prompt, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; } if (!accepted) { if (!QProcess::startDetached(mainAppPath, mainArgs)) { QMessageBox::critical(nullptr, "启动失败", QString("无法启动主程序:%1").arg(mainAppPath)); return -1; } return 0; } const QStringList updaterArgs{appId, channel, latestVer, QString::number(targetVersionId)}; if (!QProcess::startDetached(updaterPath, updaterArgs)) { QMessageBox::critical(nullptr, "更新器启动失败", QString("无法启动更新器:%1").arg(updaterPath)); return -1; } return 0; } if (!networkOk && !policy.isOfflineAllowed()) { progress.close(); QMessageBox::critical(nullptr, "网络不可用", "无法连接更新服务器,且当前策略不允许离线启动。"); return -1; } progress.setLabelText(networkOk ? "当前已是最新版本,正在启动..." : "当前处于离线模式,正在启动..."); QApplication::processEvents(); if (!QProcess::startDetached(mainAppPath, mainArgs)) { progress.close(); QMessageBox::critical(nullptr, "启动失败", QString("无法启动主程序:%1").arg(mainAppPath)); return -1; } progress.close(); return 0; }