mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-02-17 22:11:30 +08:00
fix: file transfer, auto start on reconnect (#13329)
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -92,6 +92,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
|
||||
gFFI.dialogManager.dismissAll();
|
||||
WakelockPlus.disable();
|
||||
});
|
||||
model.jobController.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -1033,30 +1033,54 @@ class JobController {
|
||||
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
|
||||
}
|
||||
|
||||
void loadLastJob(Map<String, dynamic> evt) {
|
||||
Future<void> loadLastJob(Map<String, dynamic> evt) async {
|
||||
debugPrint("load last job: $evt");
|
||||
Map<String, dynamic> jobDetail = json.decode(evt['value']);
|
||||
// int id = int.parse(jobDetail['id']);
|
||||
String remote = jobDetail['remote'];
|
||||
String to = jobDetail['to'];
|
||||
bool showHidden = jobDetail['show_hidden'];
|
||||
int fileNum = jobDetail['file_num'];
|
||||
bool isRemote = jobDetail['is_remote'];
|
||||
final currJobId = JobController.jobID.next();
|
||||
String fileName = path.basename(isRemote ? remote : to);
|
||||
var jobProgress = JobProgress()
|
||||
..type = JobType.transfer
|
||||
..fileName = fileName
|
||||
..jobName = isRemote ? remote : to
|
||||
..id = currJobId
|
||||
..isRemoteToLocal = isRemote
|
||||
..fileNum = fileNum
|
||||
..remote = remote
|
||||
..to = to
|
||||
..showHidden = showHidden
|
||||
..state = JobState.paused;
|
||||
jobTable.add(jobProgress);
|
||||
bind.sessionAddJob(
|
||||
bool isAutoStart = jobDetail['auto_start'] == true;
|
||||
int currJobId = -1;
|
||||
if (isAutoStart) {
|
||||
// Ensure jobDetail['id'] exists and is an int
|
||||
if (jobDetail.containsKey('id') &&
|
||||
jobDetail['id'] != null &&
|
||||
jobDetail['id'] is int) {
|
||||
currJobId = jobDetail['id'];
|
||||
}
|
||||
}
|
||||
if (currJobId < 0) {
|
||||
// If id is missing or invalid, disable auto-start and assign a new job id
|
||||
isAutoStart = false;
|
||||
currJobId = JobController.jobID.next();
|
||||
}
|
||||
|
||||
if (!isAutoStart) {
|
||||
if (!(isDesktop || isWebDesktop)) {
|
||||
// Don't add to job table if not auto start on mobile.
|
||||
// Because mobile does not support job list view now.
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to job table if not auto start on desktop.
|
||||
String fileName = path.basename(isRemote ? remote : to);
|
||||
final jobProgress = JobProgress()
|
||||
..type = JobType.transfer
|
||||
..fileName = fileName
|
||||
..jobName = isRemote ? remote : to
|
||||
..id = currJobId
|
||||
..isRemoteToLocal = isRemote
|
||||
..fileNum = fileNum
|
||||
..remote = remote
|
||||
..to = to
|
||||
..showHidden = showHidden
|
||||
..state = JobState.paused;
|
||||
jobTable.add(jobProgress);
|
||||
}
|
||||
|
||||
await bind.sessionAddJob(
|
||||
sessionId: sessionId,
|
||||
isRemote: isRemote,
|
||||
includeHidden: showHidden,
|
||||
@@ -1065,6 +1089,11 @@ class JobController {
|
||||
to: isRemote ? to : remote,
|
||||
fileNum: fileNum,
|
||||
);
|
||||
|
||||
if (isAutoStart) {
|
||||
await bind.sessionResumeJob(
|
||||
sessionId: sessionId, actId: currJobId, isRemote: isRemote);
|
||||
}
|
||||
}
|
||||
|
||||
void resumeJob(int jobId) {
|
||||
@@ -1095,6 +1124,11 @@ class JobController {
|
||||
}
|
||||
debugPrint("update folder files: $info");
|
||||
}
|
||||
|
||||
void clear() {
|
||||
jobTable.clear();
|
||||
jobResultListener.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class JobResultListener<T> {
|
||||
|
||||
@@ -23,7 +23,7 @@ use std::{
|
||||
os::raw::{c_char, c_int, c_void},
|
||||
str::FromStr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
Arc, RwLock,
|
||||
},
|
||||
};
|
||||
@@ -756,7 +756,7 @@ impl InvokeUiSession for FlutterHandler {
|
||||
// unused in flutter
|
||||
fn clear_all_jobs(&self) {}
|
||||
|
||||
fn load_last_job(&self, _cnt: i32, job_json: &str) {
|
||||
fn load_last_job(&self, _cnt: i32, job_json: &str, _auto_start: bool) {
|
||||
self.push_event("load_last_job", &[("value", job_json)], &[]);
|
||||
}
|
||||
|
||||
@@ -1328,6 +1328,7 @@ pub fn session_add(
|
||||
server_keyboard_enabled: Arc::new(RwLock::new(true)),
|
||||
server_file_transfer_enabled: Arc::new(RwLock::new(true)),
|
||||
server_clipboard_enabled: Arc::new(RwLock::new(true)),
|
||||
reconnect_count: Arc::new(AtomicUsize::new(0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ class JobTable: Reactor.Component {
|
||||
self.timer(30ms, function() { self.update(); });
|
||||
}
|
||||
|
||||
function addJob(id, path, to, file_num, show_hidden, is_remote) {
|
||||
function addJob(id, path, to, file_num, show_hidden, is_remote, auto_start) {
|
||||
var job = { type: "transfer",
|
||||
id: id, path: path, to: to,
|
||||
include_hidden: show_hidden,
|
||||
@@ -146,6 +146,10 @@ class JobTable: Reactor.Component {
|
||||
this.job_map[id] = this.jobs[this.jobs.length - 1];
|
||||
handler.update_next_job_id(id + 1);
|
||||
handler.add_job(id, 0, path, to, file_num, show_hidden, is_remote);
|
||||
if (auto_start) {
|
||||
this.continueJob(id);
|
||||
this.update();
|
||||
}
|
||||
stdout.println(JSON.stringify(job));
|
||||
}
|
||||
|
||||
@@ -279,7 +283,8 @@ class JobTable: Reactor.Component {
|
||||
if (!err) {
|
||||
handler.remove_dir(job.id, job.path, job.is_remote);
|
||||
refreshDir(job.is_remote);
|
||||
if (is_remote) file_transfer.remote_folder_view.table.resetCurrent();
|
||||
// Use the job's is_remote; local variable `is_remote` is undefined in this scope.
|
||||
if (job.is_remote) file_transfer.remote_folder_view.table.resetCurrent();
|
||||
else file_transfer.local_folder_view.table.resetCurrent();
|
||||
}
|
||||
} else if (!job.no_confirm) {
|
||||
@@ -697,9 +702,9 @@ handler.clearAllJobs = function() {
|
||||
file_transfer.job_table.clearAllJobs();
|
||||
}
|
||||
|
||||
handler.addJob = function (id, path, to, file_num, show_hidden, is_remote) { // load last job
|
||||
handler.addJob = function (id, path, to, file_num, show_hidden, is_remote, auto_start) { // load last job
|
||||
// stdout.println("restore job: " + is_remote);
|
||||
file_transfer.job_table.addJob(id,path,to,file_num,show_hidden,is_remote);
|
||||
file_transfer.job_table.addJob(id,path,to,file_num,show_hidden,is_remote,auto_start);
|
||||
}
|
||||
|
||||
handler.updateTransferList = function () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
sync::{atomic::AtomicUsize, Arc, Mutex, RwLock},
|
||||
};
|
||||
|
||||
use sciter::{
|
||||
@@ -199,7 +199,7 @@ impl InvokeUiSession for SciterHandler {
|
||||
self.call("clearAllJobs", &make_args!());
|
||||
}
|
||||
|
||||
fn load_last_job(&self, cnt: i32, job_json: &str) {
|
||||
fn load_last_job(&self, cnt: i32, job_json: &str, auto_start: bool) {
|
||||
let job: Result<TransferJobMeta, serde_json::Error> = serde_json::from_str(job_json);
|
||||
if let Ok(job) = job {
|
||||
let path;
|
||||
@@ -213,7 +213,15 @@ impl InvokeUiSession for SciterHandler {
|
||||
}
|
||||
self.call(
|
||||
"addJob",
|
||||
&make_args!(cnt, path, to, job.file_num, job.show_hidden, job.is_remote),
|
||||
&make_args!(
|
||||
cnt,
|
||||
path,
|
||||
to,
|
||||
job.file_num,
|
||||
job.show_hidden,
|
||||
job.is_remote,
|
||||
auto_start
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -570,6 +578,7 @@ impl SciterSession {
|
||||
server_keyboard_enabled: Arc::new(RwLock::new(true)),
|
||||
server_file_transfer_enabled: Arc::new(RwLock::new(true)),
|
||||
server_clipboard_enabled: Arc::new(RwLock::new(true)),
|
||||
reconnect_count: Arc::new(AtomicUsize::new(0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,10 @@ use std::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc, Mutex, RwLock,
|
||||
},
|
||||
time::SystemTime,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
@@ -61,6 +64,9 @@ pub struct Session<T: InvokeUiSession> {
|
||||
pub last_change_display: Arc<Mutex<ChangeDisplayRecord>>,
|
||||
pub connection_round_state: Arc<Mutex<ConnectionRoundState>>,
|
||||
pub printer_names: Arc<RwLock<HashMap<i32, String>>>,
|
||||
// Indicate whether the session is reconnected.
|
||||
// Used to auto start file transfer after reconnection.
|
||||
pub reconnect_count: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -1272,6 +1278,7 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
self.lc.write().unwrap().force_relay = true;
|
||||
}
|
||||
self.lc.write().unwrap().peer_info = None;
|
||||
self.reconnect_count.fetch_add(1, Ordering::SeqCst);
|
||||
let mut lock = self.thread.lock().unwrap();
|
||||
// No need to join the previous thread, because it will exit automatically.
|
||||
// And the previous thread will not change important states.
|
||||
@@ -1372,6 +1379,24 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
self.send(Data::Close);
|
||||
}
|
||||
|
||||
fn try_auto_start_job_str(is_reconnected: bool, job_str: &str) -> Option<String> {
|
||||
if is_reconnected {
|
||||
let job_str = job_str.trim();
|
||||
if let Some(stripped) = job_str.strip_suffix('}') {
|
||||
format!(r#"{},"auto_start": true}}"#, stripped).into()
|
||||
} else {
|
||||
// unreachable in normal cases
|
||||
log::warn!(
|
||||
"The last character is not '}}': {}, auto start is ignored on flutter",
|
||||
job_str
|
||||
);
|
||||
Some(job_str.to_owned())
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_last_jobs(&self) {
|
||||
self.clear_all_jobs();
|
||||
let pc = self.load_config();
|
||||
@@ -1379,18 +1404,32 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
// no last jobs
|
||||
return;
|
||||
}
|
||||
let reconnect_count_thr = if cfg!(feature = "flutter") { 0 } else { 1 };
|
||||
let is_reconnected = self.reconnect_count.load(Ordering::SeqCst) > reconnect_count_thr;
|
||||
// TODO: can add a confirm dialog
|
||||
let mut cnt = 1;
|
||||
for job_str in pc.transfer.read_jobs.iter() {
|
||||
if !job_str.is_empty() {
|
||||
self.load_last_job(cnt, job_str);
|
||||
self.load_last_job(
|
||||
cnt,
|
||||
Self::try_auto_start_job_str(is_reconnected, job_str)
|
||||
.as_deref()
|
||||
.unwrap_or(job_str),
|
||||
is_reconnected,
|
||||
);
|
||||
cnt += 1;
|
||||
log::info!("restore read_job: {:?}", job_str);
|
||||
}
|
||||
}
|
||||
for job_str in pc.transfer.write_jobs.iter() {
|
||||
if !job_str.is_empty() {
|
||||
self.load_last_job(cnt, job_str);
|
||||
self.load_last_job(
|
||||
cnt,
|
||||
Self::try_auto_start_job_str(is_reconnected, job_str)
|
||||
.as_deref()
|
||||
.unwrap_or(job_str),
|
||||
is_reconnected,
|
||||
);
|
||||
cnt += 1;
|
||||
log::info!("restore write_job: {:?}", job_str);
|
||||
}
|
||||
@@ -1623,7 +1662,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
||||
fn clear_all_jobs(&self);
|
||||
fn new_message(&self, msg: String);
|
||||
fn update_transfer_list(&self);
|
||||
fn load_last_job(&self, cnt: i32, job_json: &str);
|
||||
fn load_last_job(&self, cnt: i32, job_json: &str, auto_start: bool);
|
||||
fn update_folder_files(
|
||||
&self,
|
||||
id: i32,
|
||||
|
||||
Reference in New Issue
Block a user