Merge pull request #1457 from Heap-Hop/master

Update desktop file transfer and fix sciter can't update connect status bug
This commit is contained in:
RustDesk 2022-09-06 20:21:23 +07:00 committed by GitHub
commit c474ac01cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 158 deletions

View File

@ -59,8 +59,11 @@ class _FileManagerPageState extends State<FileManagerPage>
super.initState(); super.initState();
_ffi = FFI(); _ffi = FFI();
_ffi.connect(widget.id, isFileTransfer: true); _ffi.connect(widget.id, isFileTransfer: true);
WidgetsBinding.instance.addPostFrameCallback((_) {
_ffi.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
Get.put(_ffi, tag: 'ft_${widget.id}'); Get.put(_ffi, tag: 'ft_${widget.id}');
// _ffi.ffiModel.updateEventListener(widget.id);
if (!Platform.isLinux) { if (!Platform.isLinux) {
Wakelock.enable(); Wakelock.enable();
} }
@ -117,7 +120,8 @@ class _FileManagerPageState extends State<FileManagerPage>
Widget menu({bool isLocal = false}) { Widget menu({bool isLocal = false}) {
return PopupMenuButton<String>( return PopupMenuButton<String>(
icon: Icon(Icons.more_vert), icon: const Icon(Icons.more_vert),
splashRadius: 20,
itemBuilder: (context) { itemBuilder: (context) {
return [ return [
PopupMenuItem( PopupMenuItem(
@ -413,6 +417,7 @@ class _FileManagerPageState extends State<FileManagerPage>
/// watch transfer status /// watch transfer status
Widget statusList() { Widget statusList() {
return PreferredSize( return PreferredSize(
preferredSize: const Size(200, double.infinity),
child: Container( child: Container(
margin: const EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0), margin: const EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0),
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -429,8 +434,8 @@ class _FileManagerPageState extends State<FileManagerPage>
children: [ children: [
Transform.rotate( Transform.rotate(
angle: item.isRemote ? pi : 0, angle: item.isRemote ? pi : 0,
child: Icon(Icons.send)), child: const Icon(Icons.send)),
SizedBox( const SizedBox(
width: 16.0, width: 16.0,
), ),
Expanded( Expanded(
@ -441,7 +446,7 @@ class _FileManagerPageState extends State<FileManagerPage>
Tooltip( Tooltip(
message: item.jobName, message: item.jobName,
child: Text( child: Text(
'${item.jobName}', item.jobName,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
)), )),
@ -455,7 +460,7 @@ class _FileManagerPageState extends State<FileManagerPage>
offstage: offstage:
item.state != JobState.inProgress, item.state != JobState.inProgress,
child: Text( child: Text(
'${readableFileSize(item.speed) + "/s"} ')), '${"${readableFileSize(item.speed)}/s"} ')),
Offstage( Offstage(
offstage: item.totalSize <= 0, offstage: item.totalSize <= 0,
child: Text( child: Text(
@ -475,10 +480,12 @@ class _FileManagerPageState extends State<FileManagerPage>
onPressed: () { onPressed: () {
model.resumeJob(item.id); model.resumeJob(item.id);
}, },
icon: Icon(Icons.restart_alt_rounded)), splashRadius: 20,
icon: const Icon(Icons.restart_alt_rounded)),
), ),
IconButton( IconButton(
icon: Icon(Icons.delete), icon: const Icon(Icons.delete),
splashRadius: 20,
onPressed: () { onPressed: () {
model.jobTable.removeAt(index); model.jobTable.removeAt(index);
model.cancelJob(item.id); model.cancelJob(item.id);
@ -500,8 +507,7 @@ class _FileManagerPageState extends State<FileManagerPage>
itemCount: model.jobTable.length, itemCount: model.jobTable.length,
), ),
), ),
), ));
preferredSize: Size(200, double.infinity));
} }
goBack({bool? isLocal}) { goBack({bool? isLocal}) {
@ -551,12 +557,15 @@ class _FileManagerPageState extends State<FileManagerPage>
Row( Row(
children: [ children: [
IconButton( IconButton(
onPressed: () { onPressed: () {
model.goHome(isLocal: isLocal); model.goHome(isLocal: isLocal);
}, },
icon: Icon(Icons.home_outlined)), icon: const Icon(Icons.home_outlined),
splashRadius: 20,
),
IconButton( IconButton(
icon: Icon(Icons.arrow_upward), icon: const Icon(Icons.arrow_upward),
splashRadius: 20,
onPressed: () { onPressed: () {
goBack(isLocal: isLocal); goBack(isLocal: isLocal);
}, },
@ -622,13 +631,15 @@ class _FileManagerPageState extends State<FileManagerPage>
), ),
)) ))
], ],
child: Icon(Icons.search), splashRadius: 20,
child: const Icon(Icons.search),
), ),
IconButton( IconButton(
onPressed: () { onPressed: () {
model.refresh(isLocal: isLocal); model.refresh(isLocal: isLocal);
}, },
icon: Icon(Icons.refresh)), splashRadius: 20,
icon: const Icon(Icons.refresh)),
], ],
), ),
Row( Row(
@ -686,6 +697,7 @@ class _FileManagerPageState extends State<FileManagerPage>
); );
}); });
}, },
splashRadius: 20,
icon: const Icon(Icons.create_new_folder_outlined)), icon: const Icon(Icons.create_new_folder_outlined)),
IconButton( IconButton(
onPressed: () async { onPressed: () async {
@ -695,7 +707,8 @@ class _FileManagerPageState extends State<FileManagerPage>
await (model.removeAction(items, isLocal: isLocal)); await (model.removeAction(items, isLocal: isLocal));
items.clear(); items.clear();
}, },
icon: Icon(Icons.delete_forever_outlined)), splashRadius: 20,
icon: const Icon(Icons.delete_forever_outlined)),
], ],
), ),
), ),
@ -707,7 +720,7 @@ class _FileManagerPageState extends State<FileManagerPage>
}, },
icon: Transform.rotate( icon: Transform.rotate(
angle: isLocal ? 0 : pi, angle: isLocal ? 0 : pi,
child: Icon( child: const Icon(
Icons.send, Icons.send,
), ),
), ),

View File

@ -360,9 +360,9 @@ class FileModel extends ChangeNotifier {
Future refresh({bool? isLocal}) async { Future refresh({bool? isLocal}) async {
if (isDesktop) { if (isDesktop) {
isLocal = isLocal ?? _isLocal; isLocal = isLocal ?? _isLocal;
await isLocal isLocal
? openDirectory(currentLocalDir.path, isLocal: isLocal) ? await openDirectory(currentLocalDir.path, isLocal: isLocal)
: openDirectory(currentRemoteDir.path, isLocal: isLocal); : await openDirectory(currentRemoteDir.path, isLocal: isLocal);
} else { } else {
await openDirectory(currentDir.path); await openDirectory(currentDir.path);
} }
@ -393,7 +393,7 @@ class FileModel extends ChangeNotifier {
} }
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
debugPrint("Failed to openDirectory ${path} :$e"); debugPrint("Failed to openDirectory $path: $e");
} }
} }

View File

@ -326,8 +326,8 @@ class FfiModel with ChangeNotifier {
await bind.sessionGetOption(id: peerId, arg: "touch-mode") != ''; await bind.sessionGetOption(id: peerId, arg: "touch-mode") != '';
} }
if (evt['is_file_transfer'] == "true") { if (parent.target != null &&
// TODO is file transfer parent.target!.connType == ConnType.fileTransfer) {
parent.target?.fileModel.onReady(); parent.target?.fileModel.onReady();
} else { } else {
_pi.displays = []; _pi.displays = [];
@ -916,6 +916,8 @@ extension ToString on MouseButtons {
} }
} }
enum ConnType { defaultConn, fileTransfer, portForward, rdp }
/// FFI class for communicating with the Rust core. /// FFI class for communicating with the Rust core.
class FFI { class FFI {
var id = ""; var id = "";
@ -924,6 +926,7 @@ class FFI {
var alt = false; var alt = false;
var command = false; var command = false;
var version = ""; var version = "";
var connType = ConnType.defaultConn;
/// dialogManager use late to ensure init after main page binding [globalKey] /// dialogManager use late to ensure init after main page binding [globalKey]
late final dialogManager = OverlayDialogManager(); late final dialogManager = OverlayDialogManager();
@ -1055,9 +1058,11 @@ class FFI {
double tabBarHeight = 0.0}) { double tabBarHeight = 0.0}) {
assert(!(isFileTransfer && isPortForward), "more than one connect type"); assert(!(isFileTransfer && isPortForward), "more than one connect type");
if (isFileTransfer) { if (isFileTransfer) {
id = 'ft_${id}'; connType = ConnType.fileTransfer;
id = 'ft_$id';
} else if (isPortForward) { } else if (isPortForward) {
id = 'pf_${id}'; connType = ConnType.portForward;
id = 'pf_$id';
} else { } else {
chatModel.resetClientMode(); chatModel.resetClientMode();
canvasModel.id = id; canvasModel.id = id;
@ -1086,7 +1091,7 @@ class FFI {
// every instance will bind a stream // every instance will bind a stream
this.id = id; this.id = id;
if (isFileTransfer) { if (isFileTransfer) {
this.fileModel.initFileFetcher(); fileModel.initFileFetcher();
} }
} }

View File

@ -1665,6 +1665,7 @@ pub async fn handle_login_from_ui(
/// Interface for client to send data and commands. /// Interface for client to send data and commands.
#[async_trait] #[async_trait]
pub trait Interface: Send + Clone + 'static + Sized { pub trait Interface: Send + Clone + 'static + Sized {
/// Send message data to remote peer.
fn send(&self, data: Data); fn send(&self, data: Data);
fn msgbox(&self, msgtype: &str, title: &str, text: &str); fn msgbox(&self, msgtype: &str, title: &str, text: &str);
fn handle_login_error(&mut self, err: &str) -> bool; fn handle_login_error(&mut self, err: &str) -> bool;

View File

@ -269,33 +269,6 @@ impl<T: InvokeUiSession> Remote<T> {
Some(tx) Some(tx)
} }
// TODO
fn load_last_jobs(&mut self) {
self.handler.clear_all_jobs();
let pc = self.handler.load_config();
if pc.transfer.write_jobs.is_empty() && pc.transfer.read_jobs.is_empty() {
// no last jobs
return;
}
// 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.handler.load_last_job(cnt, job_str);
cnt += 1;
log::info!("restore read_job: {:?}", job_str);
}
}
for job_str in pc.transfer.write_jobs.iter() {
if !job_str.is_empty() {
self.handler.load_last_job(cnt, job_str);
cnt += 1;
log::info!("restore write_job: {:?}", job_str);
}
}
self.handler.update_transfer_list();
}
async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool { async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool {
match data { match data {
Data::Close => { Data::Close => {
@ -479,7 +452,6 @@ impl<T: InvokeUiSession> Remote<T> {
file_num, file_num,
job.files[i].name.clone(), job.files[i].name.clone(),
); );
self.handler.confirm_delete_files(id, file_num);
} }
} }
} }
@ -768,7 +740,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
if self.handler.is_file_transfer() { if self.handler.is_file_transfer() {
self.load_last_jobs(); self.handler.load_last_jobs();
} }
} }
_ => {} _ => {}
@ -827,7 +799,7 @@ impl<T: InvokeUiSession> Remote<T> {
&entries, &entries,
fd.path, fd.path,
false, false,
fd.id > 0, false,
); );
if let Some(job) = fs::get_job(fd.id, &mut self.write_jobs) { if let Some(job) = fs::get_job(fd.id, &mut self.write_jobs) {
log::info!("job set_files: {:?}", entries); log::info!("job set_files: {:?}", entries);

View File

@ -366,7 +366,7 @@ pub fn session_get_platform(id: String, is_remote: bool) -> String {
pub fn session_load_last_transfer_jobs(id: String) { pub fn session_load_last_transfer_jobs(id: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&id) {
// return session.load_last_jobs(); return session.load_last_jobs();
} else { } else {
// a tip for flutter dev // a tip for flutter dev
eprintln!( eprintln!(

View File

@ -87,7 +87,7 @@ pub fn start(args: &mut [String]) {
} }
#[cfg(windows)] #[cfg(windows)]
if args.len() > 0 && args[0] == "--tray" { if args.len() > 0 && args[0] == "--tray" {
let options = check_connect_status(false).1; let options = crate::ui_interface::check_connect_status(false).1;
crate::tray::start_tray(options); crate::tray::start_tray(options);
return; return;
} }
@ -664,79 +664,6 @@ pub fn check_zombie(childs: Childs) {
} }
} }
// notice: avoiding create ipc connecton repeatly,
// because windows named pipe has serious memory leak issue.
#[tokio::main(flavor = "current_thread")]
async fn check_connect_status_(
reconnect: bool,
status: Arc<Mutex<Status>>,
options: Arc<Mutex<HashMap<String, String>>>,
rx: mpsc::UnboundedReceiver<ipc::Data>,
password: Arc<Mutex<String>>,
) {
let mut key_confirmed = false;
let mut rx = rx;
let mut mouse_time = 0;
let mut id = "".to_owned();
loop {
if let Ok(mut c) = ipc::connect(1000, "").await {
let mut timer = time::interval(time::Duration::from_secs(1));
loop {
tokio::select! {
res = c.next() => {
match res {
Err(err) => {
log::error!("ipc connection closed: {}", err);
break;
}
Ok(Some(ipc::Data::MouseMoveTime(v))) => {
mouse_time = v;
status.lock().unwrap().2 = v;
}
Ok(Some(ipc::Data::Options(Some(v)))) => {
*options.lock().unwrap() = v
}
Ok(Some(ipc::Data::Config((name, Some(value))))) => {
if name == "id" {
id = value;
} else if name == "temporary-password" {
*password.lock().unwrap() = value;
}
}
Ok(Some(ipc::Data::OnlineStatus(Some((mut x, c))))) => {
if x > 0 {
x = 1
}
key_confirmed = c;
*status.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone());
}
_ => {}
}
}
Some(data) = rx.recv() => {
allow_err!(c.send(&data).await);
}
_ = timer.tick() => {
c.send(&ipc::Data::OnlineStatus(None)).await.ok();
c.send(&ipc::Data::Options(None)).await.ok();
c.send(&ipc::Data::Config(("id".to_owned(), None))).await.ok();
c.send(&ipc::Data::Config(("temporary-password".to_owned(), None))).await.ok();
}
}
}
}
if !reconnect {
options
.lock()
.unwrap()
.insert("ipc-closed".to_owned(), "Y".to_owned());
break;
}
*status.lock().unwrap() = (-1, key_confirmed, mouse_time, id.clone());
sleep(1.).await;
}
}
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn get_sound_inputs() -> Vec<String> { fn get_sound_inputs() -> Vec<String> {
let mut out = Vec::new(); let mut out = Vec::new();
@ -763,27 +690,6 @@ fn get_sound_inputs() -> Vec<String> {
.collect() .collect()
} }
fn check_connect_status(
reconnect: bool,
) -> (
Arc<Mutex<Status>>,
Arc<Mutex<HashMap<String, String>>>,
mpsc::UnboundedSender<ipc::Data>,
Arc<Mutex<String>>,
) {
let status = Arc::new(Mutex::new((0, false, 0, "".to_owned())));
let options = Arc::new(Mutex::new(Config::get_options()));
let cloned = status.clone();
let cloned_options = options.clone();
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
let password = Arc::new(Mutex::new(String::default()));
let cloned_password = password.clone();
std::thread::spawn(move || {
check_connect_status_(reconnect, cloned, cloned_options, rx, cloned_password)
});
(status, options, tx, password)
}
const INVALID_FORMAT: &'static str = "Invalid format"; const INVALID_FORMAT: &'static str = "Invalid format";
const UNKNOWN_ERROR: &'static str = "Unknown error"; const UNKNOWN_ERROR: &'static str = "Unknown error";

View File

@ -1055,6 +1055,7 @@ function showSettings() {
} }
function checkConnectStatus() { function checkConnectStatus() {
handler.check_mouse_time(); // trigger connection status updater
self.timer(1s, function() { self.timer(1s, function() {
var tmp = !!handler.get_option("stop-service"); var tmp = !!handler.get_option("stop-service");
if (tmp != service_stopped) { if (tmp != service_stopped) {

View File

@ -709,18 +709,15 @@ impl SciterSession {
} }
pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value { pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
log::debug!("make_fd");
let mut m = Value::map(); let mut m = Value::map();
m.set_item("id", id); m.set_item("id", id);
let mut a = Value::array(0); let mut a = Value::array(0);
let mut n: u64 = 0; let mut n: u64 = 0;
for entry in entries { for entry in entries {
log::debug!("for");
n += entry.size; n += entry.size;
if only_count { if only_count {
continue; continue;
} }
log::debug!("for1");
let mut e = Value::map(); let mut e = Value::map();
e.set_item("name", entry.name.to_owned()); e.set_item("name", entry.name.to_owned());
let tmp = entry.entry_type.value(); let tmp = entry.entry_type.value();
@ -734,6 +731,5 @@ pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
} }
m.set_item("num_entries", entries.len() as i32); m.set_item("num_entries", entries.len() as i32);
m.set_item("total_size", n as f64); m.set_item("total_size", n as f64);
log::debug!("make_fd end");
m m
} }

View File

@ -532,6 +532,32 @@ impl<T: InvokeUiSession> Session<T> {
pub fn close(&self) { pub fn close(&self) {
self.send(Data::Close); self.send(Data::Close);
} }
pub fn load_last_jobs(&self) {
self.clear_all_jobs();
let pc = self.load_config();
if pc.transfer.write_jobs.is_empty() && pc.transfer.read_jobs.is_empty() {
// no last jobs
return;
}
// 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);
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);
cnt += 1;
log::info!("restore write_job: {:?}", job_str);
}
}
self.update_transfer_list();
}
} }
pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {