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:
RustDesk
2025-07-01 13:12:55 +08:00
committed by GitHub
parent ee5cdc3155
commit 5faf0ad3cf
130 changed files with 4064 additions and 4247 deletions

View File

@@ -20,7 +20,7 @@ use uuid::Uuid;
use hbb_common::fs;
use hbb_common::{
allow_err,
config::{Config, LocalConfig, PeerConfig},
config::{keys, Config, LocalConfig, PeerConfig},
get_version_number, log,
message_proto::*,
rendezvous_proto::ConnType,
@@ -191,10 +191,18 @@ impl<T: InvokeUiSession> Session<T> {
.eq(&ConnType::FILE_TRANSFER)
}
pub fn is_default(&self) -> bool {
self.lc.read().unwrap().conn_type.eq(&ConnType::DEFAULT_CONN)
}
pub fn is_view_camera(&self) -> bool {
self.lc.read().unwrap().conn_type.eq(&ConnType::VIEW_CAMERA)
}
pub fn is_terminal(&self) -> bool {
self.lc.read().unwrap().conn_type.eq(&ConnType::TERMINAL)
}
pub fn is_port_forward(&self) -> bool {
let conn_type = self.lc.read().unwrap().conn_type;
conn_type == ConnType::PORT_FORWARD || conn_type == ConnType::RDP
@@ -341,7 +349,7 @@ impl<T: InvokeUiSession> Session<T> {
pub fn toggle_option(&self, name: String) {
let msg = self.lc.write().unwrap().toggle_option(name.clone());
#[cfg(all(target_os = "windows", not(feature = "flutter")))]
if name == hbb_common::config::keys::OPTION_ENABLE_FILE_COPY_PASTE {
if name == keys::OPTION_ENABLE_FILE_COPY_PASTE {
self.send(Data::ToggleClipboardFile);
}
if let Some(msg) = msg {
@@ -746,6 +754,57 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::Message(msg_out));
}
// Terminal methods
pub fn open_terminal(&self, terminal_id: i32, rows: u32, cols: u32) {
let mut action = TerminalAction::new();
action.set_open(OpenTerminal {
terminal_id,
rows,
cols,
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_terminal_action(action);
self.send(Data::Message(msg_out));
}
pub fn send_terminal_input(&self, terminal_id: i32, data: String) {
let mut action = TerminalAction::new();
action.set_data(TerminalData {
terminal_id,
data: bytes::Bytes::from(data.into_bytes()),
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_terminal_action(action);
self.send(Data::Message(msg_out));
}
pub fn resize_terminal(&self, terminal_id: i32, rows: u32, cols: u32) {
let mut action = TerminalAction::new();
action.set_resize(ResizeTerminal {
terminal_id,
rows,
cols,
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_terminal_action(action);
self.send(Data::Message(msg_out));
}
pub fn close_terminal(&self, terminal_id: i32) {
let mut action = TerminalAction::new();
action.set_close(CloseTerminal {
terminal_id,
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_terminal_action(action);
self.send(Data::Message(msg_out));
}
pub fn capture_displays(&self, add: Vec<i32>, sub: Vec<i32>, set: Vec<i32>) {
let mut misc = Misc::new();
misc.set_capture_displays(CaptureDisplays {
@@ -1488,7 +1547,7 @@ impl<T: InvokeUiSession> Session<T> {
self.read_remote_dir(remote_dir, show_hidden);
}
}
} else {
} else if !self.is_terminal() {
self.msgbox(
"success",
"Successful",
@@ -1603,6 +1662,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn update_empty_dirs(&self, _res: ReadEmptyDirsResponse) {}
fn printer_request(&self, id: i32, path: String);
fn handle_screenshot_resp(&self, sid: String, msg: String);
fn handle_terminal_response(&self, response: TerminalResponse);
}
impl<T: InvokeUiSession> Deref for Session<T> {
@@ -1663,7 +1723,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
self.on_error("No active console user logged on, please connect and logon first.");
return;
}
} else if !self.is_port_forward() {
} else if !self.is_port_forward() && !self.is_terminal() {
if pi.displays.is_empty() {
self.lc.write().unwrap().handle_peer_info(&pi);
self.update_privacy_mode();
@@ -1695,7 +1755,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
self.set_peer_info(&pi);
if self.is_file_transfer() {
self.close_success();
} else if !self.is_port_forward() {
} else if !self.is_port_forward() && !self.is_terminal() {
self.msgbox(
"success",
"Successful",