功能:新增桌面连接配置持久化(desktops.json)

This commit is contained in:
宋一鸣 2026-10-29 02:09:57 -04:00
parent 921f4c7798
commit 28f79e674b

View File

@ -0,0 +1,160 @@
#include "desktop_store.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include "config.h"
namespace vdi {
namespace {
// 三张默认桌面卡:id/name/os 固定,连接参数由现场配置。
// endpoint 为空 = 待分配,配置地址后即变为可连接。
std::vector<DesktopInfo> defaultDesktops(const QString& migratedServer) {
std::vector<DesktopInfo> list;
DesktopInfo win;
win.id = QStringLiteral("desk-win10-01");
win.name = QStringLiteral("Windows 10");
win.os = QStringLiteral("Windows 桌面");
win.protocol = Protocol::kMoonlight;
win.endpoint = migratedServer; // 兼容老盒子:迁移 client.conf 的 server
win.app = QStringLiteral("Desktop");
win.width = 1920;
win.height = 1080;
win.fps = 60;
list.push_back(win);
DesktopInfo ubuntu;
ubuntu.id = QStringLiteral("desk-ubuntu-01");
ubuntu.name = QStringLiteral("Ubuntu");
ubuntu.os = QStringLiteral("Ubuntu 桌面");
ubuntu.protocol = Protocol::kRdp;
list.push_back(ubuntu);
DesktopInfo kylin;
kylin.id = QStringLiteral("desk-kylin-01");
kylin.name = QStringLiteral("麒麟");
kylin.os = QStringLiteral("银河麒麟桌面");
kylin.protocol = Protocol::kRdp;
list.push_back(kylin);
return list;
}
DesktopInfo fromJson(const QJsonObject& obj) {
DesktopInfo d;
d.id = obj.value(QStringLiteral("id")).toString();
d.name = obj.value(QStringLiteral("name")).toString();
d.os = obj.value(QStringLiteral("os")).toString();
d.protocol = obj.value(QStringLiteral("protocol")).toString() == QStringLiteral("rdp")
? Protocol::kRdp
: Protocol::kMoonlight;
d.endpoint = obj.value(QStringLiteral("endpoint")).toString();
d.app = obj.value(QStringLiteral("app")).toString();
d.width = obj.value(QStringLiteral("width")).toInt(1920);
d.height = obj.value(QStringLiteral("height")).toInt(1080);
d.fps = obj.value(QStringLiteral("fps")).toInt(60);
d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable;
return d;
}
QJsonObject toJson(const DesktopInfo& d) {
QJsonObject obj;
obj.insert(QStringLiteral("id"), d.id);
obj.insert(QStringLiteral("name"), d.name);
obj.insert(QStringLiteral("os"), d.os);
obj.insert(QStringLiteral("protocol"),
d.protocol == Protocol::kRdp ? QStringLiteral("rdp") : QStringLiteral("moonlight"));
obj.insert(QStringLiteral("endpoint"), d.endpoint);
obj.insert(QStringLiteral("app"), d.app);
obj.insert(QStringLiteral("width"), d.width);
obj.insert(QStringLiteral("height"), d.height);
obj.insert(QStringLiteral("fps"), d.fps);
return obj;
}
} // namespace
QString DesktopStore::storePath() {
return QString::fromStdString(configDir()) + QStringLiteral("/desktops.json");
}
std::vector<DesktopInfo> DesktopStore::load() {
std::vector<DesktopInfo> result;
QFile file(storePath());
if (file.exists() && file.open(QIODevice::ReadOnly)) {
const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
const QJsonArray arr = doc.object().value(QStringLiteral("desktops")).toArray();
for (const QJsonValue& v : arr) {
DesktopInfo d = fromJson(v.toObject());
if (!d.id.isEmpty()) {
result.push_back(d);
}
}
}
// 确保三张默认卡始终存在(新环境骨架 / 防止手工编辑删卡)。
// 兼容老盒子:client.conf 里只要配过 server,就迁移为 Windows 桌面地址。
const TerminalConfig cfg = loadConfig();
const QString migrated = result.empty() && !cfg.server.empty()
? QString::fromStdString(cfg.server)
: QString();
const std::vector<DesktopInfo> defaults = defaultDesktops(migrated);
for (const DesktopInfo& def : defaults) {
bool found = false;
for (const DesktopInfo& d : result) {
if (d.id == def.id) {
found = true;
break;
}
}
if (!found) {
result.push_back(def);
}
}
// 统一按 endpoint 推导状态:有地址=可连接,无地址=待分配
for (DesktopInfo& d : result) {
d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable;
}
return result;
}
bool DesktopStore::save(const std::vector<DesktopInfo>& desktops) {
QJsonArray arr;
for (const DesktopInfo& d : desktops) {
arr.append(toJson(d));
}
QJsonObject root;
root.insert(QStringLiteral("version"), 1);
root.insert(QStringLiteral("desktops"), arr);
const QString path = storePath();
QDir().mkpath(QFileInfo(path).absolutePath());
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return false;
}
file.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
return true;
}
bool DesktopStore::update(const DesktopInfo& info) {
std::vector<DesktopInfo> list = load();
for (DesktopInfo& d : list) {
if (d.id == info.id) {
d = info;
d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable;
return save(list);
}
}
return false;
}
} // namespace vdi