FtpsClient.cs
|
using System; using System.IO; using System.Management.Automation; using System.Net; using FluentFTP; namespace PureStorage.AzureNative.Tools { // Public static helper class designed to be called from PowerShell public static class FtpsClient { // Verifies FTPS connectivity by establishing a TLS-secured FTP session and issuing a NOOP. public static void AssertFtpsServerConnectible(string ftpsServer, int ftpsPort, PSCredential ftpsCredential) { if (string.IsNullOrWhiteSpace(ftpsServer)) throw new ArgumentException("FTPS server is required", nameof(ftpsServer)); if (ftpsCredential == null) throw new ArgumentNullException(nameof(ftpsCredential)); using (var client = CreateClient(ftpsServer, ftpsPort, ftpsCredential)) { client.Connect(); // NOOP is a lightweight connectivity check client.Noop(); } } // Uploads a single local file to the FTPS server under /<remoteDir>/<filename> public static void SendFileToFtps(string ftpsServer, int ftpsPort, string localFilePath, PSCredential ftpsCredential, string remoteDir) { if (string.IsNullOrWhiteSpace(localFilePath)) throw new ArgumentException("Local file path is required", nameof(localFilePath)); if (!File.Exists(localFilePath)) throw new FileNotFoundException("Local file not found", localFilePath); using (var client = CreateClient(ftpsServer, ftpsPort, ftpsCredential)) { client.Connect(); if (!client.DirectoryExists(remoteDir)) { client.CreateDirectory(remoteDir, true); } var fileName = Path.GetFileName(localFilePath); var remotePath = $"{remoteDir}/{fileName}"; var status = client.UploadFile(localFilePath, remotePath, FtpRemoteExists.Overwrite, true, FtpVerify.None, p => { if (p.Progress >= 0) { Console.Write($"\rUploading: {p.Progress:0.0}%"); if (p.Progress >= 100.0) { Console.WriteLine(); } } }); if (status != FtpStatus.Success) { throw new InvalidOperationException($"FTPS upload failed with status: {status}"); } } } private static FtpClient CreateClient(string server, int port, PSCredential credential) { var netCred = credential.GetNetworkCredential(); var client = new FtpClient(server, netCred.UserName, netCred.Password); // Use FTPS (TLS). Default to Implicit on 990, else Explicit. client.Config.EncryptionMode = port == 990 ? FtpEncryptionMode.Implicit : FtpEncryptionMode.Explicit; client.Config.DataConnectionType = FtpDataConnectionType.AutoPassive; client.Config.ValidateAnyCertificate = false; // set to true if you need to skip certificate validation // Control connection timeouts client.Config.ConnectTimeout = 1000 * 30; // 30 seconds client.Config.ReadTimeout = 1000 * 60 * 5; // 5 minutes // Data connection timeouts tuned for large file transfers (multi‑GB) client.Config.DataConnectionConnectTimeout = 1000 * 60; // 60 seconds client.Config.DataConnectionReadTimeout = 1000 * 60 * 30; // 30 minutes // Socket / keep‑alive behavior client.Config.SocketKeepAlive = true; // File transfer behavior client.Config.TransferChunkSize = 256 * 1024; // 256 KB chunks client.Config.UploadDataType = FtpDataType.Binary; // ensure binary uploads client.Config.DownloadDataType = FtpDataType.Binary; // ensure binary downloads // Verification / retries used with FtpVerify.Retry client.Config.RetryAttempts = 3; return client; } } } |