mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-22 04:23:06 +08:00
[fix] support self-hosted server URLs with paths
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include "SimpleIni.h"
|
#include "SimpleIni.h"
|
||||||
#include "autostart.h"
|
#include "autostart.h"
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
|
#include "signal_server_address.h"
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
@@ -290,10 +291,23 @@ int ConfigCenter::SetTurn(bool enable_turn, bool force_relay) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ConfigCenter::SetServerHost(const std::string& host) {
|
int ConfigCenter::SetServerHost(const std::string& host) {
|
||||||
if (host.empty() || host.size() > 253 || host.find_first_of("/\\@?#") != std::string::npos ||
|
const auto address = minirtc::ParseSignalServerAddress(host);
|
||||||
std::any_of(host.begin(), host.end(), [](unsigned char c) { return c <= 32 || c == 127; })) return -1;
|
if (!address) return -1;
|
||||||
if (StoreValues({{"signal_server_host", host}}) != 0) return -1;
|
if (address->port) return SetServerEndpoint(host, *address->port);
|
||||||
signal_server_host_ = host;
|
if (StoreValues({{"signal_server_host", address->Address()}}) != 0) return -1;
|
||||||
|
signal_server_host_ = address->Address();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConfigCenter::SetServerEndpoint(const std::string& host, int port) {
|
||||||
|
const auto address = minirtc::ParseSignalServerAddress(host);
|
||||||
|
if (!address) return -1;
|
||||||
|
port = address->port.value_or(port);
|
||||||
|
if (port < 1 || port > 65535) return -1;
|
||||||
|
if (StoreValues({{"signal_server_host", address->Address()},
|
||||||
|
{"signal_server_port", std::to_string(port)}}) != 0) return -1;
|
||||||
|
signal_server_host_ = address->Address();
|
||||||
|
signal_server_port_ = port;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class ConfigCenter {
|
|||||||
int SetTurn(bool enable_turn, bool force_relay);
|
int SetTurn(bool enable_turn, bool force_relay);
|
||||||
int SetServerHost(const std::string& signal_server_host);
|
int SetServerHost(const std::string& signal_server_host);
|
||||||
int SetServerPort(int signal_server_port);
|
int SetServerPort(int signal_server_port);
|
||||||
|
int SetServerEndpoint(const std::string& address, int port);
|
||||||
int SetSelfHosted(bool enable_self_hosted);
|
int SetSelfHosted(bool enable_self_hosted);
|
||||||
int SetAutostart(bool enable_autostart);
|
int SetAutostart(bool enable_autostart);
|
||||||
int SetDaemon(bool enable_daemon);
|
int SetDaemon(bool enable_daemon);
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
#include "server_window_state.h"
|
#include "server_window_state.h"
|
||||||
#include "signal_server_settings.h"
|
#include "signal_server_settings.h"
|
||||||
|
#include "signal_server_address.h"
|
||||||
#include "ui/announcement_text.h"
|
#include "ui/announcement_text.h"
|
||||||
#include "ui/ui_localization.h"
|
#include "ui/ui_localization.h"
|
||||||
#include "update_checker.h"
|
#include "update_checker.h"
|
||||||
@@ -1285,6 +1286,7 @@ void GuiApplication::ResetSettingsUi() {
|
|||||||
ui_->main->set_file_save_path(file_transfer_save_path_buf_);
|
ui_->main->set_file_save_path(file_transfer_save_path_buf_);
|
||||||
ui_->main->set_server_host(signal_server_ip_self_);
|
ui_->main->set_server_host(signal_server_ip_self_);
|
||||||
ui_->main->set_server_port(signal_server_port_self_);
|
ui_->main->set_server_port(signal_server_port_self_);
|
||||||
|
ui_->main->set_self_host_settings_error("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::BindMainCallbacks() {
|
void GuiApplication::BindMainCallbacks() {
|
||||||
@@ -1419,29 +1421,14 @@ void GuiApplication::BindMainCallbacks() {
|
|||||||
ui_->main->set_file_save_path(folder);
|
ui_->main->set_file_save_path(folder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
main->on_save_settings([this] { SaveSettingsFromUi(); });
|
main->on_save_settings([this] { return SaveSettingsFromUi(); });
|
||||||
main->on_cancel_settings([this] { ResetSettingsUi(); });
|
main->on_cancel_settings([this] { ResetSettingsUi(); });
|
||||||
main->on_save_self_hosted_settings([this] {
|
main->on_save_self_hosted_settings([this] {
|
||||||
const std::string host(ui_->main->get_server_host());
|
// Stage the endpoint until the surrounding settings dialog is confirmed.
|
||||||
const auto signal_port = ParsePort(ui_->main->get_server_port());
|
return ValidateSelfHostedSettingsFromUi();
|
||||||
if (!host.empty()) {
|
|
||||||
config_center_->SetServerHost(host);
|
|
||||||
std::memset(signal_server_ip_self_, 0, sizeof(signal_server_ip_self_));
|
|
||||||
std::strncpy(signal_server_ip_self_, host.c_str(),
|
|
||||||
sizeof(signal_server_ip_self_) - 1);
|
|
||||||
std::memset(signal_server_ip_, 0, sizeof(signal_server_ip_));
|
|
||||||
std::strncpy(signal_server_ip_, host.c_str(),
|
|
||||||
sizeof(signal_server_ip_) - 1);
|
|
||||||
}
|
|
||||||
if (signal_port) {
|
|
||||||
config_center_->SetServerPort(*signal_port);
|
|
||||||
std::snprintf(signal_server_port_self_, sizeof(signal_server_port_self_),
|
|
||||||
"%d", *signal_port);
|
|
||||||
std::snprintf(signal_server_port_, sizeof(signal_server_port_), "%d",
|
|
||||||
*signal_port);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
main->on_cancel_self_hosted_settings([this] {
|
main->on_cancel_self_hosted_settings([this] {
|
||||||
|
ui_->main->set_self_host_settings_error("");
|
||||||
const std::string host = config_center_->GetSignalServerHost();
|
const std::string host = config_center_->GetSignalServerHost();
|
||||||
ui_->main->set_server_host(UiText(host));
|
ui_->main->set_server_host(UiText(host));
|
||||||
const int signal_port = config_center_->GetSignalServerPort();
|
const int signal_port = config_center_->GetSignalServerPort();
|
||||||
@@ -3496,9 +3483,45 @@ void GuiApplication::SyncServerWindow() {
|
|||||||
PositionServerWindows();
|
PositionServerWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::SaveSettingsFromUi() {
|
bool GuiApplication::ValidateSelfHostedSettingsFromUi() {
|
||||||
|
auto& main = ui_->main;
|
||||||
|
const auto address = minirtc::ParseSignalServerAddress(
|
||||||
|
std::string(main->get_server_host()));
|
||||||
|
if (!address) {
|
||||||
|
main->set_self_host_settings_error(UiText(
|
||||||
|
localization::self_hosted_address_invalid[localization_language_index_]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto port = address->port ? address->port : ParsePort(main->get_server_port());
|
||||||
|
if (!port) {
|
||||||
|
main->set_self_host_settings_error(UiText(
|
||||||
|
localization::self_hosted_port_invalid[localization_language_index_]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
main->set_server_host(UiText(address->Address()));
|
||||||
|
main->set_server_port(UiText(std::to_string(*port)));
|
||||||
|
main->set_self_host_settings_error("");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GuiApplication::SaveSettingsFromUi() {
|
||||||
const auto previous_server = GetSignalServerSettings(*config_center_);
|
const auto previous_server = GetSignalServerSettings(*config_center_);
|
||||||
auto& main = ui_->main;
|
auto& main = ui_->main;
|
||||||
|
const bool has_endpoint = main->get_self_hosted_enabled() ||
|
||||||
|
!std::string(main->get_server_host()).empty() ||
|
||||||
|
!std::string(main->get_server_port()).empty();
|
||||||
|
if (has_endpoint && !ValidateSelfHostedSettingsFromUi()) {
|
||||||
|
main->set_self_host_settings_open(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((has_endpoint && config_center_->SetServerEndpoint(
|
||||||
|
std::string(main->get_server_host()), *ParsePort(main->get_server_port())) != 0) ||
|
||||||
|
config_center_->SetSelfHosted(main->get_self_hosted_enabled()) != 0) {
|
||||||
|
main->set_self_host_settings_error(UiText(
|
||||||
|
localization::self_hosted_save_failed[localization_language_index_]));
|
||||||
|
main->set_self_host_settings_open(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
language_button_value_ =
|
language_button_value_ =
|
||||||
localization::detail::ClampLanguageIndex(main->get_language_index());
|
localization::detail::ClampLanguageIndex(main->get_language_index());
|
||||||
video_encode_format_button_value_ = std::clamp(main->get_codec_index(), 0, 1);
|
video_encode_format_button_value_ = std::clamp(main->get_codec_index(), 0, 1);
|
||||||
@@ -3564,17 +3587,9 @@ void GuiApplication::SaveSettingsFromUi() {
|
|||||||
sizeof(file_transfer_save_path_buf_) - 1);
|
sizeof(file_transfer_save_path_buf_) - 1);
|
||||||
config_center_->SetFileTransferSavePath(path);
|
config_center_->SetFileTransferSavePath(path);
|
||||||
|
|
||||||
const std::string host(main->get_server_host());
|
|
||||||
if (!host.empty()) {
|
|
||||||
config_center_->SetServerHost(host);
|
|
||||||
}
|
|
||||||
if (const auto port = ParsePort(main->get_server_port())) {
|
|
||||||
config_center_->SetServerPort(*port);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_center_->SetSelfHosted(enable_self_hosted_);
|
|
||||||
ApplySettingsFromConfig(previous_server !=
|
ApplySettingsFromConfig(previous_server !=
|
||||||
GetSignalServerSettings(*config_center_));
|
GetSignalServerSettings(*config_center_));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::ApplySettingsFromConfig(bool reconnect) {
|
void GuiApplication::ApplySettingsFromConfig(bool reconnect) {
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
void UpdateLocalization();
|
void UpdateLocalization();
|
||||||
void ResetSettingsUi();
|
void ResetSettingsUi();
|
||||||
void SaveSettingsFromUi();
|
bool ValidateSelfHostedSettingsFromUi();
|
||||||
|
bool SaveSettingsFromUi();
|
||||||
void ApplySettingsFromConfig(bool reconnect);
|
void ApplySettingsFromConfig(bool reconnect);
|
||||||
#if _WIN32 && CROSSDESK_PORTABLE
|
#if _WIN32 && CROSSDESK_PORTABLE
|
||||||
void CheckPortableWindowsService();
|
void CheckPortableWindowsService();
|
||||||
|
|||||||
@@ -240,6 +240,9 @@ struct TranslationRow {
|
|||||||
"Server Address:", u8"Адрес сервера:") \
|
"Server Address:", u8"Адрес сервера:") \
|
||||||
X(self_hosted_server_port, u8"信令服务端口:", \
|
X(self_hosted_server_port, u8"信令服务端口:", \
|
||||||
"Signal Service Port:", u8"Порт сигнального сервиса:") \
|
"Signal Service Port:", u8"Порт сигнального сервиса:") \
|
||||||
|
X(self_hosted_address_invalid, u8"请输入有效的主机名、IP 或 HTTPS/WSS 信令地址,可包含路径。", "Enter a valid host, IP, or HTTPS/WSS signaling URL. Paths are supported.", u8"Введите имя хоста, IP или HTTPS/WSS-адрес сигнального сервиса. Путь допустим.") \
|
||||||
|
X(self_hosted_port_invalid, u8"请输入 1–65535 范围内的信令端口。", "Enter a signaling port between 1 and 65535.", u8"Введите порт сигнального сервиса от 1 до 65535.") \
|
||||||
|
X(self_hosted_save_failed, u8"配置保存失败,请检查配置目录是否可写后重试。", "Could not save settings. Check that the configuration directory is writable and retry.", u8"Не удалось сохранить настройки. Проверьте доступ на запись в каталог конфигурации.") \
|
||||||
X(ok, u8"确认", "OK", u8"ОК") \
|
X(ok, u8"确认", "OK", u8"ОК") \
|
||||||
X(cancel, u8"取消", "Cancel", u8"Отмена") \
|
X(cancel, u8"取消", "Cancel", u8"Отмена") \
|
||||||
X(new_password, u8"请输入六位密码:", \
|
X(new_password, u8"请输入六位密码:", \
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
#include "signal_server_address.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -51,9 +53,12 @@ void AnnouncementInbox::Configure(std::string host, int port,
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
if (directory_.empty() || host.empty() || port <= 0 || device_id.empty())
|
if (directory_.empty() || host.empty() || port <= 0 || device_id.empty())
|
||||||
return;
|
return;
|
||||||
for (auto& ch : host)
|
auto address = minirtc::ParseSignalServerAddress(host);
|
||||||
|
if (!address) return;
|
||||||
|
for (auto& ch : address->host)
|
||||||
if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A';
|
if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A';
|
||||||
if (host.back() == '.') host.pop_back();
|
if (address->host.back() == '.') address->host.pop_back();
|
||||||
|
host = address->Address();
|
||||||
const auto scope = json::array({host, port, device_id}).dump();
|
const auto scope = json::array({host, port, device_id}).dump();
|
||||||
if (scope_ == scope) return;
|
if (scope_ == scope) return;
|
||||||
scope_ = scope;
|
scope_ = scope;
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ export component MainWindow inherits Window {
|
|||||||
in-out property <string> file-save-path: "";
|
in-out property <string> file-save-path: "";
|
||||||
in-out property <string> server-host: "";
|
in-out property <string> server-host: "";
|
||||||
in-out property <string> server-port: "";
|
in-out property <string> server-port: "";
|
||||||
|
in-out property <string> self-host-settings-error: "";
|
||||||
in property <bool> settings-session-active: false;
|
in property <bool> settings-session-active: false;
|
||||||
// Keep the setting visible on every platform. Unsupported builds expose it
|
// Keep the setting visible on every platform. Unsupported builds expose it
|
||||||
// as disabled so the fixed settings layout never turns into a blank row.
|
// as disabled so the fixed settings layout never turns into a blank row.
|
||||||
@@ -393,9 +394,9 @@ export component MainWindow inherits Window {
|
|||||||
callback recent-connect(string);
|
callback recent-connect(string);
|
||||||
callback recent-edit-alias(string, string);
|
callback recent-edit-alias(string, string);
|
||||||
callback recent-delete(string);
|
callback recent-delete(string);
|
||||||
callback save-settings;
|
callback save-settings() -> bool;
|
||||||
callback cancel-settings;
|
callback cancel-settings;
|
||||||
callback save-self-hosted-settings;
|
callback save-self-hosted-settings() -> bool;
|
||||||
callback cancel-self-hosted-settings;
|
callback cancel-self-hosted-settings;
|
||||||
callback browse-save-path;
|
callback browse-save-path;
|
||||||
callback open-download;
|
callback open-download;
|
||||||
@@ -418,6 +419,9 @@ export component MainWindow inherits Window {
|
|||||||
in-out property <bool> settings-open: false;
|
in-out property <bool> settings-open: false;
|
||||||
private property <length> settings-scroll-y: 0px;
|
private property <length> settings-scroll-y: 0px;
|
||||||
in-out property <bool> self-host-settings-open: false;
|
in-out property <bool> self-host-settings-open: false;
|
||||||
|
changed self-host-settings-open => {
|
||||||
|
if !root.self-host-settings-open { root.self-host-settings-error = ""; }
|
||||||
|
}
|
||||||
in-out property <bool> about-open: false;
|
in-out property <bool> about-open: false;
|
||||||
in-out property <bool> update-open: false;
|
in-out property <bool> update-open: false;
|
||||||
in-out property <bool> reset-password-open: false;
|
in-out property <bool> reset-password-open: false;
|
||||||
@@ -1809,7 +1813,7 @@ export component MainWindow inherits Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle { x: 7px; y: 286px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
Rectangle { x: 7px; y: 286px; width: parent.width - 14px; height: 1px; background: ImGuiLineStyle.separator; }
|
||||||
CompactButton { x: root.compact-language ? 63px : 89px; y: 297px; primary: true; text: UiStrings.ok; clicked => { root.save-settings(); root.settings-open = false; root.self-host-settings-open = false; } }
|
CompactButton { x: root.compact-language ? 63px : 89px; y: 297px; primary: true; text: UiStrings.ok; clicked => { if root.save-settings() { root.settings-open = false; root.self-host-settings-open = false; } } }
|
||||||
CompactButton { x: root.compact-language ? 104px : 130px; y: 297px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-settings(); root.settings-open = false; root.self-host-settings-open = false; } }
|
CompactButton { x: root.compact-language ? 104px : 130px; y: 297px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-settings(); root.settings-open = false; root.self-host-settings-open = false; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1822,7 +1826,7 @@ export component MainWindow inherits Window {
|
|||||||
x: root.compact-language ? 190px : 140px;
|
x: root.compact-language ? 190px : 140px;
|
||||||
y: 105px;
|
y: 105px;
|
||||||
width: root.compact-language ? 260px : 360px;
|
width: root.compact-language ? 260px : 360px;
|
||||||
height: 138px;
|
height: root.self-host-settings-error == "" ? 138px : 202px;
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -1846,7 +1850,7 @@ export component MainWindow inherits Window {
|
|||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: ImGuiLineStyle.border;
|
border-color: ImGuiLineStyle.border;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-host; font-size: ImGuiFontStyle.body; }
|
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-host; input-type: InputType.text; font-size: ImGuiFontStyle.body; }
|
||||||
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
||||||
}
|
}
|
||||||
Text { x: 8px; y: 61px; width: root.compact-language ? 88px : 165px; height: 24px; text: UiStrings.server-port; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
Text { x: 8px; y: 61px; width: root.compact-language ? 88px : 165px; height: 24px; text: UiStrings.server-port; font-size: ImGuiFontStyle.body; overflow: elide; vertical-alignment: center; }
|
||||||
@@ -1862,8 +1866,13 @@ export component MainWindow inherits Window {
|
|||||||
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-port; input-type: InputType.number; font-size: ImGuiFontStyle.body; }
|
LineEdit { x: 1px; y: 1.5px; width: parent.width - 2px; height: parent.height - 2px; text <=> root.server-port; input-type: InputType.number; font-size: ImGuiFontStyle.body; }
|
||||||
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
LineEditFocusUnderlineMask { x: 5px; y: parent.height - 3px; width: parent.width - 10px; }
|
||||||
}
|
}
|
||||||
CompactButton { x: root.compact-language ? 93px : 135px; y: 100px; primary: true; text: UiStrings.ok; clicked => { root.save-self-hosted-settings(); root.self-host-settings-open = false; } }
|
if root.self-host-settings-error != "": Text {
|
||||||
CompactButton { x: root.compact-language ? 134px : 176px; y: 100px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } }
|
x: 8px; y: 89px; width: parent.width - 16px; height: 64px;
|
||||||
|
text: root.self-host-settings-error; color: #b3261e;
|
||||||
|
font-size: ImGuiFontStyle.body; wrap: word-wrap;
|
||||||
|
}
|
||||||
|
CompactButton { x: root.compact-language ? 93px : 135px; y: parent.height - 38px; primary: true; text: UiStrings.ok; clicked => { if root.save-self-hosted-settings() { root.self-host-settings-open = false; } } }
|
||||||
|
CompactButton { x: root.compact-language ? 134px : 176px; y: parent.height - 38px; width: root.compact-language ? 34px : 56px; text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "config_center.h"
|
#include "config_center.h"
|
||||||
|
#include "signal_server_address.h"
|
||||||
#include "signal_server_settings.h"
|
#include "signal_server_settings.h"
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
@@ -83,9 +84,7 @@ SettingResult ApplyConsoleSetting(ConfigCenter& config, const std::string& key,
|
|||||||
canonical = value;
|
canonical = value;
|
||||||
save = [&config, mode] { return config.SetTurnMode(static_cast<ConfigCenter::TURN_MODE>(mode)); };
|
save = [&config, mode] { return config.SetTurnMode(static_cast<ConfigCenter::TURN_MODE>(mode)); };
|
||||||
} else if (key == "server_host") {
|
} else if (key == "server_host") {
|
||||||
if (input.empty() || input.size() > 253 ||
|
if (!minirtc::ParseSignalServerAddress(input)) return result;
|
||||||
input.find_first_of("/\\@?#") != std::string::npos ||
|
|
||||||
std::any_of(input.begin(), input.end(), [](unsigned char c) { return c <= 32 || c == 127; })) return result;
|
|
||||||
save = [&] { return config.SetServerHost(input); };
|
save = [&] { return config.SetServerHost(input); };
|
||||||
} else if (key == "server_port") {
|
} else if (key == "server_port") {
|
||||||
int port = 0;
|
int port = 0;
|
||||||
|
|||||||
@@ -453,6 +453,7 @@ function setup_targets()
|
|||||||
add_deps("rd_log", "autostart")
|
add_deps("rd_log", "autostart")
|
||||||
add_files("apps/desktop/src/config_center/*.cpp")
|
add_files("apps/desktop/src/config_center/*.cpp")
|
||||||
add_includedirs("apps/desktop/src", "apps/desktop/src/config_center",
|
add_includedirs("apps/desktop/src", "apps/desktop/src/config_center",
|
||||||
|
"deps/submodules/minirtc/src/api",
|
||||||
{public = true})
|
{public = true})
|
||||||
|
|
||||||
target("assets")
|
target("assets")
|
||||||
|
|||||||
Vendored
+1
-1
Submodule deps/submodules/minirtc updated: 3f6f7f2725...d2f42cb02c
+1
-1
@@ -61,7 +61,7 @@ xmake r crossdesk --headless
|
|||||||
| `codec` | `h264` / `av1` | 保存后重新连接 |
|
| `codec` | `h264` / `av1` | 保存后重新连接 |
|
||||||
| `hardware` | `on` / `off` | 保存后重新连接;构建不支持时拒绝开启 |
|
| `hardware` | `on` / `off` | 保存后重新连接;构建不支持时拒绝开启 |
|
||||||
| `turn` | `off` / `auto` / `udp` / `tcp` | 保存后重新连接;`udp` / `tcp` 表示强制中继 |
|
| `turn` | `off` / `auto` / `udp` / `tcp` | 保存后重新连接;`udp` / `tcp` 表示强制中继 |
|
||||||
| `server_host` | 主机名或 IP,不含协议与路径 | 自托管未启用时保存备用,已启用时重连 |
|
| `server_host` | 主机名、IP 或 HTTPS/WSS 信令地址,支持路径和显式端口 | 自托管未启用时保存备用,已启用时重连 |
|
||||||
| `server_port` | `1`–`65535` | 同上 |
|
| `server_port` | `1`–`65535` | 同上 |
|
||||||
| `self_hosted` | `on` / `off` | 先配置地址、端口,再开启;保存后重连 |
|
| `self_hosted` | `on` / `off` | 先配置地址、端口,再开启;保存后重连 |
|
||||||
| `privacy` | `on` / `off` | 后续远程连接的自动隐私屏行为 |
|
| `privacy` | `on` / `off` | 后续远程连接的自动隐私屏行为 |
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ The menu shares the GUI's `config.ini`. Each valid change is saved immediately;
|
|||||||
| `codec` | `h264` / `av1` | Reconnect after saving |
|
| `codec` | `h264` / `av1` | Reconnect after saving |
|
||||||
| `hardware` | `on` / `off` | Reconnect; enabling requires a build with hardware codec support |
|
| `hardware` | `on` / `off` | Reconnect; enabling requires a build with hardware codec support |
|
||||||
| `turn` | `off` / `auto` / `udp` / `tcp` | Reconnect; UDP/TCP force relay use |
|
| `turn` | `off` / `auto` / `udp` / `tcp` | Reconnect; UDP/TCP force relay use |
|
||||||
| `server_host` | Hostname or IP without URL scheme/path | Reconnect if self-hosting is enabled; otherwise saved for later |
|
| `server_host` | Hostname, IP, or HTTPS/WSS signaling URL, with optional path and explicit port | Reconnect if self-hosting is enabled; otherwise saved for later |
|
||||||
| `server_port` | `1`–`65535` | Same as server host |
|
| `server_port` | `1`–`65535` | Same as server host |
|
||||||
| `self_hosted` | `on` / `off` | Configure host/port first, then enable; reconnect |
|
| `self_hosted` | `on` / `off` | Configure host/port first, then enable; reconnect |
|
||||||
| `privacy` | `on` / `off` | Automatic privacy screen on subsequent connections |
|
| `privacy` | `on` / `off` | Automatic privacy screen on subsequent connections |
|
||||||
|
|||||||
@@ -44,10 +44,12 @@ sudo docker compose ps
|
|||||||
|
|
||||||
1. 断开现有会话,点击主窗口右上角 **☰ → 设置**。
|
1. 断开现有会话,点击主窗口右上角 **☰ → 设置**。
|
||||||
2. 在设置列表中向下滚动,点击 **自托管配置**。
|
2. 在设置列表中向下滚动,点击 **自托管配置**。
|
||||||
3. 填写 **服务器地址**、**信令服务端口**,点击“确认”。地址只填主机名或 IP,不加 `https://`、路径或端口。
|
3. 填写 **服务器地址**、**信令服务端口**,点击“确认”。地址支持主机名或 IP(如 `my-server.example.com`),也支持带路径的信令地址(如 `my-server.example.com/signal-path`)或 `https://` / `wss://` URL。URL 内明确填写的端口优先;否则使用单独填写的信令服务端口。所有连接均使用 WSS,带路径的地址需要反向代理将该路径转发到信令 WebSocket 服务,普通网页地址不能直接用于信令连接。
|
||||||
4. 回到设置窗口,勾选 **自托管配置** 右侧复选框,再点击“确认”保存。
|
4. 回到设置窗口,勾选 **自托管配置** 右侧复选框,再点击“确认”保存。
|
||||||
5. 在控制端和被控端执行相同配置。等待两端都显示“已连接服务器”,再使用被控端当前显示的 ID 发起连接。
|
5. 在控制端和被控端执行相同配置。等待两端都显示“已连接服务器”,再使用被控端当前显示的 ID 发起连接。
|
||||||
|
|
||||||
|
地址与端口在最后确认设置时一起保存;格式无效或保存失败时会保留输入并显示错误。
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="images/desktop-self-hosted-zh.png" width="720" alt="当前 Slint 客户端自托管设置:服务器地址与信令端口" />
|
<img src="images/desktop-self-hosted-zh.png" width="720" alt="当前 Slint 客户端自托管设置:服务器地址与信令端口" />
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ For a self-signed deployment, complete the [certificate trust steps](#3-trust-th
|
|||||||
|
|
||||||
1. Disconnect existing sessions and open **☰ → Settings**.
|
1. Disconnect existing sessions and open **☰ → Settings**.
|
||||||
2. Scroll down and click **Self-Hosted Config**.
|
2. Scroll down and click **Self-Hosted Config**.
|
||||||
3. Enter **Server Address** and **Signal Service Port**, then confirm. Enter only the hostname or IP in the address field, without a URL scheme, path, or port.
|
3. Enter **Server Address** and **Signal Service Port**, then confirm. The address accepts a hostname or IP (such as `my-server.example.com`), a signaling path (such as `my-server.example.com/signal-path`), or an `https://` / `wss://` URL. An explicit URL port takes precedence; otherwise the separate signaling port is used. Connections always use WSS. Paths must be routed to the signaling WebSocket service by your reverse proxy; an ordinary web page is not a signaling endpoint.
|
||||||
4. Enable the checkbox beside **Self-Hosted Config**, then click **OK** in the parent settings window.
|
4. Enable the checkbox beside **Self-Hosted Config**, then click **OK** in the parent settings window.
|
||||||
5. Configure both the controller and host this way. Once both report a server connection, connect using the host's currently displayed ID.
|
5. Configure both the controller and host this way. Once both report a server connection, connect using the host's currently displayed ID.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user