allow use websocket (#11677)

1. Enable the RustDesk client to use WebSocket for either controlling or being controlled.
2. Fix TCP sending `register_pk` frequently

Note:
1. Because hbb_common directly uses `use_ws` to read config directly, rustdesk also directly reads config

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2025-05-09 12:18:49 +08:00
committed by GitHub
parent 86bbdf7a5d
commit 9475743b4e
61 changed files with 413 additions and 64 deletions

View File

@@ -1,4 +1,5 @@
use crate::{
common::CheckTestNatType,
privacy_mode::PrivacyModeState,
ui_interface::{get_local_option, set_local_option},
};
@@ -22,7 +23,7 @@ pub use clipboard::ClipboardFile;
use hbb_common::{
allow_err, bail, bytes,
bytes_codec::BytesCodec,
config::{self, Config, Config2},
config::{self, keys::OPTION_ALLOW_WEBSOCKET, Config, Config2},
futures::StreamExt as _,
futures_util::sink::SinkExt,
log, password_security as password, timeout,
@@ -282,6 +283,7 @@ pub enum Data {
ControllingSessionCount(usize),
#[cfg(target_os = "windows")]
PortForwardSessionCount(Option<usize>),
SocksWs(Option<Box<(Option<config::Socks5Server>, String)>>),
}
#[tokio::main(flavor = "current_thread")]
@@ -348,29 +350,40 @@ pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
}
}
pub struct CheckIfRestart(String, Vec<String>, String, String);
pub struct CheckIfRestart {
stop_service: String,
rendezvous_servers: Vec<String>,
audio_input: String,
voice_call_input: String,
ws: String,
api_server: String,
}
impl CheckIfRestart {
pub fn new() -> CheckIfRestart {
CheckIfRestart(
Config::get_option("stop-service"),
Config::get_rendezvous_servers(),
Config::get_option("audio-input"),
Config::get_option("voice-call-input"),
)
CheckIfRestart {
stop_service: Config::get_option("stop-service"),
rendezvous_servers: Config::get_rendezvous_servers(),
audio_input: Config::get_option("audio-input"),
voice_call_input: Config::get_option("voice-call-input"),
ws: Config::get_option(OPTION_ALLOW_WEBSOCKET),
api_server: Config::get_option("api-server"),
}
}
}
impl Drop for CheckIfRestart {
fn drop(&mut self) {
if self.0 != Config::get_option("stop-service")
|| self.1 != Config::get_rendezvous_servers()
if self.stop_service != Config::get_option("stop-service")
|| self.rendezvous_servers != Config::get_rendezvous_servers()
|| self.ws != Config::get_option(OPTION_ALLOW_WEBSOCKET)
|| self.api_server != Config::get_option("api-server")
{
RendezvousMediator::restart();
}
if self.2 != Config::get_option("audio-input") {
if self.audio_input != Config::get_option("audio-input") {
crate::audio_service::restart();
}
if self.3 != Config::get_option("voice-call-input") {
if self.voice_call_input != Config::get_option("voice-call-input") {
crate::audio_service::set_voice_call_input_device(
Some(Config::get_option("voice-call-input")),
true,
@@ -455,16 +468,29 @@ async fn handle(data: Data, stream: &mut Connection) {
allow_err!(stream.send(&Data::Socks(Config::get_socks())).await);
}
Some(data) => {
let _nat = CheckTestNatType::new();
if data.proxy.is_empty() {
Config::set_socks(None);
} else {
Config::set_socks(Some(data));
}
crate::common::test_nat_type();
RendezvousMediator::restart();
log::info!("socks updated");
}
},
Data::SocksWs(s) => match s {
None => {
allow_err!(
stream
.send(&Data::SocksWs(Some(Box::new((
Config::get_socks(),
Config::get_option(OPTION_ALLOW_WEBSOCKET)
)))))
.await
);
}
_ => {}
},
#[cfg(feature = "flutter")]
Data::VideoConnCount(None) => {
let n = crate::server::AUTHED_CONNS
@@ -501,7 +527,8 @@ async fn handle(data: Data, stream: &mut Connection) {
None
};
} else if name == "hide_cm" {
value = if crate::hbbs_http::sync::is_pro() || crate::common::is_custom_client() {
value = if crate::hbbs_http::sync::is_pro() || crate::common::is_custom_client()
{
Some(hbb_common::password_security::hide_cm().to_string())
} else {
None
@@ -544,6 +571,7 @@ async fn handle(data: Data, stream: &mut Connection) {
}
Some(value) => {
let _chk = CheckIfRestart::new();
let _nat = CheckTestNatType::new();
if let Some(v) = value.get("privacy-mode-impl-key") {
crate::privacy_mode::switch(v);
}
@@ -1113,6 +1141,7 @@ pub fn set_option(key: &str, value: &str) {
#[tokio::main(flavor = "current_thread")]
pub async fn set_options(value: HashMap<String, String>) -> ResultType<()> {
let _nat = CheckTestNatType::new();
if let Ok(mut c) = connect(1000, "").await {
c.send(&Data::Options(Some(value.clone()))).await?;
// do not put below before connect, because we need to check should_exit
@@ -1170,6 +1199,7 @@ pub async fn get_socks() -> Option<config::Socks5Server> {
#[tokio::main(flavor = "current_thread")]
pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
let _nat = CheckTestNatType::new();
Config::set_socks(if value.proxy.is_empty() {
None
} else {
@@ -1182,6 +1212,29 @@ pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
Ok(())
}
async fn get_socks_ws_(ms_timeout: u64) -> ResultType<(Option<config::Socks5Server>, String)> {
let mut c = connect(ms_timeout, "").await?;
c.send(&Data::SocksWs(None)).await?;
if let Some(Data::SocksWs(Some(value))) = c.next_timeout(ms_timeout).await? {
Config::set_socks(value.0.clone());
Config::set_option(OPTION_ALLOW_WEBSOCKET.to_string(), value.1.clone());
Ok(*value)
} else {
Ok((
Config::get_socks(),
Config::get_option(OPTION_ALLOW_WEBSOCKET),
))
}
}
#[tokio::main(flavor = "current_thread")]
pub async fn get_socks_ws() -> (Option<config::Socks5Server>, String) {
get_socks_ws_(1_000).await.unwrap_or((
Config::get_socks(),
Config::get_option(OPTION_ALLOW_WEBSOCKET),
))
}
pub fn get_proxy_status() -> bool {
Config::get_socks().is_some()
}