From a73f47497e83ebddc7dc6b8359cc9b8a97f833e3 Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Tue, 16 May 2023 11:17:08 +0300 Subject: [PATCH 1/3] Added new result attribute for destination file paths --- Frends.SFTP.DownloadFiles/CHANGELOG.md | 4 + .../MacroTests.cs | 5 +- .../TransferTests.cs | 2 + .../Definitions/FileTransferResult.cs | 2 + .../Definitions/FileTransporter.cs | 1 + .../Definitions/Result.cs | 16 +- .../Definitions/SingleFileTransfer.cs | 1088 +++++++++-------- .../Definitions/SingleFileTransferResult.cs | 2 + .../Frends.SFTP.DownloadFiles.csproj | 2 +- 9 files changed, 575 insertions(+), 547 deletions(-) diff --git a/Frends.SFTP.DownloadFiles/CHANGELOG.md b/Frends.SFTP.DownloadFiles/CHANGELOG.md index 8f92121..a63300e 100644 --- a/Frends.SFTP.DownloadFiles/CHANGELOG.md +++ b/Frends.SFTP.DownloadFiles/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [2.5.5] - 2023-05-16 +### Added +- Added new result attribute TransferredDestinationFilePaths list consisting of the destination file paths. + ## [2.5.4] - 2023-02-14 ### Added - Re-enabled key exchange algorithms 'curve25519-sha256' and 'curve25519-sha256@libssh.org'. diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/MacroTests.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/MacroTests.cs index d581933..705e3bd 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/MacroTests.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/MacroTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System.IO; using System; +using System.Linq; using System.Threading; using Frends.SFTP.DownloadFiles.Definitions; @@ -22,7 +23,9 @@ public void DownloadFiles_TestUsingMacros() var result = SFTP.DownloadFiles(_source, destination, _connection, _options, _info, new CancellationToken()); Assert.IsTrue(result.Success); var date = DateTime.Now; - Assert.IsTrue(File.Exists(Path.Combine(_destWorkDir, "SFTPDownloadTestFile1" + date.ToString(@"yyyy-MM-dd") + ".txt"))); + var file = Path.Combine(_destWorkDir, "SFTPDownloadTestFile1" + date.ToString(@"yyyy-MM-dd") + ".txt"); + Assert.AreEqual(file, result.TransferredDestinationFilePaths.ToList().FirstOrDefault()); + Assert.IsTrue(File.Exists(file)); } [Test] diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/TransferTests.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/TransferTests.cs index 7322db0..6f98ddd 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/TransferTests.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.Tests/TransferTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using System; using System.IO; +using System.Linq; using System.Threading; using System.Collections.Generic; using Frends.SFTP.DownloadFiles.Definitions; @@ -16,6 +17,7 @@ public void DownloadFiles_TestSimpleTransfer() var result = SFTP.DownloadFiles(_source, _destination, _connection, _options, _info, new CancellationToken()); Assert.IsTrue(result.Success); Assert.AreEqual(1, result.SuccessfulTransferCount); + Assert.AreEqual(Path.Combine(_destination.Directory, _source.FileName), result.TransferredDestinationFilePaths.ToList().FirstOrDefault()); } [Test] diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransferResult.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransferResult.cs index 1e0c819..4b81239 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransferResult.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransferResult.cs @@ -18,6 +18,8 @@ internal class FileTransferResult public IEnumerable TransferredFilePaths { get; set; } + public IEnumerable TransferredDestinationFilePaths { get; set; } + public IDictionary OperationsLog { get; set; } } diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs index 6ef5474..563c9a8 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs @@ -488,6 +488,7 @@ private FileTransferResult FormResultFromSingleTransferResults(List r.TransferredFile ?? "--unknown--").ToList(), TransferErrors = transferErrors, TransferredFilePaths = transferredFileResults.Select(r => r.TransferredFilePath ?? "--unknown--").ToList(), + TransferredDestinationFilePaths = transferredFileResults.Select(s => s.DestinationFilePath ?? "--unknown--").ToList(), OperationsLog = (singleResults.Any(x => !x.EnableOperationsLog)) ? null : new Dictionary() }; } diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/Result.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/Result.cs index b5b29c0..fa526a1 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/Result.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/Result.cs @@ -77,13 +77,24 @@ public class Result /// /// /// [ - /// "C:\\test\\test.txt", - /// "C:\\test\\test2.txt" + /// "/Upload/upload/test.txt", + /// "/Upload/upload/test2.txt" /// ] /// /// public IEnumerable TransferredFilePaths { get; private set; } + /// + /// List of destination file paths of the transferred files. + /// + /// + /// [ + /// "C:\\test\\test.txt", + /// "C:\\test\\test2.txt" + /// ] + /// + public IEnumerable TransferredDestinationFilePaths { get; private set; } + /// /// Operations logs for the transfer. /// @@ -107,6 +118,7 @@ internal Result(FileTransferResult result) TransferredFileNames = result.TransferredFileNames; TransferErrors = result.TransferErrors; TransferredFilePaths = result.TransferredFilePaths; + TransferredDestinationFilePaths = result.TransferredDestinationFilePaths; OperationsLog = result.OperationsLog; } } diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransfer.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransfer.cs index 6acd057..5b626f4 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransfer.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransfer.cs @@ -1,546 +1,548 @@ -using System.Text; -using Renci.SshNet; -using Renci.SshNet.Sftp; - -namespace Frends.SFTP.DownloadFiles.Definitions; - -internal class SingleFileTransfer -{ - private readonly RenamingPolicy _renamingPolicy; - private readonly ISFTPLogger _logger; - private readonly SingleFileTransferResult _result; - - public SingleFileTransfer(FileItem file, BatchContext context, SftpClient client, RenamingPolicy renamingPolicy, ISFTPLogger logger) - { - _renamingPolicy = renamingPolicy; - _logger = logger; - - FileTransferStartTime = DateTime.UtcNow; - Client = client; - SourceFile = file; - WorkFile = file; - BatchContext = context; - - DestinationFileWithMacrosExpanded = Path.Combine( - renamingPolicy.ExpandDirectoryForMacros(context.Destination.Directory), - renamingPolicy.CreateRemoteFileName( - file.Name, - context.Destination.FileName)); - WorkFileInfo = new WorkFileInfo(file.Name, Path.GetFileName(DestinationFileWithMacrosExpanded), BatchContext.TempWorkDir); - - _result = new SingleFileTransferResult { Success = true }; - } - - public DateTime FileTransferStartTime { get; set; } - - public WorkFileInfo WorkFileInfo { get; set; } - - public FileItem WorkFile { get; set; } - - public SftpClient Client { get; set; } - - public FileItem SourceFile { get; set; } - - public FileItem DestinationFile { get; set; } - - public string DestinationFileWithMacrosExpanded { get; set; } - - private string SourceFileDuringTransfer { get; set; } - - public string DestinationFileDuringTransfer { get; set; } - - public BatchContext BatchContext { get; set; } - - /// - /// Transfer state for SFTP Logger - /// - public TransferState State { get; set; } - - internal SingleFileTransferResult TransferSingleFile() - { - try - { - _result.TransferredFile = SourceFile.Name; - _result.TransferredFilePath = SourceFile.FullPath; - - GetSourceFile(); - - ExecuteSourceOperationMoveOrRename(); - - if (DestinationFileExists(DestinationFileWithMacrosExpanded)) - { - DestinationFile = new FileItem(DestinationFileWithMacrosExpanded); - switch (BatchContext.Destination.Action) - { - case DestinationAction.Append: - AppendDestinationFile(); - break; - case DestinationAction.Overwrite: - PutDestinationFile(removeExisting: true); - break; - case DestinationAction.Error: - throw new DestinationFileExistsException(Path.GetFileName(DestinationFileWithMacrosExpanded)); - } - } - else PutDestinationFile(); - - if (BatchContext.Options.PreserveLastModified) RestoreModified(); - - ExecuteSourceOperationNothingOrDelete(); - - _logger.LogTransferSuccess(this, BatchContext); - CleanUpFiles(); - } - catch (Exception ex) - { - var sourceFileRestoreMessage = RestoreSourceFileAfterErrorIfItWasRenamed(); - HandleTransferError(ex, sourceFileRestoreMessage); - - var destinationFileRestoreMessage = RestoreDestinationFileAfterErrorIfItWasRenamed(); - if (!string.IsNullOrEmpty(destinationFileRestoreMessage)) - HandleTransferError(ex, destinationFileRestoreMessage); - } - return _result; - } - - private void GetSourceFile() - { - if (BatchContext.Options.RenameSourceFileBeforeTransfer) - RenameSourceFile(); - else - SourceFileDuringTransfer = SourceFile.FullPath; - - SetCurrentState(TransferState.GetFile, $"Downloading temporary source file {Path.GetFileName(SourceFileDuringTransfer)} to local temp folder {WorkFileInfo.WorkFileDir}"); - using (var fs = File.Open(Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)), FileMode.Create)) - { - Client.DownloadFile(SourceFileDuringTransfer, fs); - } - } - - private bool DestinationFileExists(string path) - { - SetCurrentState( - TransferState.CheckIfDestinationFileExists, - $"Checking if destination file {Path.GetFileName(path)} exists."); - var exists = File.Exists(path); - _logger.NotifyInformation(BatchContext, $"FILE EXISTS {path}: {exists}."); - - return exists; - } - - private void RenameSourceFile() - { - if (!string.IsNullOrEmpty(SourceFileDuringTransfer)) - { - Client.RenameFile(SourceFileDuringTransfer, SourceFile.FullPath); - return; - } - - var uniqueFileName = Util.CreateUniqueFileName(BatchContext.Options.SourceFileExtension); - var directory = Path.GetDirectoryName(SourceFile.FullPath); - - SourceFileDuringTransfer = (SourceFile.FullPath.Contains('/')) - ? Path.Combine(directory, uniqueFileName).Replace("\\", "/") - : Path.Combine(directory, uniqueFileName); - - SetCurrentState(TransferState.RenameSourceFileBeforeTransfer, $"Renaming source file {SourceFile.Name} to temporary file name {uniqueFileName} before transfer."); - - Client.RenameFile(SourceFile.FullPath, SourceFileDuringTransfer); - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Source file {SourceFile.Name} renamed to target {uniqueFileName}."); - } - - private void AppendDestinationFile() - { - var filePath = Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)); - Encoding encoding; - try - { - encoding = Util.GetEncoding(BatchContext.Destination.FileContentEncoding, BatchContext.Destination.FileContentEncodingInString, BatchContext.Destination.EnableBomForContent); - } - catch (Exception ex) - { - throw new Exception("Error in initializing file content encoding: ", ex); - } - - if (BatchContext.Options.RenameDestinationFileDuringTransfer) - RenameDestinationFile(); - - Append(GetSourceFileContent(filePath, BatchContext.Destination.AddNewLine, encoding), encoding); - - if (BatchContext.Options.RenameDestinationFileDuringTransfer) - RenameDestinationFile(); - } - - private void RenameDestinationFile() - { - if (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) - { - SetCurrentState(TransferState.RenameDestinationFile, $"Renaming temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} to target file {DestinationFile.Name}."); - File.Move(DestinationFileDuringTransfer, DestinationFile.FullPath); - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} renamed to target {DestinationFile.Name}."); - } - else - { - DestinationFileDuringTransfer = Path.Combine(Path.GetDirectoryName(DestinationFile.FullPath), Util.CreateUniqueFileName(BatchContext.Options.DestinationFileExtension)); - SetCurrentState(TransferState.RenameDestinationFile, $"Renaming destination file {DestinationFile.Name} to temporary file name {Path.GetFileName(DestinationFileDuringTransfer)} during transfer."); - File.Move(DestinationFile.FullPath, DestinationFileDuringTransfer); - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Destination file {DestinationFile.Name} renamed to target {Path.GetFileName(DestinationFileDuringTransfer)}."); - } - } - - private void Append(string content, Encoding encoding) - { - SetCurrentState( - TransferState.AppendToDestinationFile, - $"Appending file {Path.GetFileName(SourceFileDuringTransfer)} to existing file {DestinationFile.Name}."); - - // If destination rename during transfer is enabled, use that instead - var path = (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) - ? DestinationFileDuringTransfer - : DestinationFile.FullPath; - - File.AppendAllText(path, content, encoding); - _logger.NotifyInformation(BatchContext, $"FILE APPEND: Source file appended to target {DestinationFile.Name}."); - } - - private static string GetSourceFileContent(string filePath, bool addNewLine, Encoding encoding) - { - string content; - content = File.ReadAllText(filePath, encoding); - if (addNewLine) - content = Environment.NewLine + content; - return content; - - } - - /// - /// Downloads source file to local directory. Overwrites the destination file if enabled. - /// - /// - private void PutDestinationFile(bool removeExisting = false) - { - var doRename = BatchContext.Options.RenameDestinationFileDuringTransfer; - - DestinationFileDuringTransfer = doRename - ? Path.Combine(Path.GetDirectoryName(DestinationFileWithMacrosExpanded), Util.CreateUniqueFileName(BatchContext.Options.DestinationFileExtension)) - : DestinationFileWithMacrosExpanded; - - var helper = doRename ? "temporary " : string.Empty; - SetCurrentState( - TransferState.PutFile, - $"Downloading {helper}destination file {Path.GetFileName(DestinationFileDuringTransfer)}."); - - File.Copy(Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)), DestinationFileDuringTransfer, removeExisting); - - _logger.NotifyInformation(BatchContext, $"FILE COPY {SourceFileDuringTransfer} to {DestinationFileDuringTransfer}."); - - if (doRename) - { - if (removeExisting) - { - SetCurrentState( - TransferState.DeleteDestinationFile, - $"Deleting destination file {Path.GetFileName(DestinationFileWithMacrosExpanded)} that is to be overwritten."); - - File.Delete(DestinationFileWithMacrosExpanded); - _logger.NotifyInformation(BatchContext, $"FILE DELETE: Destination file {Path.GetFileName(DestinationFileWithMacrosExpanded)} deleted."); - } - - SetCurrentState( - TransferState.RenameDestinationFile, - $"Renaming temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} to target file {Path.GetFileName(DestinationFileWithMacrosExpanded)}."); - - File.Move(DestinationFileDuringTransfer, DestinationFileWithMacrosExpanded); - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} renamed to target {Path.GetFileName(DestinationFileWithMacrosExpanded)}."); - } - } - - /// - /// Restores the LastWriteTime stamp to the destination file. - /// - private void RestoreModified() - { +using System.Text; +using Renci.SshNet; +using Renci.SshNet.Sftp; + +namespace Frends.SFTP.DownloadFiles.Definitions; + +internal class SingleFileTransfer +{ + private readonly RenamingPolicy _renamingPolicy; + private readonly ISFTPLogger _logger; + private readonly SingleFileTransferResult _result; + + public SingleFileTransfer(FileItem file, BatchContext context, SftpClient client, RenamingPolicy renamingPolicy, ISFTPLogger logger) + { + _renamingPolicy = renamingPolicy; + _logger = logger; + + FileTransferStartTime = DateTime.UtcNow; + Client = client; + SourceFile = file; + WorkFile = file; + BatchContext = context; + + DestinationFileWithMacrosExpanded = Path.Combine( + renamingPolicy.ExpandDirectoryForMacros(context.Destination.Directory), + renamingPolicy.CreateRemoteFileName( + file.Name, + context.Destination.FileName)); + WorkFileInfo = new WorkFileInfo(file.Name, Path.GetFileName(DestinationFileWithMacrosExpanded), BatchContext.TempWorkDir); + + _result = new SingleFileTransferResult { Success = true }; + } + + public DateTime FileTransferStartTime { get; set; } + + public WorkFileInfo WorkFileInfo { get; set; } + + public FileItem WorkFile { get; set; } + + public SftpClient Client { get; set; } + + public FileItem SourceFile { get; set; } + + public FileItem DestinationFile { get; set; } + + public string DestinationFileWithMacrosExpanded { get; set; } + + private string SourceFileDuringTransfer { get; set; } + + public string DestinationFileDuringTransfer { get; set; } + + public BatchContext BatchContext { get; set; } + + /// + /// Transfer state for SFTP Logger + /// + public TransferState State { get; set; } + + internal SingleFileTransferResult TransferSingleFile() + { + try + { + _result.TransferredFile = SourceFile.Name; + _result.TransferredFilePath = SourceFile.FullPath; + + GetSourceFile(); + + ExecuteSourceOperationMoveOrRename(); + + if (DestinationFileExists(DestinationFileWithMacrosExpanded)) + { + DestinationFile = new FileItem(DestinationFileWithMacrosExpanded); + switch (BatchContext.Destination.Action) + { + case DestinationAction.Append: + AppendDestinationFile(); + break; + case DestinationAction.Overwrite: + PutDestinationFile(removeExisting: true); + break; + case DestinationAction.Error: + throw new DestinationFileExistsException(Path.GetFileName(DestinationFileWithMacrosExpanded)); + } + } + else PutDestinationFile(); + + if (BatchContext.Options.PreserveLastModified) RestoreModified(); + + ExecuteSourceOperationNothingOrDelete(); + + _logger.LogTransferSuccess(this, BatchContext); + CleanUpFiles(); + } + catch (Exception ex) + { + var sourceFileRestoreMessage = RestoreSourceFileAfterErrorIfItWasRenamed(); + HandleTransferError(ex, sourceFileRestoreMessage); + + var destinationFileRestoreMessage = RestoreDestinationFileAfterErrorIfItWasRenamed(); + if (!string.IsNullOrEmpty(destinationFileRestoreMessage)) + HandleTransferError(ex, destinationFileRestoreMessage); + } + + _result.DestinationFilePath = DestinationFileWithMacrosExpanded; + return _result; + } + + private void GetSourceFile() + { + if (BatchContext.Options.RenameSourceFileBeforeTransfer) + RenameSourceFile(); + else + SourceFileDuringTransfer = SourceFile.FullPath; + + SetCurrentState(TransferState.GetFile, $"Downloading temporary source file {Path.GetFileName(SourceFileDuringTransfer)} to local temp folder {WorkFileInfo.WorkFileDir}"); + using (var fs = File.Open(Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)), FileMode.Create)) + { + Client.DownloadFile(SourceFileDuringTransfer, fs); + } + } + + private bool DestinationFileExists(string path) + { + SetCurrentState( + TransferState.CheckIfDestinationFileExists, + $"Checking if destination file {Path.GetFileName(path)} exists."); + var exists = File.Exists(path); + _logger.NotifyInformation(BatchContext, $"FILE EXISTS {path}: {exists}."); + + return exists; + } + + private void RenameSourceFile() + { + if (!string.IsNullOrEmpty(SourceFileDuringTransfer)) + { + Client.RenameFile(SourceFileDuringTransfer, SourceFile.FullPath); + return; + } + + var uniqueFileName = Util.CreateUniqueFileName(BatchContext.Options.SourceFileExtension); + var directory = Path.GetDirectoryName(SourceFile.FullPath); + + SourceFileDuringTransfer = (SourceFile.FullPath.Contains('/')) + ? Path.Combine(directory, uniqueFileName).Replace("\\", "/") + : Path.Combine(directory, uniqueFileName); + + SetCurrentState(TransferState.RenameSourceFileBeforeTransfer, $"Renaming source file {SourceFile.Name} to temporary file name {uniqueFileName} before transfer."); + + Client.RenameFile(SourceFile.FullPath, SourceFileDuringTransfer); + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Source file {SourceFile.Name} renamed to target {uniqueFileName}."); + } + + private void AppendDestinationFile() + { + var filePath = Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)); + Encoding encoding; + try + { + encoding = Util.GetEncoding(BatchContext.Destination.FileContentEncoding, BatchContext.Destination.FileContentEncodingInString, BatchContext.Destination.EnableBomForContent); + } + catch (Exception ex) + { + throw new Exception("Error in initializing file content encoding: ", ex); + } + + if (BatchContext.Options.RenameDestinationFileDuringTransfer) + RenameDestinationFile(); + + Append(GetSourceFileContent(filePath, BatchContext.Destination.AddNewLine, encoding), encoding); + + if (BatchContext.Options.RenameDestinationFileDuringTransfer) + RenameDestinationFile(); + } + + private void RenameDestinationFile() + { + if (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) + { + SetCurrentState(TransferState.RenameDestinationFile, $"Renaming temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} to target file {DestinationFile.Name}."); + File.Move(DestinationFileDuringTransfer, DestinationFile.FullPath); + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} renamed to target {DestinationFile.Name}."); + } + else + { + DestinationFileDuringTransfer = Path.Combine(Path.GetDirectoryName(DestinationFile.FullPath), Util.CreateUniqueFileName(BatchContext.Options.DestinationFileExtension)); + SetCurrentState(TransferState.RenameDestinationFile, $"Renaming destination file {DestinationFile.Name} to temporary file name {Path.GetFileName(DestinationFileDuringTransfer)} during transfer."); + File.Move(DestinationFile.FullPath, DestinationFileDuringTransfer); + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Destination file {DestinationFile.Name} renamed to target {Path.GetFileName(DestinationFileDuringTransfer)}."); + } + } + + private void Append(string content, Encoding encoding) + { + SetCurrentState( + TransferState.AppendToDestinationFile, + $"Appending file {Path.GetFileName(SourceFileDuringTransfer)} to existing file {DestinationFile.Name}."); + + // If destination rename during transfer is enabled, use that instead + var path = (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) + ? DestinationFileDuringTransfer + : DestinationFile.FullPath; + + File.AppendAllText(path, content, encoding); + _logger.NotifyInformation(BatchContext, $"FILE APPEND: Source file appended to target {DestinationFile.Name}."); + } + + private static string GetSourceFileContent(string filePath, bool addNewLine, Encoding encoding) + { + string content; + content = File.ReadAllText(filePath, encoding); + if (addNewLine) + content = Environment.NewLine + content; + return content; + + } + + /// + /// Downloads source file to local directory. Overwrites the destination file if enabled. + /// + /// + private void PutDestinationFile(bool removeExisting = false) + { + var doRename = BatchContext.Options.RenameDestinationFileDuringTransfer; + + DestinationFileDuringTransfer = doRename + ? Path.Combine(Path.GetDirectoryName(DestinationFileWithMacrosExpanded), Util.CreateUniqueFileName(BatchContext.Options.DestinationFileExtension)) + : DestinationFileWithMacrosExpanded; + + var helper = doRename ? "temporary " : string.Empty; + SetCurrentState( + TransferState.PutFile, + $"Downloading {helper}destination file {Path.GetFileName(DestinationFileDuringTransfer)}."); + + File.Copy(Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)), DestinationFileDuringTransfer, removeExisting); + + _logger.NotifyInformation(BatchContext, $"FILE COPY {SourceFileDuringTransfer} to {DestinationFileDuringTransfer}."); + + if (doRename) + { + if (removeExisting) + { + SetCurrentState( + TransferState.DeleteDestinationFile, + $"Deleting destination file {Path.GetFileName(DestinationFileWithMacrosExpanded)} that is to be overwritten."); + + File.Delete(DestinationFileWithMacrosExpanded); + _logger.NotifyInformation(BatchContext, $"FILE DELETE: Destination file {Path.GetFileName(DestinationFileWithMacrosExpanded)} deleted."); + } + + SetCurrentState( + TransferState.RenameDestinationFile, + $"Renaming temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} to target file {Path.GetFileName(DestinationFileWithMacrosExpanded)}."); + + File.Move(DestinationFileDuringTransfer, DestinationFileWithMacrosExpanded); + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary destination file {Path.GetFileName(DestinationFileDuringTransfer)} renamed to target {Path.GetFileName(DestinationFileWithMacrosExpanded)}."); + } + } + + /// + /// Restores the LastWriteTime stamp to the destination file. + /// + private void RestoreModified() + { var date = SourceFile.Modified; SetCurrentState( - TransferState.RestoreModified, - $"Restoring the modified datetime of transferred file {Path.GetFileName(DestinationFileWithMacrosExpanded)}"); - File.SetLastWriteTime(DestinationFileWithMacrosExpanded, date); - _logger.NotifyInformation(BatchContext, $"SET MODIFIED {date.ToString("dd.MM.yyyy hh:mm:ss")}"); - } - - private void ExecuteSourceOperationNothingOrDelete() - { - var filePath = string.IsNullOrEmpty(SourceFileDuringTransfer) ? SourceFile.FullPath : SourceFileDuringTransfer; - switch (BatchContext.Source.Operation) - { - case SourceOperation.Delete: - SetCurrentState(TransferState.SourceOperationDelete, $"Deleting source file {Path.GetFileName(SourceFile.FullPath)} after transfer."); - Client.DeleteFile(filePath); - _logger.NotifyInformation(BatchContext, $"FILE DELETE: Source file {filePath} deleted."); - break; - - case SourceOperation.Nothing: - if (BatchContext.Options.RenameSourceFileBeforeTransfer) - { - SetCurrentState( - TransferState.RestoreSourceFile, - $"Restoring source file from temporary {Path.GetFileName(SourceFileDuringTransfer)} to the original name {Path.GetFileName(SourceFile.FullPath)}."); - Client.RenameFile(filePath, SourceFile.FullPath); - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary file {SourceFileDuringTransfer} restored to target {SourceFile.FullPath}."); - } - break; - } - } - - private void ExecuteSourceOperationMoveOrRename() - { - var filePath = string.IsNullOrEmpty(SourceFileDuringTransfer) ? SourceFile.FullPath : SourceFileDuringTransfer; - SftpFile file; - - if (BatchContext.Source.Operation == SourceOperation.Move) - { - file = Client.Get(filePath); - var moveToPath = _renamingPolicy.ExpandDirectoryForMacros(BatchContext.Source.DirectoryToMoveAfterTransfer); - SetCurrentState(TransferState.SourceOperationMove, $"Moving source file {SourceFile.FullPath} to {moveToPath}."); - if (!Client.Exists(moveToPath)) - { - var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be moved to given directory {moveToPath} because the directory didn't exist."; - _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in moving the source file.")); - _result.ErrorMessages.Add($"Failure in source operation: {msg}"); - } - var destFileName = Path.Combine(moveToPath, SourceFile.Name).Replace("\\", "/"); - if (Client.Exists(destFileName)) throw new Exception($"Failure in source operation: File {Path.GetFileName(destFileName)} exists in move to directory."); - - try { file.MoveTo(destFileName); } - catch (Exception ex) { throw new Exception($"Failure in source operation: {ex.GetType().Name}", ex); } - - if (!Client.Exists(destFileName)) throw new Exception($"Failure in source operation: Source file couldn't be moved to move to directory."); - - _logger.NotifyInformation(BatchContext, $"Source file {SourceFileDuringTransfer} moved to target {destFileName}."); - SourceFile = new FileItem(file); - - if (SourceFile.FullPath == null) - _logger.NotifyInformation(BatchContext, "Source end point returned null as the moved file. It should return the name of the moved file."); - } - else if (BatchContext.Source.Operation == SourceOperation.Rename) - { - file = Client.Get(filePath); - var path = string.IsNullOrEmpty(Path.GetDirectoryName(BatchContext.Source.FileNameAfterTransfer)) - ? Path.GetDirectoryName(SourceFile.FullPath).Replace("\\", "/") - : Path.GetDirectoryName(_renamingPolicy.CreateRemoteFileNameForRename(SourceFile.FullPath, BatchContext.Source.FileNameAfterTransfer)).Replace("\\", "/"); - - if (!Client.Exists(path)) - { - var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be moved to given directory {path} because the directory didn't exist."; - _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in moving the source file.")); - _result.ErrorMessages.Add($"Failure in source operation: {msg}"); - } - - var rename = Path.Combine(path, _renamingPolicy.CreateRemoteFileNameForRename(SourceFile.Name, Path.GetFileName(BatchContext.Source.FileNameAfterTransfer))).Replace("\\", "/"); - SetCurrentState(TransferState.SourceOperationRename, $"Renaming source file {SourceFile.FullPath} to {rename}."); - - try { file.MoveTo(rename); } - catch (Exception ex) { throw new Exception($"Failure in source operation: {ex.GetType().Name}", ex); } - - _logger.NotifyInformation(BatchContext, $"FILE RENAME: Source file {SourceFileDuringTransfer} renamed to target {rename}."); - - if (!Client.Exists(rename)) - { - var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be renamed to given name {Path.GetFileName(rename)}"; - _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in renaming source file.")); - _result.ErrorMessages.Add($"Failure in source operation: {msg}"); - } - - file = Client.Get(rename); - WorkFile = new FileItem(file); - - if (WorkFile.FullPath == null) - _logger.NotifyInformation(BatchContext, "Source end point returned null as the renamed file. It should return the name of the renamed file."); - } - } - - private void CleanUpFiles() - { - var temporarySourceFile = Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)); - SetCurrentState(TransferState.CleanUpFiles, $"Checking if temporary source file {temporarySourceFile} exists."); - var exists = !string.IsNullOrEmpty(temporarySourceFile) && File.Exists(temporarySourceFile); - _logger.NotifyInformation(BatchContext, $"FILE EXISTS {temporarySourceFile}: {exists}"); - if (exists) - { - SetCurrentState(TransferState.CleanUpFiles, $"Removing temporary source file {temporarySourceFile}."); - TryToRemoveLocalTempFile(temporarySourceFile); - } - - exists = !string.IsNullOrEmpty(DestinationFileDuringTransfer) && File.Exists(DestinationFileDuringTransfer) && BatchContext.Options.RenameDestinationFileDuringTransfer; - if (!exists) return; - SetCurrentState(TransferState.CleanUpFiles, $"Checking if temporary destination file {DestinationFileDuringTransfer} exists."); - _logger.NotifyInformation(BatchContext, $"FILE EXISTS {DestinationFileDuringTransfer}: {exists}"); - SetCurrentState(TransferState.CleanUpFiles, $"Removing temporary destination file {WorkFileInfo.WorkFilePath}."); - TryToRemoveDestinationTempFile(); - } - - private void HandleTransferError(Exception exception, string sourceFileRestoreMessage) - { - _result.Success = false; // the routine instance should be marked as failed if even one transfer fails - var errorMessage = $"Failure in {State}: File '{SourceFile.Name}' could not be transferred to '{BatchContext.Destination.Directory}'. Error: {exception.Message}."; - if (!string.IsNullOrEmpty(sourceFileRestoreMessage)) - errorMessage += " " + sourceFileRestoreMessage; - - _result.ErrorMessages.Add(errorMessage); - - _logger.LogTransferFailed(this, BatchContext, errorMessage, exception); - } - - private void TryToRemoveDestinationTempFile() - { - // If DestinationFileNameDuringTransfer is not set, - // the destination file already exists and DestinationFileExistAction=Error - if (string.IsNullOrEmpty(DestinationFileDuringTransfer)) return; - - // If RenameDestinationFileDuringTransfer=False, there is no temporary file that could be deleted - if (!BatchContext.Options.RenameDestinationFileDuringTransfer) return; - - try - { - SetCurrentState(TransferState.RemoveTemporaryDestinationFile, $"Removing temporary destination file {DestinationFileDuringTransfer}."); - File.Delete(DestinationFileDuringTransfer); - _logger.NotifyInformation(BatchContext, $"FILE DELETE: Temporary destination file {DestinationFileDuringTransfer} removed."); - } - catch (Exception ex) - { - _logger.NotifyError(BatchContext, $"Could not clean up temporary destination file '{DestinationFileDuringTransfer}': {ex.Message}.", ex); - } - } - - private void TryToRemoveLocalTempFile(string filePath) - { - try - { - if (FileDefinedAndExists(filePath)) - { - if ((File.GetAttributes(filePath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) - File.SetAttributes(filePath, FileAttributes.Normal); - File.Delete(filePath); - _logger.NotifyInformation(BatchContext, $"FILE DELETE: Temporary source file {filePath} removed."); - } - } - catch (Exception e) - { - _logger.NotifyError(BatchContext, $"Could not clean up local file '{Path.GetFileName(filePath)}'", e); - } - } - - private static bool FileDefinedAndExists(string path) - { - return !string.IsNullOrEmpty(path) && File.Exists(path); - } - - private string RestoreSourceFileAfterErrorIfItWasRenamed() - { - // Check that the connection is alive and if not try to connect again - if (!Client.IsConnected) - Client.Connect(); - - // restore the source file so we can retry the operations - // - but only if the source file has been renamed in the first place - if (!string.IsNullOrEmpty(SourceFileDuringTransfer)) - { - try - { - if (ShouldSourceFileBeRestoredOnError()) - { - if (BatchContext.Source.Operation == SourceOperation.Move) - RestoreSourceFileIfItWasMoved(); - if (!Path.GetFileName(WorkFile.Name).Equals(SourceFile.Name) || !SourceFileDuringTransfer.Equals(SourceFile.FullPath)) - Client.RenameFile(SourceFileDuringTransfer, SourceFile.FullPath); - return "[Source file restored.]"; - } - } - catch (Exception ex) - { - var message = $"Could not restore original source file '{Path.GetFileName(SourceFile.FullPath)}' from temporary file '{Path.GetFileName(SourceFileDuringTransfer)}'. Error: {ex.Message}."; - - _logger.NotifyError(BatchContext, message, ex); - return $"[{message}]"; - } - } - - return string.Empty; - } - - private void RestoreSourceFileIfItWasMoved() - { - var filePath = _renamingPolicy.ExpandDirectoryForMacros(BatchContext.Source.DirectoryToMoveAfterTransfer); - - var destFileName = Path.Combine(filePath, SourceFile.Name); - destFileName = (filePath.Contains('/')) ? destFileName.Replace("\\", "/") : destFileName; - - if (!Client.Exists(destFileName)) return; - - var file = Client.Get(destFileName); - - var restorePath = Path.Combine(BatchContext.Source.Directory, SourceFile.Name); - restorePath = (BatchContext.Source.Directory.Contains('/')) ? restorePath.Replace("\\", "/") : restorePath; - - file.MoveTo(restorePath); - - var path = file.FullName; - - if (!Client.Exists(path)) throw new ArgumentException("Failure in restoring moved source file."); - } - - private string RestoreDestinationFileAfterErrorIfItWasRenamed() - { - if (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) - { - try - { - if (BatchContext.Options.RenameDestinationFileDuringTransfer) - { - File.Move(DestinationFileDuringTransfer, DestinationFileWithMacrosExpanded); - return string.Empty; - } - } - catch (Exception ex) - { + TransferState.RestoreModified, + $"Restoring the modified datetime of transferred file {Path.GetFileName(DestinationFileWithMacrosExpanded)}"); + File.SetLastWriteTime(DestinationFileWithMacrosExpanded, date); + _logger.NotifyInformation(BatchContext, $"SET MODIFIED {date.ToString("dd.MM.yyyy hh:mm:ss")}"); + } + + private void ExecuteSourceOperationNothingOrDelete() + { + var filePath = string.IsNullOrEmpty(SourceFileDuringTransfer) ? SourceFile.FullPath : SourceFileDuringTransfer; + switch (BatchContext.Source.Operation) + { + case SourceOperation.Delete: + SetCurrentState(TransferState.SourceOperationDelete, $"Deleting source file {Path.GetFileName(SourceFile.FullPath)} after transfer."); + Client.DeleteFile(filePath); + _logger.NotifyInformation(BatchContext, $"FILE DELETE: Source file {filePath} deleted."); + break; + + case SourceOperation.Nothing: + if (BatchContext.Options.RenameSourceFileBeforeTransfer) + { + SetCurrentState( + TransferState.RestoreSourceFile, + $"Restoring source file from temporary {Path.GetFileName(SourceFileDuringTransfer)} to the original name {Path.GetFileName(SourceFile.FullPath)}."); + Client.RenameFile(filePath, SourceFile.FullPath); + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Temporary file {SourceFileDuringTransfer} restored to target {SourceFile.FullPath}."); + } + break; + } + } + + private void ExecuteSourceOperationMoveOrRename() + { + var filePath = string.IsNullOrEmpty(SourceFileDuringTransfer) ? SourceFile.FullPath : SourceFileDuringTransfer; + SftpFile file; + + if (BatchContext.Source.Operation == SourceOperation.Move) + { + file = Client.Get(filePath); + var moveToPath = _renamingPolicy.ExpandDirectoryForMacros(BatchContext.Source.DirectoryToMoveAfterTransfer); + SetCurrentState(TransferState.SourceOperationMove, $"Moving source file {SourceFile.FullPath} to {moveToPath}."); + if (!Client.Exists(moveToPath)) + { + var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be moved to given directory {moveToPath} because the directory didn't exist."; + _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in moving the source file.")); + _result.ErrorMessages.Add($"Failure in source operation: {msg}"); + } + var destFileName = Path.Combine(moveToPath, SourceFile.Name).Replace("\\", "/"); + if (Client.Exists(destFileName)) throw new Exception($"Failure in source operation: File {Path.GetFileName(destFileName)} exists in move to directory."); + + try { file.MoveTo(destFileName); } + catch (Exception ex) { throw new Exception($"Failure in source operation: {ex.GetType().Name}", ex); } + + if (!Client.Exists(destFileName)) throw new Exception($"Failure in source operation: Source file couldn't be moved to move to directory."); + + _logger.NotifyInformation(BatchContext, $"Source file {SourceFileDuringTransfer} moved to target {destFileName}."); + SourceFile = new FileItem(file); + + if (SourceFile.FullPath == null) + _logger.NotifyInformation(BatchContext, "Source end point returned null as the moved file. It should return the name of the moved file."); + } + else if (BatchContext.Source.Operation == SourceOperation.Rename) + { + file = Client.Get(filePath); + var path = string.IsNullOrEmpty(Path.GetDirectoryName(BatchContext.Source.FileNameAfterTransfer)) + ? Path.GetDirectoryName(SourceFile.FullPath).Replace("\\", "/") + : Path.GetDirectoryName(_renamingPolicy.CreateRemoteFileNameForRename(SourceFile.FullPath, BatchContext.Source.FileNameAfterTransfer)).Replace("\\", "/"); + + if (!Client.Exists(path)) + { + var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be moved to given directory {path} because the directory didn't exist."; + _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in moving the source file.")); + _result.ErrorMessages.Add($"Failure in source operation: {msg}"); + } + + var rename = Path.Combine(path, _renamingPolicy.CreateRemoteFileNameForRename(SourceFile.Name, Path.GetFileName(BatchContext.Source.FileNameAfterTransfer))).Replace("\\", "/"); + SetCurrentState(TransferState.SourceOperationRename, $"Renaming source file {SourceFile.FullPath} to {rename}."); + + try { file.MoveTo(rename); } + catch (Exception ex) { throw new Exception($"Failure in source operation: {ex.GetType().Name}", ex); } + + _logger.NotifyInformation(BatchContext, $"FILE RENAME: Source file {SourceFileDuringTransfer} renamed to target {rename}."); + + if (!Client.Exists(rename)) + { + var msg = $"Operation failed: Source file {SourceFile.Name} couldn't be renamed to given name {Path.GetFileName(rename)}"; + _logger.NotifyError(BatchContext, msg, new ArgumentException("Failure in renaming source file.")); + _result.ErrorMessages.Add($"Failure in source operation: {msg}"); + } + + file = Client.Get(rename); + WorkFile = new FileItem(file); + + if (WorkFile.FullPath == null) + _logger.NotifyInformation(BatchContext, "Source end point returned null as the renamed file. It should return the name of the renamed file."); + } + } + + private void CleanUpFiles() + { + var temporarySourceFile = Path.Combine(WorkFileInfo.WorkFileDir, Path.GetFileName(SourceFileDuringTransfer)); + SetCurrentState(TransferState.CleanUpFiles, $"Checking if temporary source file {temporarySourceFile} exists."); + var exists = !string.IsNullOrEmpty(temporarySourceFile) && File.Exists(temporarySourceFile); + _logger.NotifyInformation(BatchContext, $"FILE EXISTS {temporarySourceFile}: {exists}"); + if (exists) + { + SetCurrentState(TransferState.CleanUpFiles, $"Removing temporary source file {temporarySourceFile}."); + TryToRemoveLocalTempFile(temporarySourceFile); + } + + exists = !string.IsNullOrEmpty(DestinationFileDuringTransfer) && File.Exists(DestinationFileDuringTransfer) && BatchContext.Options.RenameDestinationFileDuringTransfer; + if (!exists) return; + SetCurrentState(TransferState.CleanUpFiles, $"Checking if temporary destination file {DestinationFileDuringTransfer} exists."); + _logger.NotifyInformation(BatchContext, $"FILE EXISTS {DestinationFileDuringTransfer}: {exists}"); + SetCurrentState(TransferState.CleanUpFiles, $"Removing temporary destination file {WorkFileInfo.WorkFilePath}."); + TryToRemoveDestinationTempFile(); + } + + private void HandleTransferError(Exception exception, string sourceFileRestoreMessage) + { + _result.Success = false; // the routine instance should be marked as failed if even one transfer fails + var errorMessage = $"Failure in {State}: File '{SourceFile.Name}' could not be transferred to '{BatchContext.Destination.Directory}'. Error: {exception.Message}."; + if (!string.IsNullOrEmpty(sourceFileRestoreMessage)) + errorMessage += " " + sourceFileRestoreMessage; + + _result.ErrorMessages.Add(errorMessage); + + _logger.LogTransferFailed(this, BatchContext, errorMessage, exception); + } + + private void TryToRemoveDestinationTempFile() + { + // If DestinationFileNameDuringTransfer is not set, + // the destination file already exists and DestinationFileExistAction=Error + if (string.IsNullOrEmpty(DestinationFileDuringTransfer)) return; + + // If RenameDestinationFileDuringTransfer=False, there is no temporary file that could be deleted + if (!BatchContext.Options.RenameDestinationFileDuringTransfer) return; + + try + { + SetCurrentState(TransferState.RemoveTemporaryDestinationFile, $"Removing temporary destination file {DestinationFileDuringTransfer}."); + File.Delete(DestinationFileDuringTransfer); + _logger.NotifyInformation(BatchContext, $"FILE DELETE: Temporary destination file {DestinationFileDuringTransfer} removed."); + } + catch (Exception ex) + { + _logger.NotifyError(BatchContext, $"Could not clean up temporary destination file '{DestinationFileDuringTransfer}': {ex.Message}.", ex); + } + } + + private void TryToRemoveLocalTempFile(string filePath) + { + try + { + if (FileDefinedAndExists(filePath)) + { + if ((File.GetAttributes(filePath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) + File.SetAttributes(filePath, FileAttributes.Normal); + File.Delete(filePath); + _logger.NotifyInformation(BatchContext, $"FILE DELETE: Temporary source file {filePath} removed."); + } + } + catch (Exception e) + { + _logger.NotifyError(BatchContext, $"Could not clean up local file '{Path.GetFileName(filePath)}'", e); + } + } + + private static bool FileDefinedAndExists(string path) + { + return !string.IsNullOrEmpty(path) && File.Exists(path); + } + + private string RestoreSourceFileAfterErrorIfItWasRenamed() + { + // Check that the connection is alive and if not try to connect again + if (!Client.IsConnected) + Client.Connect(); + + // restore the source file so we can retry the operations + // - but only if the source file has been renamed in the first place + if (!string.IsNullOrEmpty(SourceFileDuringTransfer)) + { + try + { + if (ShouldSourceFileBeRestoredOnError()) + { + if (BatchContext.Source.Operation == SourceOperation.Move) + RestoreSourceFileIfItWasMoved(); + if (!Path.GetFileName(WorkFile.Name).Equals(SourceFile.Name) || !SourceFileDuringTransfer.Equals(SourceFile.FullPath)) + Client.RenameFile(SourceFileDuringTransfer, SourceFile.FullPath); + return "[Source file restored.]"; + } + } + catch (Exception ex) + { + var message = $"Could not restore original source file '{Path.GetFileName(SourceFile.FullPath)}' from temporary file '{Path.GetFileName(SourceFileDuringTransfer)}'. Error: {ex.Message}."; + + _logger.NotifyError(BatchContext, message, ex); + return $"[{message}]"; + } + } + + return string.Empty; + } + + private void RestoreSourceFileIfItWasMoved() + { + var filePath = _renamingPolicy.ExpandDirectoryForMacros(BatchContext.Source.DirectoryToMoveAfterTransfer); + + var destFileName = Path.Combine(filePath, SourceFile.Name); + destFileName = (filePath.Contains('/')) ? destFileName.Replace("\\", "/") : destFileName; + + if (!Client.Exists(destFileName)) return; + + var file = Client.Get(destFileName); + + var restorePath = Path.Combine(BatchContext.Source.Directory, SourceFile.Name); + restorePath = (BatchContext.Source.Directory.Contains('/')) ? restorePath.Replace("\\", "/") : restorePath; + + file.MoveTo(restorePath); + + var path = file.FullName; + + if (!Client.Exists(path)) throw new ArgumentException("Failure in restoring moved source file."); + } + + private string RestoreDestinationFileAfterErrorIfItWasRenamed() + { + if (!string.IsNullOrEmpty(DestinationFileDuringTransfer)) + { + try + { + if (BatchContext.Options.RenameDestinationFileDuringTransfer) + { + File.Move(DestinationFileDuringTransfer, DestinationFileWithMacrosExpanded); + return string.Empty; + } + } + catch (Exception ex) + { var message = - $"Could not restore original destination file '{Path.GetFileName(DestinationFileWithMacrosExpanded)}' from temporary file '{Path.GetFileName(DestinationFileDuringTransfer)}'. Error: {ex.Message}."; - - _logger.NotifyError(BatchContext, message, ex); - return $"[{message}]"; - } - } - - return string.Empty; - } - - private bool ShouldSourceFileBeRestoredOnError() - { - if (BatchContext.Options.RenameSourceFileBeforeTransfer) return true; - - if (BatchContext.Source.Operation == SourceOperation.Move) return true; - - if (BatchContext.Source.Operation == SourceOperation.Rename) return true; - - return false; - } - - private void SetCurrentState(TransferState state, string msg) - { - State = state; - _logger.NotifyTrace($"{state}: {msg}"); - } - - /// - /// Exception class for more specific Exception name. - /// - public class DestinationFileExistsException : Exception - { - /// - /// Exception message. - /// - /// - public DestinationFileExistsException(string fileName) : base($"Unable to transfer file. Destination file already exists: {fileName}.") { } - } -} - + $"Could not restore original destination file '{Path.GetFileName(DestinationFileWithMacrosExpanded)}' from temporary file '{Path.GetFileName(DestinationFileDuringTransfer)}'. Error: {ex.Message}."; + + _logger.NotifyError(BatchContext, message, ex); + return $"[{message}]"; + } + } + + return string.Empty; + } + + private bool ShouldSourceFileBeRestoredOnError() + { + if (BatchContext.Options.RenameSourceFileBeforeTransfer) return true; + + if (BatchContext.Source.Operation == SourceOperation.Move) return true; + + if (BatchContext.Source.Operation == SourceOperation.Rename) return true; + + return false; + } + + private void SetCurrentState(TransferState state, string msg) + { + State = state; + _logger.NotifyTrace($"{state}: {msg}"); + } + + /// + /// Exception class for more specific Exception name. + /// + public class DestinationFileExistsException : Exception + { + /// + /// Exception message. + /// + /// + public DestinationFileExistsException(string fileName) : base($"Unable to transfer file. Destination file already exists: {fileName}.") { } + } +} + diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransferResult.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransferResult.cs index 0bd48b4..6fba4c2 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransferResult.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/SingleFileTransferResult.cs @@ -15,6 +15,8 @@ internal class SingleFileTransferResult internal string TransferredFilePath { get; set; } + internal string DestinationFilePath { get; set; } + internal bool EnableOperationsLog { get; set; } = true; internal SingleFileTransferResult() diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj index 13fb8c1..82feb94 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj @@ -8,7 +8,7 @@ Frends.SFTP.DownloadFiles Frends.SFTP.DownloadFiles - 2.5.4 + 2.5.5 Frends Frends Frends From ab869d0aca0be200add14bfcdf82858a05a27e49 Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Tue, 16 May 2023 11:50:24 +0300 Subject: [PATCH 2/3] Added the result attribute to FormFailedFileTransferResult method --- .../Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs index 563c9a8..9412eac 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Definitions/FileTransporter.cs @@ -461,6 +461,7 @@ private static FileTransferResult FormFailedFileTransferResult(string userResult TransferredFileNames = new List(), TransferErrors = new Dictionary>(), TransferredFilePaths = new List(), + TransferredDestinationFilePaths = new List(), OperationsLog = new Dictionary() }; } From 5e432ff33ec676688ba120ae66dc4c0824c3de47 Mon Sep 17 00:00:00 2001 From: Riku Virtanen Date: Wed, 17 May 2023 09:03:00 +0300 Subject: [PATCH 3/3] PR review changes - updated version number --- Frends.SFTP.DownloadFiles/CHANGELOG.md | 2 +- .../Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Frends.SFTP.DownloadFiles/CHANGELOG.md b/Frends.SFTP.DownloadFiles/CHANGELOG.md index a63300e..512adab 100644 --- a/Frends.SFTP.DownloadFiles/CHANGELOG.md +++ b/Frends.SFTP.DownloadFiles/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [2.5.5] - 2023-05-16 +## [2.6.0] - 2023-05-16 ### Added - Added new result attribute TransferredDestinationFilePaths list consisting of the destination file paths. diff --git a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj index 82feb94..80f4dd4 100644 --- a/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj +++ b/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles/Frends.SFTP.DownloadFiles.csproj @@ -8,7 +8,7 @@ Frends.SFTP.DownloadFiles Frends.SFTP.DownloadFiles - 2.5.5 + 2.6.0 Frends Frends Frends