[GH-ISSUE #696] FtpClient - Missing Objects/Methods #2491

Closed
opened 2026-03-01 17:20:58 +03:00 by kerem · 4 comments
Owner

Originally created by @GlacierDataworks on GitHub (Aug 4, 2024).
Original GitHub issue: https://github.com/1Remote/1Remote/issues/696

Originally assigned to: @VShawn on GitHub.

Describe the bug
FtpFileSystemObjectType does not exist.
FtpClient does not contain a definition for UploadFileAsync and DownloadFileAsync

To Reproduce
Steps to reproduce the behavior:

  1. Clone repo in Visual Studion 2022
  2. Restored NuGet packages
  3. Clean and Build solution.

Expected behavior
Build without error

Screenshots
image

Desktop (please complete the following information):

  • OS: Windows 11 Home edition
  • Visual Studio 2022 Version 17.10.4

Additional context
I think the FTPClient needs to be AsyncFtpClient instead of FtpClient, but that doesn't solve all the issues. I'm still working on how to make the async methods run.

Thanks

Originally created by @GlacierDataworks on GitHub (Aug 4, 2024). Original GitHub issue: https://github.com/1Remote/1Remote/issues/696 Originally assigned to: @VShawn on GitHub. **Describe the bug** FtpFileSystemObjectType does not exist. FtpClient does not contain a definition for UploadFileAsync and DownloadFileAsync **To Reproduce** Steps to reproduce the behavior: 1. Clone repo in Visual Studion 2022 2. Restored NuGet packages 3. Clean and Build solution. **Expected behavior** Build without error **Screenshots** ![image](https://github.com/user-attachments/assets/b7ae32ca-9e2b-406c-9ee3-57763f12ec58) **Desktop (please complete the following information):** - OS: Windows 11 Home edition - Visual Studio 2022 Version 17.10.4 **Additional context** I think the FTPClient needs to be AsyncFtpClient instead of FtpClient, but that doesn't solve all the issues. I'm still working on how to make the async methods run. Thanks
kerem 2026-03-01 17:20:58 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@GlacierDataworks commented on GitHub (Aug 4, 2024):

Changed _ftp type from FtpClient to AsyncFtpClient.
FtpFileSystemObjectType was renamed to FtpObjectType.
Removed Async from UploadFile and DownloadFile method names.
Now it builds just fine!

<!-- gh-comment-id:2267667381 --> @GlacierDataworks commented on GitHub (Aug 4, 2024): Changed _ftp type from FtpClient to AsyncFtpClient. FtpFileSystemObjectType was renamed to FtpObjectType. Removed Async from UploadFile and DownloadFile method names. Now it builds just fine!
Author
Owner

@VShawn commented on GitHub (Aug 9, 2024):

maybe you can make a PR for this :)

<!-- gh-comment-id:2277392349 --> @VShawn commented on GitHub (Aug 9, 2024): maybe you can make a PR for this :)
Author
Owner

@GlacierDataworks commented on GitHub (Aug 9, 2024):

I got a good build, but have not tested any of it yet. I'd hate to introduce other bugs because it wasn't tested.

<!-- gh-comment-id:2278405218 --> @GlacierDataworks commented on GitHub (Aug 9, 2024): I got a good build, but have not tested any of it yet. I'd hate to introduce other bugs because it wasn't tested.
Author
Owner

@GlacierDataworks commented on GitHub (Aug 9, 2024):

This is the file that changed.

Pam

From: VShawn @.>
Sent: Thursday, August 8, 2024 10:06 PM
To: 1Remote/1Remote @.
>
Cc: Glacier Dataworks @.>; Author @.>
Subject: Re: [1Remote/1Remote] FtpClient - Missing Objects/Methods (Issue #696)

maybe you can make a PR for this :)


Reply to this email directly, view it on GitHub https://github.com/1Remote/1Remote/issues/696#issuecomment-2277392349 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AUFZJQT4GRSXYMFWYHJQ75LZQRZ57AVCNFSM6AAAAABL7EIYSSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENZXGM4TEMZUHE .
You are receiving this because you authored the thread.Message ID: @.***>

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using FluentFTP;
using Shawn.Utils;

namespace _1RM.Model.Protocol.FileTransmit.Transmitters
{
public class TransmitterFtp : ITransmitter
{
public readonly string Hostname;
public readonly int Port;
public readonly string Username;
public readonly string Password;
private AsyncFtpClient? _ftp = null;

    public TransmitterFtp(string host, int port, string username, string password)
    {
        Hostname = host;
        Port = port;
        Username = username;
        Password = password;
        InitClient();
        CheckMeAlive();
    }

    ~TransmitterFtp()
    {
        _ftp?.Dispose();
        _timerKeepAlive.Stop();
    }

    public void Conn()
    {
        InitClient();
    }

    public bool IsConnected()
    {
        lock (this)
        {
            return _ftp?.IsConnected == true;
        }
    }

    public ITransmitter Clone()
    {
        return new TransmitterFtp(Hostname, Port, Username, Password);
    }

    public RemoteItem? Get(string path)
    {
        if (_ftp == null) return null;
        lock (this)
        {
            return Exists(path) ? FtpListItem2RemoteItem(_ftp.GetObjectInfo(path).Result) : null;
        }
    }

    public List<RemoteItem> ListDirectoryItems(string path)
    {
        if (_ftp == null) return new List<RemoteItem>();
        lock (this)
        {
            var ret = new List<RemoteItem>();
            IEnumerable<FtpListItem> items = _ftp.GetListing(path).Result;
            if (items == null ||
                !items.Any())
                return ret;

            items = items.OrderBy(x => x.Name);
            foreach (var item in items)
            {
                if (item.Name == "." || item.Name == "..")
                    continue;
                ret.Add(FtpListItem2RemoteItem(item));
            }
            return ret;
        }
    }

    public bool Exists(string path)
    {
        if (_ftp == null) return false;
        lock (this)
        {
            if (_ftp.FileExists(path).Result)
                return true;
            if (_ftp.DirectoryExists(path).Result)
                return true;
            return false;
        }
    }

    private RemoteItem FtpListItem2RemoteItem(FtpListItem item)
    {
        lock (this)
        {
            var fn = item.FullName;
            var newItem = new RemoteItem()
            {
                Icon = null,
                IsDirectory = item.Type == FtpObjectType.Directory,
                Name = item.Name,
                FullName = fn,
                LastUpdate = item.RawModified,
                ByteSize = (ulong)item.Size,
                IsSymlink = item.Type == FtpObjectType.Link,
            };
            if (item.Type == FtpObjectType.Directory)
            {
                if (newItem.IsSymlink)
                {
                    newItem.Icon = TransmitItemIconCache.GetDictIcon(Environment.GetFolderPath(Environment.SpecialFolder.Favorites));
                }
                else
                {
                    newItem.Icon = TransmitItemIconCache.GetDictIcon();
                }
                newItem.ByteSize = 0;
                newItem.FileType = "folder";
            }
            else
            {
                if (item.Name.IndexOf(".", StringComparison.Ordinal) > 0)
                {
                    var ext = item.Name.Substring(item.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLower();
                    newItem.FileType = ext;
                    newItem.Icon = TransmitItemIconCache.GetFileIcon(ext);
                }
                else
                {
                    newItem.Icon = TransmitItemIconCache.GetFileIcon();
                }
            }
            return newItem;
        }
    }

    public void Delete(string path)
    {
        if (_ftp == null) return;
        lock (this)
        {
            var item = Get(path);
            if (item != null)
            {
                if (item.IsDirectory)
                {
                    _ftp.DeleteDirectory(path);
                }
                else
                    _ftp.DeleteFile(path);
            }
        }
    }

    public void Delete(RemoteItem item)
    {
        lock (this)
        {
            Delete(item.FullName);
        }
    }

    public void CreateDirectory(string path)
    {
        if (_ftp == null) return;
        lock (this)
        {
            if (_ftp.DirectoryExists(path).Result == false)
                _ftp.CreateDirectory(path);
        }
    }

    public void RenameFile(string path, string newPath)
    {
        if (_ftp == null) return;
        if (path != newPath)
            if (Exists(path))
                lock (this)
                {
                    _ftp.Rename(path, newPath);
                }
    }

    public void UploadFile(string localFilePath, string saveToRemotePath, Action<ulong> writeCallBack, CancellationToken cancellationToken)
    {
        if (_ftp == null) return;
        var fi = new FileInfo(localFilePath);
        if (fi?.Exists != true)
            return;

        lock (this)
        {
            try
            {
                // check parent
                if (saveToRemotePath.LastIndexOf("/", StringComparison.Ordinal) > 0)
                {
                    var parent = saveToRemotePath.Substring(0,
                        saveToRemotePath.LastIndexOf("/", StringComparison.Ordinal));
                    if (_ftp.DirectoryExists(parent).Result == false)
                        _ftp.CreateDirectory(parent);
                }

                _ftp.UploadFile(localFilePath, saveToRemotePath, FtpRemoteExists.Overwrite, true, FtpVerify.Delete,
                    new Progress<FtpProgress>(progress =>
                    {
                        writeCallBack?.Invoke((ulong)progress.TransferredBytes);
                    }), cancellationToken).Wait(cancellationToken);
            }
            catch (Exception)
            {
                if (cancellationToken.IsCancellationRequested == false)
                    throw;
            }
        }
    }

    public void DownloadFile(string remoteFilePath, string saveToLocalPath, Action<ulong> readCallBack, CancellationToken cancellationToken)
    {
        if (_ftp == null) return;
        try
        {
            var t = _ftp.DownloadFile(saveToLocalPath, remoteFilePath, FtpLocalExists.Overwrite, FtpVerify.None,
                new Progress<FtpProgress>(progress =>
                {
                    readCallBack?.Invoke((ulong)progress.TransferredBytes);
                }), cancellationToken);
            t.Wait(cancellationToken);
        }
        catch (Exception)
        {
            if (cancellationToken.IsCancellationRequested == false)
                throw;
        }
    }

    public void Release()
    {
        _ftp?.Disconnect();
        _ftp?.Dispose();
    }

    private void InitClient()
    {
        lock (this)
        {
            if (_ftp?.IsConnected != true)
            {
                _ftp?.Dispose();
                _ftp = new AsyncFtpClient(Hostname, new System.Net.NetworkCredential(Username, Password), Port);
                _ftp.Connect();
            }
        }
    }

    private readonly System.Timers.Timer _timerKeepAlive = new System.Timers.Timer();

    private void CheckMeAlive()
    {
        _timerKeepAlive.Interval = 10 * 1000;
        _timerKeepAlive.AutoReset = false;
        _timerKeepAlive.Elapsed += (sender, args) =>
        {
            InitClient();
            lock (this)
            {
                _ftp?.GetListing("/");
            }

            try
            {
                _timerKeepAlive.Interval = 10 * 1000;
                _timerKeepAlive?.Start();
            }
            catch (Exception e)
            {
                SimpleLogHelper.Error(e);
            }
        };
        _timerKeepAlive.Start();
    }
}

}

<!-- gh-comment-id:2278415985 --> @GlacierDataworks commented on GitHub (Aug 9, 2024): This is the file that changed. Pam From: VShawn ***@***.***> Sent: Thursday, August 8, 2024 10:06 PM To: 1Remote/1Remote ***@***.***> Cc: Glacier Dataworks ***@***.***>; Author ***@***.***> Subject: Re: [1Remote/1Remote] FtpClient - Missing Objects/Methods (Issue #696) maybe you can make a PR for this :) — Reply to this email directly, view it on GitHub <https://github.com/1Remote/1Remote/issues/696#issuecomment-2277392349> , or unsubscribe <https://github.com/notifications/unsubscribe-auth/AUFZJQT4GRSXYMFWYHJQ75LZQRZ57AVCNFSM6AAAAABL7EIYSSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENZXGM4TEMZUHE> . You are receiving this because you authored the thread.Message ID: ***@***.***> using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using FluentFTP; using Shawn.Utils; namespace _1RM.Model.Protocol.FileTransmit.Transmitters { public class TransmitterFtp : ITransmitter { public readonly string Hostname; public readonly int Port; public readonly string Username; public readonly string Password; private AsyncFtpClient? _ftp = null; public TransmitterFtp(string host, int port, string username, string password) { Hostname = host; Port = port; Username = username; Password = password; InitClient(); CheckMeAlive(); } ~TransmitterFtp() { _ftp?.Dispose(); _timerKeepAlive.Stop(); } public void Conn() { InitClient(); } public bool IsConnected() { lock (this) { return _ftp?.IsConnected == true; } } public ITransmitter Clone() { return new TransmitterFtp(Hostname, Port, Username, Password); } public RemoteItem? Get(string path) { if (_ftp == null) return null; lock (this) { return Exists(path) ? FtpListItem2RemoteItem(_ftp.GetObjectInfo(path).Result) : null; } } public List<RemoteItem> ListDirectoryItems(string path) { if (_ftp == null) return new List<RemoteItem>(); lock (this) { var ret = new List<RemoteItem>(); IEnumerable<FtpListItem> items = _ftp.GetListing(path).Result; if (items == null || !items.Any()) return ret; items = items.OrderBy(x => x.Name); foreach (var item in items) { if (item.Name == "." || item.Name == "..") continue; ret.Add(FtpListItem2RemoteItem(item)); } return ret; } } public bool Exists(string path) { if (_ftp == null) return false; lock (this) { if (_ftp.FileExists(path).Result) return true; if (_ftp.DirectoryExists(path).Result) return true; return false; } } private RemoteItem FtpListItem2RemoteItem(FtpListItem item) { lock (this) { var fn = item.FullName; var newItem = new RemoteItem() { Icon = null, IsDirectory = item.Type == FtpObjectType.Directory, Name = item.Name, FullName = fn, LastUpdate = item.RawModified, ByteSize = (ulong)item.Size, IsSymlink = item.Type == FtpObjectType.Link, }; if (item.Type == FtpObjectType.Directory) { if (newItem.IsSymlink) { newItem.Icon = TransmitItemIconCache.GetDictIcon(Environment.GetFolderPath(Environment.SpecialFolder.Favorites)); } else { newItem.Icon = TransmitItemIconCache.GetDictIcon(); } newItem.ByteSize = 0; newItem.FileType = "folder"; } else { if (item.Name.IndexOf(".", StringComparison.Ordinal) > 0) { var ext = item.Name.Substring(item.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLower(); newItem.FileType = ext; newItem.Icon = TransmitItemIconCache.GetFileIcon(ext); } else { newItem.Icon = TransmitItemIconCache.GetFileIcon(); } } return newItem; } } public void Delete(string path) { if (_ftp == null) return; lock (this) { var item = Get(path); if (item != null) { if (item.IsDirectory) { _ftp.DeleteDirectory(path); } else _ftp.DeleteFile(path); } } } public void Delete(RemoteItem item) { lock (this) { Delete(item.FullName); } } public void CreateDirectory(string path) { if (_ftp == null) return; lock (this) { if (_ftp.DirectoryExists(path).Result == false) _ftp.CreateDirectory(path); } } public void RenameFile(string path, string newPath) { if (_ftp == null) return; if (path != newPath) if (Exists(path)) lock (this) { _ftp.Rename(path, newPath); } } public void UploadFile(string localFilePath, string saveToRemotePath, Action<ulong> writeCallBack, CancellationToken cancellationToken) { if (_ftp == null) return; var fi = new FileInfo(localFilePath); if (fi?.Exists != true) return; lock (this) { try { // check parent if (saveToRemotePath.LastIndexOf("/", StringComparison.Ordinal) > 0) { var parent = saveToRemotePath.Substring(0, saveToRemotePath.LastIndexOf("/", StringComparison.Ordinal)); if (_ftp.DirectoryExists(parent).Result == false) _ftp.CreateDirectory(parent); } _ftp.UploadFile(localFilePath, saveToRemotePath, FtpRemoteExists.Overwrite, true, FtpVerify.Delete, new Progress<FtpProgress>(progress => { writeCallBack?.Invoke((ulong)progress.TransferredBytes); }), cancellationToken).Wait(cancellationToken); } catch (Exception) { if (cancellationToken.IsCancellationRequested == false) throw; } } } public void DownloadFile(string remoteFilePath, string saveToLocalPath, Action<ulong> readCallBack, CancellationToken cancellationToken) { if (_ftp == null) return; try { var t = _ftp.DownloadFile(saveToLocalPath, remoteFilePath, FtpLocalExists.Overwrite, FtpVerify.None, new Progress<FtpProgress>(progress => { readCallBack?.Invoke((ulong)progress.TransferredBytes); }), cancellationToken); t.Wait(cancellationToken); } catch (Exception) { if (cancellationToken.IsCancellationRequested == false) throw; } } public void Release() { _ftp?.Disconnect(); _ftp?.Dispose(); } private void InitClient() { lock (this) { if (_ftp?.IsConnected != true) { _ftp?.Dispose(); _ftp = new AsyncFtpClient(Hostname, new System.Net.NetworkCredential(Username, Password), Port); _ftp.Connect(); } } } private readonly System.Timers.Timer _timerKeepAlive = new System.Timers.Timer(); private void CheckMeAlive() { _timerKeepAlive.Interval = 10 * 1000; _timerKeepAlive.AutoReset = false; _timerKeepAlive.Elapsed += (sender, args) => { InitClient(); lock (this) { _ftp?.GetListing("/"); } try { _timerKeepAlive.Interval = 10 * 1000; _timerKeepAlive?.Start(); } catch (Exception e) { SimpleLogHelper.Error(e); } }; _timerKeepAlive.Start(); } } }
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/1Remote#2491
No description provided.