feat: 支持 Linux 客户端打包与跨平台运行
This commit is contained in:
+96
-10
@@ -284,6 +284,26 @@ ConfigHelper& ConfigHelper::instance()
|
||||
return obj;
|
||||
}
|
||||
|
||||
QString ConfigHelper::executableNameForCurrentPlatform(const QString& configuredValue,
|
||||
const QString& fallbackBaseName)
|
||||
{
|
||||
QString name = configuredValue.trimmed();
|
||||
if (name.isEmpty())
|
||||
name = fallbackBaseName.trimmed();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
const QString fileName = QFileInfo(name).fileName();
|
||||
if (!fileName.endsWith(QStringLiteral(".exe"), Qt::CaseInsensitive)
|
||||
&& QFileInfo(fileName).suffix().isEmpty()) {
|
||||
name += QStringLiteral(".exe");
|
||||
}
|
||||
#else
|
||||
if (name.endsWith(QStringLiteral(".exe"), Qt::CaseInsensitive))
|
||||
name.chop(4);
|
||||
#endif
|
||||
return name;
|
||||
}
|
||||
|
||||
int ConfigHelper::runElevatedWriteCommandIfRequested()
|
||||
{
|
||||
const QStringList arguments = QCoreApplication::arguments();
|
||||
@@ -486,11 +506,30 @@ bool ConfigHelper::syncRegistryFromConfigFileIfChanged()
|
||||
if (previousHash == sourceHash)
|
||||
return true;
|
||||
|
||||
const QJsonObject config = document.object();
|
||||
if (config.isEmpty())
|
||||
{
|
||||
settings.beginGroup(kRegistryMetaGroup);
|
||||
settings.setValue(kRegistrySourceHashKey, sourceHash);
|
||||
settings.setValue(kRegistrySourcePathKey, QDir::toNativeSeparators(QFileInfo(m_configPath).absoluteFilePath()));
|
||||
settings.setValue(kRegistryRuntimeRootKey, QDir::toNativeSeparators(QApplication::applicationDirPath()));
|
||||
settings.setValue(kRegistryImportedAtKey, QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
|
||||
settings.endGroup();
|
||||
settings.sync();
|
||||
if (settings.status() != QSettings::NoError)
|
||||
{
|
||||
m_error = QStringLiteral("Cannot sync empty app_config.json marker to registry.");
|
||||
return false;
|
||||
}
|
||||
m_error.clear();
|
||||
qDebug() << "app_config.json is empty; keeping existing registry configuration.";
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool configChangedAfterPreviousImport = !previousHash.isEmpty();
|
||||
|
||||
settings.beginGroup(kRegistryConfigGroup);
|
||||
settings.remove(QString());
|
||||
const QJsonObject config = document.object();
|
||||
for (auto it = config.constBegin(); it != config.constEnd(); ++it)
|
||||
settings.setValue(it.key(), it.value().toVariant());
|
||||
settings.endGroup();
|
||||
@@ -517,7 +556,8 @@ bool ConfigHelper::syncRegistryFromConfigFileIfChanged()
|
||||
const QString configDir = QFileInfo(m_configPath).absolutePath();
|
||||
const QStringList staleFiles{
|
||||
QDir(configDir).filePath(QStringLiteral("client_identity.dat")),
|
||||
QDir(configDir).filePath(QStringLiteral("version_policy.dat"))
|
||||
QDir(configDir).filePath(QStringLiteral("version_policy.dat")),
|
||||
QDir(configDir).filePath(QStringLiteral("local_state.json"))
|
||||
};
|
||||
for (const QString& staleFile : staleFiles)
|
||||
{
|
||||
@@ -529,8 +569,48 @@ bool ConfigHelper::syncRegistryFromConfigFileIfChanged()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
qDebug() << "Removed stale client identity and policy after app_config.json changed.";
|
||||
qDebug() << "Removed stale client identity, policy and local state after app_config.json changed.";
|
||||
}
|
||||
|
||||
if (!config.isEmpty() && !sanitizeConfigFileAfterImport(settings))
|
||||
{
|
||||
qWarning() << "Cannot sanitize app_config.json after registry import:" << m_error;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigHelper::sanitizeConfigFileAfterImport(QSettings& settings)
|
||||
{
|
||||
const QJsonObject emptyConfig;
|
||||
const QByteArray normalizedEmptyConfig = QJsonDocument(emptyConfig).toJson(QJsonDocument::Compact);
|
||||
const QByteArray emptyFileBytes = QJsonDocument(emptyConfig).toJson(QJsonDocument::Indented);
|
||||
const QString sanitizedHash = QString::fromLatin1(
|
||||
QCryptographicHash::hash(normalizedEmptyConfig, QCryptographicHash::Sha256).toHex());
|
||||
|
||||
QString writeError;
|
||||
if (!ConfigHelper::writeFileWithElevationIfNeeded(m_configPath, emptyFileBytes, &writeError))
|
||||
{
|
||||
m_error = QStringLiteral("Cannot clear app_config.json after registry import: %1").arg(writeError);
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.beginGroup(kRegistryMetaGroup);
|
||||
settings.setValue(kRegistrySourceHashKey, sanitizedHash);
|
||||
settings.setValue(kRegistrySourcePathKey, QDir::toNativeSeparators(QFileInfo(m_configPath).absoluteFilePath()));
|
||||
settings.setValue(kRegistryRuntimeRootKey, QDir::toNativeSeparators(QApplication::applicationDirPath()));
|
||||
settings.setValue(kRegistryImportedAtKey, QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
|
||||
settings.endGroup();
|
||||
settings.sync();
|
||||
|
||||
if (settings.status() != QSettings::NoError)
|
||||
{
|
||||
m_error = QStringLiteral("Cannot update registry source hash after clearing app_config.json.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_error.clear();
|
||||
qDebug() << "Cleared app_config.json after importing configuration to registry.";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -631,13 +711,19 @@ bool ConfigHelper::migrateLegacyIniIfNeeded()
|
||||
copyText("Update", "temp_folder", "update_temp");
|
||||
copyText("Update", "device_id");
|
||||
copyText("Runtime", "install_root", ".");
|
||||
copyText("Runtime", "main_executable", "MainApp.exe");
|
||||
copyText("Runtime", "launcher_executable", "Launcher.exe");
|
||||
copyText("Runtime", "updater_executable", "Updater.exe");
|
||||
copyText("Runtime", "bootstrap_executable", "Bootstrap.exe");
|
||||
copyText("Runtime", "health_check_timeout_ms", "15000");
|
||||
config.insert("platform", "windows");
|
||||
config.insert("arch", "x64");
|
||||
copyText("Runtime", "main_executable", ConfigHelper::executableNameForCurrentPlatform(QString(), "MainApp"));
|
||||
copyText("Runtime", "launcher_executable", ConfigHelper::executableNameForCurrentPlatform(QString(), "Launcher"));
|
||||
copyText("Runtime", "updater_executable", ConfigHelper::executableNameForCurrentPlatform(QString(), "Updater"));
|
||||
copyText("Runtime", "bootstrap_executable", ConfigHelper::executableNameForCurrentPlatform(QString(), "Bootstrap"));
|
||||
copyText("Runtime", "health_check_timeout_ms", "15000");
|
||||
#ifdef Q_OS_WIN
|
||||
config.insert("platform", "windows");
|
||||
#elif defined(Q_OS_LINUX)
|
||||
config.insert("platform", "linux");
|
||||
#else
|
||||
config.insert("platform", "unknown");
|
||||
#endif
|
||||
config.insert("arch", "x64");
|
||||
|
||||
QDir().mkpath(QFileInfo(m_configPath).path());
|
||||
QSaveFile output(m_configPath);
|
||||
|
||||
Reference in New Issue
Block a user