Merge remote-tracking branch 'rd/master' into feat/x11/clipboard-file/init

Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
ClSlaid
2023-10-07 17:32:25 +08:00
88 changed files with 1434 additions and 871 deletions

View File

@@ -1,4 +1,7 @@
use crate::input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL};
use async_trait::async_trait;
use bytes::Bytes;
use rdev::{Event, EventType::*, KeyCode};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use std::{collections::HashMap, sync::atomic::AtomicBool};
use std::{
@@ -10,10 +13,6 @@ use std::{
},
time::SystemTime,
};
use async_trait::async_trait;
use bytes::Bytes;
use rdev::{Event, EventType::*, KeyCode};
use uuid::Uuid;
#[cfg(not(feature = "flutter"))]
@@ -62,6 +61,7 @@ pub struct Session<T: InvokeUiSession> {
pub server_file_transfer_enabled: Arc<RwLock<bool>>,
pub server_clipboard_enabled: Arc<RwLock<bool>>,
pub last_change_display: Arc<Mutex<ChangeDisplayRecord>>,
pub connection_round_state: Arc<Mutex<ConnectionRoundState>>,
}
#[derive(Clone)]
@@ -79,6 +79,56 @@ pub struct ChangeDisplayRecord {
height: i32,
}
enum ConnectionState {
Connecting,
Connected,
Disconnected,
}
/// ConnectionRoundState is used to control the reconnecting logic.
pub struct ConnectionRoundState {
round: u32,
state: ConnectionState,
}
impl ConnectionRoundState {
pub fn new_round(&mut self) -> u32 {
self.round += 1;
self.state = ConnectionState::Connecting;
self.round
}
pub fn set_connected(&mut self) {
self.state = ConnectionState::Connected;
}
pub fn is_round_gt(&self, round: u32) -> bool {
if round == u32::MAX && self.round == 0 {
true
} else {
round < self.round
}
}
pub fn set_disconnected(&mut self, round: u32) -> bool {
if self.is_round_gt(round) {
false
} else {
self.state = ConnectionState::Disconnected;
true
}
}
}
impl Default for ConnectionRoundState {
fn default() -> Self {
Self {
round: 0,
state: ConnectionState::Connecting,
}
}
}
impl Default for ChangeDisplayRecord {
fn default() -> Self {
Self {
@@ -181,7 +231,7 @@ impl<T: InvokeUiSession> Session<T> {
}
}
pub fn save_keyboard_mode(&mut self, value: String) {
pub fn save_keyboard_mode(&self, value: String) {
self.lc.write().unwrap().save_keyboard_mode(value);
}
@@ -189,19 +239,19 @@ impl<T: InvokeUiSession> Session<T> {
self.lc.read().unwrap().reverse_mouse_wheel.clone()
}
pub fn save_reverse_mouse_wheel(&mut self, value: String) {
pub fn save_reverse_mouse_wheel(&self, value: String) {
self.lc.write().unwrap().save_reverse_mouse_wheel(value);
}
pub fn save_view_style(&mut self, value: String) {
pub fn save_view_style(&self, value: String) {
self.lc.write().unwrap().save_view_style(value);
}
pub fn save_scroll_style(&mut self, value: String) {
pub fn save_scroll_style(&self, value: String) {
self.lc.write().unwrap().save_scroll_style(value);
}
pub fn save_flutter_option(&mut self, k: String, v: String) {
pub fn save_flutter_option(&self, k: String, v: String) {
self.lc.write().unwrap().save_ui_flutter(k, v);
}
@@ -209,7 +259,7 @@ impl<T: InvokeUiSession> Session<T> {
self.lc.read().unwrap().get_ui_flutter(&k)
}
pub fn toggle_option(&mut self, name: String) {
pub fn toggle_option(&self, name: String) {
let msg = self.lc.write().unwrap().toggle_option(name.clone());
#[cfg(not(feature = "flutter"))]
if name == "enable-file-transfer" {
@@ -252,7 +302,7 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::Message(msg));
}
pub fn save_custom_image_quality(&mut self, custom_image_quality: i32) {
pub fn save_custom_image_quality(&self, custom_image_quality: i32) {
let msg = self
.lc
.write()
@@ -261,14 +311,14 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::Message(msg));
}
pub fn save_image_quality(&mut self, value: String) {
pub fn save_image_quality(&self, value: String) {
let msg = self.lc.write().unwrap().save_image_quality(value);
if let Some(msg) = msg {
self.send(Data::Message(msg));
}
}
pub fn set_custom_fps(&mut self, custom_fps: i32) {
pub fn set_custom_fps(&self, custom_fps: i32) {
let msg = self.lc.write().unwrap().set_custom_fps(custom_fps);
self.send(Data::Message(msg));
}
@@ -372,7 +422,7 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::RemovePortForward(port));
}
pub fn add_port_forward(&mut self, port: i32, remote_host: String, remote_port: i32) {
pub fn add_port_forward(&self, port: i32, remote_host: String, remote_port: i32) {
let mut config = self.load_config();
if config
.port_forwards
@@ -833,16 +883,30 @@ impl<T: InvokeUiSession> Session<T> {
}
pub fn reconnect(&self, force_relay: bool) {
self.send(Data::Close);
// 1. If current session is connecting, do not reconnect.
// 2. If the connection is established, send `Data::Close`.
// 3. If the connection is disconnected, do nothing.
let mut connection_round_state_lock = self.connection_round_state.lock().unwrap();
if self.thread.lock().unwrap().is_some() {
match connection_round_state_lock.state {
ConnectionState::Connecting => return,
ConnectionState::Connected => self.send(Data::Close),
ConnectionState::Disconnected => {}
}
}
let round = connection_round_state_lock.new_round();
drop(connection_round_state_lock);
let cloned = self.clone();
// override only if true
if true == force_relay {
cloned.lc.write().unwrap().force_relay = true;
self.lc.write().unwrap().force_relay = true;
}
let mut lock = self.thread.lock().unwrap();
lock.take().map(|t| t.join());
// No need to join the previous thread, because it will exit automatically.
// And the previous thread will not change important states.
*lock = Some(std::thread::spawn(move || {
io_loop(cloned);
io_loop(cloned, round);
}));
}
@@ -1151,11 +1215,11 @@ impl<T: InvokeUiSession> Interface for Session<T> {
self.ui_handler.msgbox(msgtype, title, text, link, retry);
}
fn handle_login_error(&mut self, err: &str) -> bool {
fn handle_login_error(&self, err: &str) -> bool {
handle_login_error(self.lc.clone(), err, self)
}
fn handle_peer_info(&mut self, mut pi: PeerInfo) {
fn handle_peer_info(&self, mut pi: PeerInfo) {
log::debug!("handle_peer_info :{:?}", pi);
pi.username = self.lc.read().unwrap().get_username(&pi);
if pi.current_display as usize >= pi.displays.len() {
@@ -1217,12 +1281,12 @@ impl<T: InvokeUiSession> Interface for Session<T> {
}
}
async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream) {
async fn handle_hash(&self, pass: &str, hash: Hash, peer: &mut Stream) {
handle_hash(self.lc.clone(), pass, hash, self, peer).await;
}
async fn handle_login_from_ui(
&mut self,
&self,
os_username: String,
os_password: String,
password: String,
@@ -1240,7 +1304,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
.await;
}
async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream) {
async fn handle_test_delay(&self, t: TestDelay, peer: &mut Stream) {
if !t.from_client {
self.update_quality_status(QualityStatus {
delay: Some(t.last_delay as _),
@@ -1283,7 +1347,7 @@ impl<T: InvokeUiSession> Session<T> {
}
#[tokio::main(flavor = "current_thread")]
pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>) {
pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>, round: u32) {
// It is ok to call this function multiple times.
#[cfg(any(target_os = "windows", target_os = "linux"))]
if !handler.is_file_transfer() && !handler.is_port_forward() {
@@ -1402,7 +1466,7 @@ pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>) {
frame_count,
decode_fps,
);
remote.io_loop(&key, &token).await;
remote.io_loop(&key, &token, round).await;
remote.sync_jobs_status_to_local().await;
}