[fix] support self-hosted server URLs with paths

This commit is contained in:
dijunkun
2026-10-09 15:34:12 +08:00
parent d3ecbe2cc9
commit a06ed5806a
14 changed files with 101 additions and 51 deletions
@@ -63,6 +63,7 @@
#include "rd_log.h"
#include "server_window_state.h"
#include "signal_server_settings.h"
#include "signal_server_address.h"
#include "ui/announcement_text.h"
#include "ui/ui_localization.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_server_host(signal_server_ip_self_);
ui_->main->set_server_port(signal_server_port_self_);
ui_->main->set_self_host_settings_error("");
}
void GuiApplication::BindMainCallbacks() {
@@ -1419,29 +1421,14 @@ void GuiApplication::BindMainCallbacks() {
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_save_self_hosted_settings([this] {
const std::string host(ui_->main->get_server_host());
const auto signal_port = ParsePort(ui_->main->get_server_port());
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);
}
// Stage the endpoint until the surrounding settings dialog is confirmed.
return ValidateSelfHostedSettingsFromUi();
});
main->on_cancel_self_hosted_settings([this] {
ui_->main->set_self_host_settings_error("");
const std::string host = config_center_->GetSignalServerHost();
ui_->main->set_server_host(UiText(host));
const int signal_port = config_center_->GetSignalServerPort();
@@ -3496,9 +3483,45 @@ void GuiApplication::SyncServerWindow() {
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_);
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_ =
localization::detail::ClampLanguageIndex(main->get_language_index());
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);
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 !=
GetSignalServerSettings(*config_center_));
return true;
}
void GuiApplication::ApplySettingsFromConfig(bool reconnect) {
@@ -76,7 +76,8 @@ private:
#endif
void UpdateLocalization();
void ResetSettingsUi();
void SaveSettingsFromUi();
bool ValidateSelfHostedSettingsFromUi();
bool SaveSettingsFromUi();
void ApplySettingsFromConfig(bool reconnect);
#if _WIN32 && CROSSDESK_PORTABLE
void CheckPortableWindowsService();
@@ -240,6 +240,9 @@ struct TranslationRow {
"Server Address:", u8"Адрес сервера:") \
X(self_hosted_server_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(cancel, u8"取消", "Cancel", u8"Отмена") \
X(new_password, u8"请输入六位密码:", \
@@ -8,6 +8,8 @@
#include <set>
#include <system_error>
#include "signal_server_address.h"
#ifdef _WIN32
#include <windows.h>
#endif
@@ -51,9 +53,12 @@ void AnnouncementInbox::Configure(std::string host, int port,
std::lock_guard<std::mutex> lock(mutex_);
if (directory_.empty() || host.empty() || port <= 0 || device_id.empty())
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 (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();
if (scope_ == scope) return;
scope_ = scope;
+16 -7
View File
@@ -379,6 +379,7 @@ export component MainWindow inherits Window {
in-out property <string> file-save-path: "";
in-out property <string> server-host: "";
in-out property <string> server-port: "";
in-out property <string> self-host-settings-error: "";
in property <bool> settings-session-active: false;
// Keep the setting visible on every platform. Unsupported builds expose it
// 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-edit-alias(string, string);
callback recent-delete(string);
callback save-settings;
callback save-settings() -> bool;
callback cancel-settings;
callback save-self-hosted-settings;
callback save-self-hosted-settings() -> bool;
callback cancel-self-hosted-settings;
callback browse-save-path;
callback open-download;
@@ -418,6 +419,9 @@ export component MainWindow inherits Window {
in-out property <bool> settings-open: false;
private property <length> settings-scroll-y: 0px;
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> update-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; }
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; } }
}
}
@@ -1822,7 +1826,7 @@ export component MainWindow inherits Window {
x: root.compact-language ? 190px : 140px;
y: 105px;
width: root.compact-language ? 260px : 360px;
height: 138px;
height: root.self-host-settings-error == "" ? 138px : 202px;
border-radius: 7px;
Rectangle {
@@ -1846,7 +1850,7 @@ export component MainWindow inherits Window {
border-width: 1px;
border-color: ImGuiLineStyle.border;
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; }
}
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; }
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; } }
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; } }
if root.self-host-settings-error != "": Text {
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; } }
}
}