diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 4dbb32e..2113d23 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -22,7 +22,12 @@ public MainWindow() { private static MainWindow instance; public static void ShowMessage(string message, string caption) { - instance.Dispatcher.BeginInvoke((Action) (() => MessageBox.Show(message, caption))); + instance.Dispatcher.Invoke(() => { + instance.TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Error; + instance.TaskbarItemInfo.ProgressValue = 100; + MessageBox.Show(instance, message, caption); + instance.TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; + }); } void MainWindow_Loaded(object sender, RoutedEventArgs e) { diff --git a/Model/SFTPFileUploader.cs b/Model/SFTPFileUploader.cs index 7a9e726..a756c0f 100644 --- a/Model/SFTPFileUploader.cs +++ b/Model/SFTPFileUploader.cs @@ -25,7 +25,7 @@ public SFTPFileUploader() { private SftpClient client; private string base_path; private int base_path_len; - public void connect(String host, int port, String user, String local_path, String remote_path, String password) { + public async Task connect(String host, int port, String user, String local_path, String remote_path, String password) { base_path = local_path; base_path_len = (base_path.EndsWith("/") || base_path.EndsWith("\\")) ? base_path.Length : base_path.Length + 1; //if it doesnt end in a slash we need to skip it if (String.IsNullOrWhiteSpace(user)) { @@ -47,13 +47,13 @@ public void connect(String host, int port, String user, String local_path, Strin client.ChangeDirectory(remote_path); ConnChanged(); } catch (SocketException e) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Unable to connect due to socket exception of: " + e.Message, "Connection Error"); } catch (SshAuthenticationException e) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Unable to connect due to auth exception of: " + e.Message, "Connection Error"); } catch (SftpPathNotFoundException) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Unable to switch to remote folder of: " + remote_path + " as it doesn't exist", "Connection Error"); } } @@ -65,17 +65,17 @@ private void ConnChanged() { public bool is_connected { get { return client != null && client.IsConnected; } } - void client_ErrorOccurred(object sender, Renci.SshNet.Common.ExceptionEventArgs e) { + async void client_ErrorOccurred(object sender, Renci.SshNet.Common.ExceptionEventArgs e) { try { throw e.Exception; } catch (SocketException exp) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Connection lost due to " + exp.SocketErrorCode + ": " + exp.Message, "Connection Error"); } catch (SshConnectionException ss_exp) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Connection issue due to " + ss_exp.DisconnectReason + ": " + ss_exp.Message, "Connection Error"); } catch (Exception ee) { - disconnect(); + await disconnect(); if (Debugger.IsAttached) throw ee; MainWindow.ShowMessage("unknown error let us know: " + ee.Message, "Unknown Error"); @@ -88,43 +88,48 @@ private void UploadCallback(ulong progress, ulong total_size) { UploadEvtProgress(this, evt); } ConcurrentQueue CurQueue = new ConcurrentQueue(); - private async void UploadLoop() { + private void UploadLoop() {//don't make async as then lose thread name string file; string last_file = null; int was_connected_cnt = 0; while (true) { - while (CurQueue.TryDequeue(out file)) { - if (!is_connected) { - was_connected_cnt = 0; - CurQueue = new ConcurrentQueue(); - disconnect(); - MainWindow.ShowMessage("Connection to server lost.", "Lost Connection");//maybe not supposed to ever happen? should have been caught sooner - break; - } - was_connected_cnt = 1; - if (file == last_file) - await Task.Delay(50); - last_file = file; - if ((DateTime.Now - last_changed[file]).TotalMilliseconds < 50) { - CurQueue.Enqueue(file); - continue; - } - var remote_name = file.Substring(base_path_len); - remote_name = remote_name.Replace('\\', '/'); - if (CurQueue.Contains(file))//continue if it was added to the queue again since we started - continue; - await UploadFile(file, remote_name); - if (!CurQueue.Contains(file)) - last_changed.Remove(file); + try { + while (CurQueue.TryDequeue(out file)) { + if (!is_connected) { + was_connected_cnt = 0; + CurQueue = new ConcurrentQueue(); + disconnect().Wait(); + MainWindow.ShowMessage("Connection to server lost.", "Lost Connection"); //maybe not supposed to ever happen? should have been caught sooner + break; + } + was_connected_cnt = 1; + if (file == last_file) + Task.Delay(50).Wait(); + last_file = file; + if ((DateTime.Now - last_changed[file]).TotalMilliseconds < 50) { + CurQueue.Enqueue(file); + continue; + } + var remote_name = file.Substring(base_path_len); + remote_name = remote_name.Replace('\\', '/'); + if (CurQueue.Contains(file)) //continue if it was added to the queue again since we started + continue; + UploadFile(file, remote_name).Wait(); + if (!CurQueue.Contains(file)) + last_changed.Remove(file); + } + bool is_conn = false; + if (was_connected_cnt > 0 && was_connected_cnt++ < 60 * 100 || (is_conn = is_connected)) { + //so isconnected is a bit of a possible costly call so lets not call it every 50ms. Lets cache for up to 5 minutes + if (is_conn) + was_connected_cnt = 1; + Task.Delay(50).Wait(); + } else + Task.Delay(1000).Wait(); + }catch(Exception e) { + MessageBox.Show("Exception in upload loop should attach debugger and figure out why this is not caught currently: " + e.Message + "\n" + e.StackTrace); } - bool is_conn = false; - if (was_connected_cnt > 0 && was_connected_cnt++ < 60 * 100 || (is_conn = is_connected)) { //so isconnected is a bit of a possible costly call so lets not call it every 50ms. Lets cache for up to 5 minutes - if (is_conn) - was_connected_cnt = 1; - await Task.Delay(50); - } else - await Task.Delay(1000); } } private async Task UploadFile(String filename, String remote_name) { @@ -143,31 +148,38 @@ private async Task UploadFile(String filename, String remote_name) { } throw e; } catch (SshConnectionException e) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Connection to server lost details: " + e.Message, "Lost Connection"); } catch (SftpPermissionDeniedException e) { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Permission denied trying to upload due to: " + e.Message, "Permission Error"); - } catch (SftpPathNotFoundException) { - disconnect(); - MainWindow.ShowMessage("Remote file not found, most likely invalid remote path(make sure folder exists)", "Path Not Found Error"); + } catch (SftpPathNotFoundException e) { + await disconnect(); + MainWindow.ShowMessage($"Remote file not accessible, most likely invalid remote path(make sure folder exists): {remote_name}", "Path Not Found Error"); } catch (SshException e) { if (e.Message == "Channel was closed.") { - disconnect(); + await disconnect(); MainWindow.ShowMessage("Connection to server lost details: " + e.Message, "Lost Connection"); } else if (e.Message == "Failure.") { - disconnect(); + await disconnect(); MainWindow.ShowMessage("General failure from SSH Libary", "General Failure"); } else throw e; } } - public void disconnect() { + public async Task disconnect() { if (client != null) { try { - client.Disconnect(); - if (client.IsConnected) - client.Disconnect(); + var tsk = Task.Run(() => { + if (client.IsConnected) //otherwise it can hang forever + client.Disconnect(); + if (client.IsConnected) + client.Disconnect(); + }); + await Task.WhenAny(tsk, Task.Delay(60 * 1000)); + if (!tsk.IsCompleted) { + MessageBox.Show("Prevented a hang on disconnect"); + } } catch (Exception e) { Debug.WriteLine("Unable to disconnect due to: " + e.Message); } diff --git a/NovaSFTP2.csproj b/NovaSFTP2.csproj index f6897a9..65e1c3a 100644 --- a/NovaSFTP2.csproj +++ b/NovaSFTP2.csproj @@ -24,7 +24,7 @@ false false true - 6 + 7 1.0.0.%2a false true diff --git a/ViewModel/MainViewModel.cs b/ViewModel/MainViewModel.cs index 2ea16e5..8c255b6 100644 --- a/ViewModel/MainViewModel.cs +++ b/ViewModel/MainViewModel.cs @@ -97,23 +97,23 @@ private void UpdateButton() { title = t_str; } - private void connect() { - uploader.connect(hostname, port, username, local_folder, remote_folder, password); + private async Task connect() { + await uploader.connect(hostname, port, username, local_folder, remote_folder, password); if (String.IsNullOrWhiteSpace(selected_host?.name) == false) UpdateRecent(selected_host.name); } - private void disconnect() { + private async Task disconnect() { StopWatcher(); - uploader.disconnect(); + await uploader.disconnect(); } private bool connected { get { return uploader.is_connected; } } - public ICommand ToggleConnectedCmd => new OurCommand(ToggleConnected,true,true); - private void ToggleConnected() { + public ICommand ToggleConnectedCmd => new OurCommand(ToggleConnected,true); + private async Task ToggleConnected() { if (connected) - disconnect(); + await disconnect(); else - connect(); + await Task.Run(async ()=> await connect()); } private void FileChanged(object sender, FileSystemEventArgs args) { if (args.ChangeType == WatcherChangeTypes.Deleted) diff --git a/lib_bins/Renci.SshNet.dll b/lib_bins/Renci.SshNet.dll index 292e1dd..804bc95 100644 Binary files a/lib_bins/Renci.SshNet.dll and b/lib_bins/Renci.SshNet.dll differ