mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-23 21:21:05 +03:00
terminal works basically. (#12189)
* terminal works basically. todo: - persistent - sessions restore - web - mobile * missed terminal persistent option change * android sdk 34 -> 35 * +#![cfg_attr(lt_1_77, feature(c_str_literals))] * fixing ci * fix ci * fix ci for android * try "Fix Android SDK Platform 35" * fix android 34 * revert flutter_plugin_android_lifecycle to 2.0.17 which used in rustdesk 1.4.0 * refactor, but break something of desktop terminal (new tab showing loading) * fix connecting...
This commit is contained in:
@@ -169,6 +169,7 @@ pub enum AuthConnType {
|
||||
FileTransfer,
|
||||
PortForward,
|
||||
ViewCamera,
|
||||
Terminal,
|
||||
}
|
||||
|
||||
pub struct Connection {
|
||||
@@ -182,6 +183,7 @@ pub struct Connection {
|
||||
file_timer: crate::RustDeskInterval,
|
||||
file_transfer: Option<(String, bool)>,
|
||||
view_camera: bool,
|
||||
terminal: bool,
|
||||
port_forward_socket: Option<Framed<TcpStream, BytesCodec>>,
|
||||
port_forward_address: String,
|
||||
tx_to_cm: mpsc::UnboundedSender<ipc::Data>,
|
||||
@@ -250,6 +252,9 @@ pub struct Connection {
|
||||
// For post requests that need to be sent sequentially.
|
||||
// eg. post_conn_audit
|
||||
tx_post_seq: mpsc::UnboundedSender<(String, Value)>,
|
||||
terminal_service_id: String,
|
||||
terminal_persistent: bool,
|
||||
terminal_generic_service: Option<Box<GenericService>>,
|
||||
}
|
||||
|
||||
impl ConnInner {
|
||||
@@ -347,6 +352,7 @@ impl Connection {
|
||||
file_timer: crate::rustdesk_interval(time::interval(SEC30)),
|
||||
file_transfer: None,
|
||||
view_camera: false,
|
||||
terminal: false,
|
||||
port_forward_socket: None,
|
||||
port_forward_address: "".to_owned(),
|
||||
tx_to_cm,
|
||||
@@ -410,6 +416,9 @@ impl Connection {
|
||||
tx_from_authed,
|
||||
printer_data: Vec::new(),
|
||||
tx_post_seq,
|
||||
terminal_service_id: "".to_owned(),
|
||||
terminal_persistent: false,
|
||||
terminal_generic_service: None,
|
||||
};
|
||||
let addr = hbb_common::try_into_v4(addr);
|
||||
if !conn.on_open(addr).await {
|
||||
@@ -450,7 +459,7 @@ impl Connection {
|
||||
let mut last_recv_time = Instant::now();
|
||||
|
||||
conn.stream.set_send_timeout(
|
||||
if conn.file_transfer.is_some() || conn.port_forward_socket.is_some() {
|
||||
if conn.file_transfer.is_some() || conn.port_forward_socket.is_some() || conn.terminal {
|
||||
SEND_TIMEOUT_OTHER
|
||||
} else {
|
||||
SEND_TIMEOUT_VIDEO
|
||||
@@ -1253,6 +1262,8 @@ impl Connection {
|
||||
(2, AuthConnType::PortForward)
|
||||
} else if self.view_camera {
|
||||
(3, AuthConnType::ViewCamera)
|
||||
} else if self.terminal {
|
||||
(4, AuthConnType::Terminal)
|
||||
} else {
|
||||
(0, AuthConnType::Remote)
|
||||
};
|
||||
@@ -1361,8 +1372,7 @@ impl Connection {
|
||||
return;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
if !self.file_transfer.is_some() && !self.port_forward_socket.is_some() && !self.view_camera
|
||||
{
|
||||
if self.is_remote() {
|
||||
let mut msg = "".to_string();
|
||||
if crate::platform::linux::is_login_screen_wayland() {
|
||||
msg = crate::client::LOGIN_SCREEN_WAYLAND.to_owned()
|
||||
@@ -1393,7 +1403,8 @@ impl Connection {
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if self.file_transfer.is_some() {
|
||||
if crate::platform::is_prelogin() { // }|| self.tx_to_cm.send(ipc::Data::Test).is_err() {
|
||||
if crate::platform::is_prelogin() {
|
||||
// }|| self.tx_to_cm.send(ipc::Data::Test).is_err() {
|
||||
username = "".to_owned();
|
||||
}
|
||||
}
|
||||
@@ -1408,6 +1419,8 @@ impl Connection {
|
||||
pi.sas_enabled = sas_enabled;
|
||||
pi.features = Some(Features {
|
||||
privacy_mode: privacy_mode::is_privacy_mode_supported(),
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
terminal: true, // Terminal feature is supported on desktop only
|
||||
..Default::default()
|
||||
})
|
||||
.into();
|
||||
@@ -1417,7 +1430,7 @@ impl Connection {
|
||||
let mut wait_session_id_confirm = false;
|
||||
#[cfg(windows)]
|
||||
self.handle_windows_specific_session(&mut pi, &mut wait_session_id_confirm);
|
||||
if self.file_transfer.is_some() {
|
||||
if self.file_transfer.is_some() || self.terminal {
|
||||
res.set_peer_info(pi);
|
||||
} else if self.view_camera {
|
||||
let supported_encoding = scrap::codec::Encoder::supported_encoding();
|
||||
@@ -1509,6 +1522,10 @@ impl Connection {
|
||||
} else {
|
||||
self.delayed_read_dir = Some((dir.to_owned(), show_hidden));
|
||||
}
|
||||
} else if self.terminal {
|
||||
self.keyboard = false;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
self.init_terminal_service().await;
|
||||
} else if self.view_camera {
|
||||
if !wait_session_id_confirm {
|
||||
self.try_sub_camera_displays();
|
||||
@@ -1531,9 +1548,16 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_remote(&self) -> bool {
|
||||
self.file_transfer.is_none()
|
||||
&& self.port_forward_socket.is_none()
|
||||
&& !self.view_camera
|
||||
&& !self.terminal
|
||||
}
|
||||
|
||||
fn try_sub_monitor_services(&mut self) {
|
||||
let is_remote =
|
||||
self.file_transfer.is_none() && self.port_forward_socket.is_none() && !self.view_camera;
|
||||
let is_remote = self.is_remote();
|
||||
if is_remote && !self.services_subed {
|
||||
self.services_subed = true;
|
||||
if let Some(s) = self.server.upgrade() {
|
||||
@@ -1651,6 +1675,7 @@ impl Connection {
|
||||
id: self.inner.id(),
|
||||
is_file_transfer: self.file_transfer.is_some(),
|
||||
is_view_camera: self.view_camera,
|
||||
is_terminal: self.terminal,
|
||||
port_forward: self.port_forward_address.clone(),
|
||||
peer_id,
|
||||
name,
|
||||
@@ -1902,6 +1927,19 @@ impl Connection {
|
||||
}
|
||||
self.view_camera = true;
|
||||
}
|
||||
Some(login_request::Union::Terminal(terminal)) => {
|
||||
if !Connection::permission(keys::OPTION_ENABLE_TERMINAL) {
|
||||
self.send_login_error("No permission of terminal").await;
|
||||
sleep(1.).await;
|
||||
return false;
|
||||
}
|
||||
self.terminal = true;
|
||||
if let Some(o) = self.options_in_login.as_ref() {
|
||||
self.terminal_persistent =
|
||||
o.terminal_persistent.enum_value() == Ok(BoolOption::Yes);
|
||||
}
|
||||
self.terminal_service_id = terminal.service_id;
|
||||
}
|
||||
Some(login_request::Union::PortForward(mut pf)) => {
|
||||
if !Connection::permission("enable-tunnel") {
|
||||
self.send_login_error("No permission of IP tunneling").await;
|
||||
@@ -2791,7 +2829,7 @@ impl Connection {
|
||||
}
|
||||
} else if self.view_camera {
|
||||
self.try_sub_camera_displays();
|
||||
} else {
|
||||
} else if !self.terminal {
|
||||
self.try_sub_monitor_services();
|
||||
}
|
||||
}
|
||||
@@ -2843,6 +2881,12 @@ impl Connection {
|
||||
self.refresh_video_display(Some(request.display as usize));
|
||||
}
|
||||
}
|
||||
Some(message::Union::TerminalAction(action)) => {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
allow_err!(self.handle_terminal_action(action).await);
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
log::warn!("Terminal action received but not supported on this platform");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -3371,6 +3415,12 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if let Ok(q) = o.terminal_persistent.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.update_terminal_persistence(q == BoolOption::Yes).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn turn_on_privacy(&mut self, impl_key: String) {
|
||||
@@ -3562,12 +3612,7 @@ impl Connection {
|
||||
|
||||
#[cfg(windows)]
|
||||
fn portable_check(&mut self) {
|
||||
if self.portable.is_installed
|
||||
|| self.file_transfer.is_some()
|
||||
|| self.view_camera
|
||||
|| self.port_forward_socket.is_some()
|
||||
|| !self.keyboard
|
||||
{
|
||||
if self.portable.is_installed || !self.is_remote() || !self.keyboard {
|
||||
return;
|
||||
}
|
||||
let running = portable_client::running();
|
||||
@@ -3779,6 +3824,55 @@ impl Connection {
|
||||
msg_out.set_message_box(res);
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
async fn update_terminal_persistence(&mut self, persistent: bool) {
|
||||
self.terminal_persistent = persistent;
|
||||
terminal_service::set_persistent(&self.terminal_service_id, persistent).ok();
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
async fn init_terminal_service(&mut self) {
|
||||
if self.terminal_service_id.is_empty() {
|
||||
self.terminal_service_id = terminal_service::generate_service_id();
|
||||
}
|
||||
let s = Box::new(terminal_service::new(
|
||||
self.terminal_service_id.clone(),
|
||||
self.terminal_persistent,
|
||||
));
|
||||
s.on_subscribe(self.inner.clone());
|
||||
self.terminal_generic_service = Some(s);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
async fn handle_terminal_action(&mut self, action: TerminalAction) -> ResultType<()> {
|
||||
let mut proxy = terminal_service::TerminalServiceProxy::new(
|
||||
self.terminal_service_id.clone(),
|
||||
Some(self.terminal_persistent),
|
||||
);
|
||||
|
||||
match proxy.handle_action(&action) {
|
||||
Ok(Some(response)) => {
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_terminal_response(response);
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
Ok(None) => {
|
||||
// No response needed
|
||||
}
|
||||
Err(err) => {
|
||||
let mut response = TerminalResponse::new();
|
||||
let mut error = TerminalError::new();
|
||||
error.message = format!("Failed to handle action: {}", err);
|
||||
response.set_error(error);
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_terminal_response(response);
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
||||
@@ -4151,6 +4245,10 @@ impl Drop for Connection {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
self.release_pressed_modifiers();
|
||||
|
||||
if let Some(s) = self.terminal_generic_service.as_ref() {
|
||||
s.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user