161 lines
5.4 KiB
C++
161 lines
5.4 KiB
C++
#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::kMoonlight;
|
||
list.push_back(ubuntu);
|
||
|
||
DesktopInfo kylin;
|
||
kylin.id = QStringLiteral("desk-kylin-01");
|
||
kylin.name = QStringLiteral("麒麟");
|
||
kylin.os = QStringLiteral("银河麒麟桌面");
|
||
kylin.protocol = Protocol::kMoonlight;
|
||
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();
|
||
// 协议统一 Moonlight:RDP 渲染路径实测差(CPU 高、卷帘),本地配置不再提供
|
||
// RDP 选项;RDP 代码保留作网关备用,协议字段仅在平台票据层区分。
|
||
d.protocol = 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
|