diff --git a/terminal/kiosk-shell/src/desktop_store.cpp b/terminal/kiosk-shell/src/desktop_store.cpp new file mode 100644 index 0000000..824b382 --- /dev/null +++ b/terminal/kiosk-shell/src/desktop_store.cpp @@ -0,0 +1,160 @@ +#include "desktop_store.h" + +#include +#include +#include +#include +#include +#include + +#include "config.h" + +namespace vdi { +namespace { + +// 三张默认桌面卡:id/name/os 固定,连接参数由现场配置。 +// endpoint 为空 = 待分配,配置地址后即变为可连接。 +std::vector defaultDesktops(const QString& migratedServer) { + std::vector 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 DesktopStore::load() { + std::vector 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 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& 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 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