diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index d3c4b3b6a..45145498e 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -573,6 +573,30 @@ public interface ISftpClient : IBaseClient /// void DownloadFile(string path, Stream output, Action? downloadCallback = null); + /// + /// Asynchronously downloads remote file specified by the path into the stream. + /// + /// File to download. + /// Stream to write the file into. + /// The download callback. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// is . + /// is or contains only whitespace characters. + /// Client is not connected. + /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. + /// was not found on the remote host./// + /// A SSH error where is the message from the remote host. + /// The method was called after the client was disposed. + /// + /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. + /// + /// A representing the asynchronous operation. + Task DownloadFileAsync(string path, Stream output, Action? downloadCallback = null, TaskFactory? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null); + /// /// Ends an asynchronous file downloading into the stream. /// @@ -1038,6 +1062,22 @@ public interface ISftpClient : IBaseClient /// If a problem occurs while copying the file. IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern); + /// + /// Asynchronously synchronizes the directories. + /// + /// The source path. + /// The destination path. + /// The search pattern. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// + /// A list of uploaded files. + /// + Task> SynchronizeDirectoriesAsync(string sourcePath, string destinationPath, string searchPattern, TaskFactory>? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null); + /// /// Uploads stream into remote file. /// @@ -1073,6 +1113,21 @@ public interface ISftpClient : IBaseClient /// void UploadFile(Stream input, string path, bool canOverride, Action? uploadCallback = null); + /// + /// Asynchronously upload the stream into the remote file. + /// + /// Data input stream. + /// Remote file path. + /// if set to then existing file will be overwritten. + /// The upload callback. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// A representing the asynchronous operation. + Task UploadFileAsync(Stream input, string path, bool canOverride = false, Action? uploadCallback = null, TaskFactory? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null); + /// /// Writes the specified byte array to the specified file, and closes the file. /// diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 4a5d7dbe7..631729b81 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -916,6 +916,39 @@ public void DownloadFile(string path, Stream output, Action? downloadCall InternalDownloadFile(path, output, asyncResult: null, downloadCallback); } + /// + /// Asynchronously downloads remote file specified by the path into the stream. + /// + /// File to download. + /// Stream to write the file into. + /// The download callback. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// is . + /// is or contains only whitespace characters. + /// Client is not connected. + /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. + /// was not found on the remote host./// + /// A SSH error where is the message from the remote host. + /// The method was called after the client was disposed. + /// + /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. + /// + /// A representing the asynchronous operation. + public Task DownloadFileAsync(string path, Stream output, Action? downloadCallback = null, TaskFactory? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null) + { + var taskFactory = factory ?? Task.Factory; + + return taskFactory.FromAsync( + BeginDownloadFile(path, output, asyncCallback: null, state: null, downloadCallback), + EndDownloadFile, + creationOptions, + scheduler ?? taskFactory.Scheduler ?? TaskScheduler.Current); + } + /// /// Begins an asynchronous file downloading into the stream. /// @@ -1077,6 +1110,30 @@ public void UploadFile(Stream input, string path, bool canOverride, Action + /// Asynchronously upload the stream into the remote file. + /// + /// Data input stream. + /// Remote file path. + /// if set to then existing file will be overwritten. + /// The upload callback. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// A representing the asynchronous operation. + public Task UploadFileAsync(Stream input, string path, bool canOverride = false, Action? uploadCallback = null, TaskFactory? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null) + { + var taskFactory = factory ?? Task.Factory; + + return taskFactory.FromAsync( + BeginUploadFile(input, path, canOverride, asyncCallback: null, state: null, uploadCallback), + EndUploadFile, + creationOptions, + scheduler ?? taskFactory.Scheduler ?? TaskScheduler.Current); + } + /// /// Begins an asynchronous uploading the stream into remote file. /// @@ -2167,6 +2224,31 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asynchResult: null); } + /// + /// Asynchronously synchronizes the directories. + /// + /// The source path. + /// The destination path. + /// The search pattern. + /// The TaskFactory used to create the Task. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// + /// A list of uploaded files. + /// + public Task> SynchronizeDirectoriesAsync(string sourcePath, string destinationPath, string searchPattern, TaskFactory>? factory = null, TaskCreationOptions creationOptions = default, TaskScheduler? scheduler = null) + { + var taskFactory = factory ?? Task>.Factory; + + return taskFactory.FromAsync( + BeginSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncCallback: null, state: null), + EndSynchronizeDirectories, + creationOptions, + scheduler ?? taskFactory?.Scheduler ?? TaskScheduler.Current); + } + /// /// Begins the synchronize directories. /// diff --git a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs index ec9fb8c76..0437a67af 100644 --- a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs +++ b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs @@ -123,7 +123,9 @@ public async Task Test_Get_FileAsync() { sftp.Connect(); +#pragma warning disable S6966 sftp.UploadFile(new MemoryStream(), "abc.txt"); +#pragma warning restore S6966 var file = await sftp.GetAsync("abc.txt", default).ConfigureAwait(false); @@ -157,7 +159,9 @@ public async Task Test_Get_International_FileAsync() { sftp.Connect(); +#pragma warning disable S6966 sftp.UploadFile(new MemoryStream(), "test-üöä-"); +#pragma warning restore S6966 var file = await sftp.GetAsync("test-üöä-", default).ConfigureAwait(false); diff --git a/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs index 951fdf666..385f08061 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -65,7 +65,7 @@ public async Task Create_directory_with_contents_and_list_it_async() // Upload file and check if it exists using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); - _sftpClient.UploadFile(fileStream, testFilePath); + await _sftpClient.UploadFileAsync(fileStream, testFilePath); Assert.IsTrue(await _sftpClient.ExistsAsync(testFilePath)); // Check if ListDirectory works @@ -124,7 +124,7 @@ public async Task Create_directory_with_contents_and_delete_contents_then_direct // Upload file and check if it exists using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); - _sftpClient.UploadFile(fileStream, testFilePath); + await _sftpClient.UploadFileAsync(fileStream, testFilePath); Assert.IsTrue(await _sftpClient.ExistsAsync(testFilePath).ConfigureAwait(false)); await _sftpClient.DeleteFileAsync(testFilePath, CancellationToken.None).ConfigureAwait(false); @@ -159,7 +159,7 @@ public async Task Create_file_and_delete_using_DeleteAsync() // Upload file and check if it exists using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); - _sftpClient.UploadFile(fileStream, testFileName); + await _sftpClient.UploadFileAsync(fileStream, testFileName); Assert.IsTrue(await _sftpClient.ExistsAsync(testFileName).ConfigureAwait(false)); await _sftpClient.DeleteAsync(testFileName, CancellationToken.None).ConfigureAwait(false); diff --git a/test/Renci.SshNet.IntegrationTests/SftpTests.cs b/test/Renci.SshNet.IntegrationTests/SftpTests.cs index f03ee6a2c..955cb7589 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -4114,9 +4114,9 @@ public async Task Sftp_ChangeDirectory_DirectoryExistsAsync() using (var uploadStream = CreateMemoryStream(100)) { uploadStream.Position = 0; - +#pragma warning disable S6966 client.UploadFile(uploadStream, "gert.txt"); - +#pragma warning restore S6966 uploadStream.Position = 0; using (var downloadStream = client.OpenRead(remoteDirectory + "/gert.txt"))