From 31804794862a9bb73f40332e861fc2aae408083b Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 8 Aug 2018 13:09:12 +0300 Subject: [PATCH 1/2] Implemented FtpSource based on FluentFtp library --- .../NAppUpdate.Framework.csproj | 6 ++ src/NAppUpdate.Framework/Sources/FtpSource.cs | 83 +++++++++++++++++++ src/NAppUpdate.Framework/packages.config | 4 + 3 files changed, 93 insertions(+) create mode 100644 src/NAppUpdate.Framework/Sources/FtpSource.cs create mode 100644 src/NAppUpdate.Framework/packages.config diff --git a/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj b/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj index 2fb2acd1..32e5cf34 100644 --- a/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj +++ b/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj @@ -68,7 +68,11 @@ v4.0 + + ..\..\..\packages\FluentFTP.19.2.2\lib\net35\FluentFTP.dll + + @@ -97,6 +101,7 @@ True Resources.resx + @@ -123,6 +128,7 @@ Designer + diff --git a/src/NAppUpdate.Framework/Sources/FtpSource.cs b/src/NAppUpdate.Framework/Sources/FtpSource.cs new file mode 100644 index 00000000..312d7d5d --- /dev/null +++ b/src/NAppUpdate.Framework/Sources/FtpSource.cs @@ -0,0 +1,83 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Web.UI.WebControls; +using FluentFTP; +using NAppUpdate.Framework.Common; + +namespace NAppUpdate.Framework.Sources +{ + public class FtpSource : IUpdateSource + { + public string HostUrl { get; set; } + + private string feedPath { get; } + + private string feedBasePath => Path.GetDirectoryName(feedPath); + + private FtpClient ftpClient { get; } + + /// Url of ftp server ("ftp://somesite.com/") + /// Local ftp path to feed ("/path/to/feed.xml") + /// Login of ftp user, if needed + /// Password of ftp user, if needed + public FtpSource(string hostUrl, string feedPath, string login = null, string password = null) + { + ftpClient = new FtpClient(hostUrl); + HostUrl = hostUrl; + this.feedPath = feedPath; + + if (login != null && password != null) + { + ftpClient.Credentials = new NetworkCredential(login, password); + } + } + + private void TryConnectToHost() + { + try + { + ftpClient.Connect(); + } + catch(Exception e) + { + throw new WebException($"Failed to connect to host: {HostUrl}. Error message: {e.Message}"); + } + } + + #region IUpdateSource Members + + public String GetUpdatesFeed() + { + TryConnectToHost(); + + string data = null; + + using (var fileStream = ftpClient.OpenRead(feedPath, FtpDataType.ASCII, true)) + { + using (var streamReader = new StreamReader(fileStream)) + { + data = streamReader.ReadToEnd(); + } + } + + // Remove byteorder mark if necessary + int indexTagOpening = data.IndexOf('<'); + if (indexTagOpening > 0) + { + data = data.Substring(indexTagOpening); + } + + return data; + } + + public Boolean GetData(String filePath, String basePath, Action onProgress, ref String tempLocation) + { + ftpClient.DownloadFile(tempLocation, Path.Combine(feedBasePath, filePath)); + return true; + } + + #endregion + } +} diff --git a/src/NAppUpdate.Framework/packages.config b/src/NAppUpdate.Framework/packages.config new file mode 100644 index 00000000..53dd6e94 --- /dev/null +++ b/src/NAppUpdate.Framework/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 9ee5a50b1e03e7b36b2a51d49a9291c78f3f6a20 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 10 Aug 2018 14:48:28 +0300 Subject: [PATCH 2/2] Additional dependency FluentFTP replaced by CLR's FTP client implementation --- .../NAppUpdate.Framework.csproj | 4 - src/NAppUpdate.Framework/Sources/FtpSource.cs | 87 +++++++++++++++---- src/NAppUpdate.Framework/packages.config | 4 - 3 files changed, 70 insertions(+), 25 deletions(-) delete mode 100644 src/NAppUpdate.Framework/packages.config diff --git a/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj b/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj index 32e5cf34..5c06df87 100644 --- a/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj +++ b/src/NAppUpdate.Framework/NAppUpdate.Framework.csproj @@ -68,9 +68,6 @@ v4.0 - - ..\..\..\packages\FluentFTP.19.2.2\lib\net35\FluentFTP.dll - @@ -128,7 +125,6 @@ Designer - diff --git a/src/NAppUpdate.Framework/Sources/FtpSource.cs b/src/NAppUpdate.Framework/Sources/FtpSource.cs index 312d7d5d..0fead11f 100644 --- a/src/NAppUpdate.Framework/Sources/FtpSource.cs +++ b/src/NAppUpdate.Framework/Sources/FtpSource.cs @@ -3,7 +3,6 @@ using System.Net; using System.Text; using System.Web.UI.WebControls; -using FluentFTP; using NAppUpdate.Framework.Common; namespace NAppUpdate.Framework.Sources @@ -16,7 +15,9 @@ public class FtpSource : IUpdateSource private string feedBasePath => Path.GetDirectoryName(feedPath); - private FtpClient ftpClient { get; } + private int bufferSize = 2048; + + private NetworkCredential credentials { get; } /// Url of ftp server ("ftp://somesite.com/") /// Local ftp path to feed ("/path/to/feed.xml") @@ -24,43 +25,94 @@ public class FtpSource : IUpdateSource /// Password of ftp user, if needed public FtpSource(string hostUrl, string feedPath, string login = null, string password = null) { - ftpClient = new FtpClient(hostUrl); HostUrl = hostUrl; this.feedPath = feedPath; if (login != null && password != null) { - ftpClient.Credentials = new NetworkCredential(login, password); + credentials = new NetworkCredential(login, password); } } private void TryConnectToHost() { + var ftpConnRequest = (FtpWebRequest)FtpWebRequest.Create(HostUrl); + ftpConnRequest.Method = WebRequestMethods.Ftp.ListDirectory; + ftpConnRequest.UsePassive = true; + ftpConnRequest.KeepAlive = false; + ftpConnRequest.Credentials = credentials; + try { - ftpClient.Connect(); + ftpConnRequest.GetResponse(); } - catch(Exception e) + catch (WebException e) { throw new WebException($"Failed to connect to host: {HostUrl}. Error message: {e.Message}"); } } + /// + /// Downloads remote file from ftp + /// + /// Path to file on server (example: "/path/to/file.txt") + /// Path on local machine, where file should be saved (if not provided, Temp folder will be used) + /// Path to saved on disk file (Temp folder) + private string DownloadRemoteFile(string path, string localPath = null) + { + try + { + string pathToSave = localPath ?? Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + // Create an FTP Request + var ftpRequest = + (FtpWebRequest)FtpWebRequest.Create( + $@"{HostUrl}{(HostUrl.EndsWith("/") ? string.Empty : "/")}{path}"); + ftpRequest.Credentials = credentials; + // Set options + ftpRequest.UseBinary = true; + ftpRequest.UsePassive = true; + ftpRequest.KeepAlive = true; + // Specify the Type of FTP Request + ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile; + + // Establish Return Communication with the FTP Server + using (var ftpResponse = (FtpWebResponse)ftpRequest.GetResponse()) + { + // Get the FTP Server's Response Stream + using (var ftpStream = ftpResponse.GetResponseStream()) + { + // Save data on disk + using (var localFileStream = new FileStream(pathToSave, FileMode.Create)) + { + byte[] byteBuffer = new byte[bufferSize]; + int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize); + + while (bytesRead > 0) + { + localFileStream.Write(byteBuffer, 0, bytesRead); + bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize); + } + } + } + } + + return pathToSave; + } + catch (Exception ex) + { + throw new WebException( + $"An error occurred when trying to download file {Path.GetFileName(path)}: {ex.Message}"); + } + } + #region IUpdateSource Members public String GetUpdatesFeed() { TryConnectToHost(); - string data = null; - - using (var fileStream = ftpClient.OpenRead(feedPath, FtpDataType.ASCII, true)) - { - using (var streamReader = new StreamReader(fileStream)) - { - data = streamReader.ReadToEnd(); - } - } + string feedFilePath = DownloadRemoteFile(feedPath); + string data = File.ReadAllText(feedFilePath); // Remove byteorder mark if necessary int indexTagOpening = data.IndexOf('<'); @@ -72,9 +124,10 @@ public String GetUpdatesFeed() return data; } - public Boolean GetData(String filePath, String basePath, Action onProgress, ref String tempLocation) + public Boolean GetData(String filePath, String basePath, Action onProgress, + ref String tempLocation) { - ftpClient.DownloadFile(tempLocation, Path.Combine(feedBasePath, filePath)); + DownloadRemoteFile(Path.Combine(feedBasePath, filePath), tempLocation); return true; } diff --git a/src/NAppUpdate.Framework/packages.config b/src/NAppUpdate.Framework/packages.config deleted file mode 100644 index 53dd6e94..00000000 --- a/src/NAppUpdate.Framework/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file