protected override async Task <IFtpClientConnection> GetConnection(CancellationToken ctk = default) { IFtpClientConnection result = null; await _semaphore.WaitAsync(ctk); try { while (_pool.TryPop(out var candidate)) { if (await candidate.IsConnectedAsync(ctk)) { result = candidate; break; } candidate.Dispose(); } if (result == null) { result = _createNewConnection(); await result.ConnectAsync(ctk); } var pooled = new PooledFtpConnection(result); pooled.Disposing += _pooled_Disposing; return(pooled); } catch { result?.Dispose(); _semaphore.Release(); throw; } }
public override async Task <IEnumerable <FtpEntry> > ListFilesRecursiveAsync(string startPath = null, Predicate <FtpEntry> skipFolder = null, CancellationToken ctk = default) { IFtpClientConnection conn = null; try { _logger.Trace("List files starting from path: {0}", startPath); conn = await GetConnection(ctk); await conn.ConnectAsync(ctk); if (skipFolder == null) { skipFolder = x => false; } Stack <FtpEntry> pendingFolders = new Stack <FtpEntry>(); IEnumerable <FtpEntry> files = new List <FtpEntry>(); Func <string, CancellationToken, Task> listFolderAsync = async(string path, CancellationToken ct) => { var retrier = Policy .Handle <Exception>() .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), }, (ex, ts) => { _logger.Warn(ex, "Failed to list folder {0}. Try again soon ...", path); }); var list = await retrier.ExecuteAsync(async ct1 => { if (!await conn.IsConnectedAsync(ctk)) { conn.Dispose(); conn = await GetConnection(ctk); await conn.ConnectAsync(ctk); } return(await conn.ListDirectoryAsync(path, ct1)); }, ct); foreach (var d in list.Where(x => x.IsDirectory && !x.Name.Equals(".") && !x.Name.Equals(".."))) { if (skipFolder.Invoke(d)) { _logger.Info("Skipping folder: {0}", d.FullPath); } else { pendingFolders.Push(d); } } files = files.Concat(list.Where(x => !x.IsDirectory).ToList()); }; await listFolderAsync(startPath, ctk); while (pendingFolders.Count > 0) { await listFolderAsync(pendingFolders.Pop().FullPath, ctk); } return(files); } finally { conn?.Dispose(); } }
public PooledFtpConnection(IFtpClientConnection inner) { Inner = inner; }