Esempio n. 1
0
        public async Task <string[]> DownloadAsync(int siteId, SFtpOptions options = null)
        {
            var policy = PolicyFactory.CreateRetry(5, (e) =>
            {
                _logger.LogError($"Retrying, ex: {e}.");
            });

            var files = await policy.Execute(async() => await DoDownloadAsync(siteId, options));

            if (files?.Length > 0)
            {
                return(files);
            }

            _logger.LogWarning($"No files found from sftp server.");
            return(null);
        }
Esempio n. 2
0
        private async Task <string[]> DoDownloadAsync(int siteId, SFtpOptions options)
        {
            var opts = _options.Value ?? options;

            if (!opts.IsValid())
            {
                _logger.LogError($"{nameof(SFtpOptions)} is invalid, config: {opts}.");
                return(null);
            }
            if (siteId <= 0)
            {
                _logger.LogError($"The {nameof(siteId)}[{siteId}] must be provided.");
                return(null);
            }

            if (Interlocked.CompareExchange(ref _isDownloading, 1, 0) != 0)
            {
                _logger.LogWarning($"{nameof(SFTPFilesDownloader)} is downloading, please try again later.");
                return(null);
            }

            string[] files = null;
            try
            {
                var sftp = new Sftp();

                _logger.LogInformation($"Connecting sftp server[{opts.Host}]...");
                if (string.IsNullOrEmpty(opts.Host))
                {
                    _logger.LogError($"The {nameof(opts.Host)}[{opts.Host}] must be provided.");
                    return(null);
                }

                await sftp.ConnectAsync(opts.Host, 22);

                _logger.LogInformation($"Authenticating sftp user[UserName: {opts.UserName}]...");
                switch (opts.AuthScheme)
                {
                case SFtpOptions.AuthenticateScheme.Password:
                    if (string.IsNullOrEmpty(opts.Password))
                    {
                        _logger.LogError($"In the password authenticate scheme, the password must be provided.");
                        return(null);
                    }
                    await sftp.AuthenticateAsync(opts.UserName, opts.Password);

                    break;

                case SFtpOptions.AuthenticateScheme.SecurityKey:
                    if (opts.PrivateKey == null ||
                        !opts.PrivateKey.CanRead)
                    {
                        _logger.LogError($"In the security sey authenticate scheme, the Private Key must be provided.");
                        return(null);
                    }
                    var privateKey = new SecureShellPrivateKey(opts.PrivateKey);
                    await sftp.AuthenticateAsync(opts.UserName, privateKey);

                    break;

                default:
                    throw new InvalidOperationException($"Only these authenticate schemes[{nameof(SFtpOptions.AuthenticateScheme.Password)},{nameof(SFtpOptions.AuthenticateScheme.SecurityKey)}] supported.");
                }

                var filter = _namingStrategy.GetFileRegexName();
                files = await sftp.ListNameAsync(opts.RemoteDirectory, new NameRegexSearchCondition(filter));

                if (files.Length <= 0)
                {
                    _logger.LogWarning($"No reports files found from sftp server.");
                    return(null);
                }

                _logger.LogInformation($"The reports[{files.Aggregate((x, y) => $"{x},{y}")}] will be downloaded.");

                if (string.IsNullOrEmpty(opts.LocalDirectory))
                {
                    opts.LocalDirectory = Path.Combine(Directory.GetCurrentDirectory(), "reports", siteId.ToString());
                }

                if (!Directory.Exists(opts.LocalDirectory))
                {
                    Directory.CreateDirectory(opts.LocalDirectory);
                }

                var hasNewFile = false;
                foreach (var file in files)
                {
                    var isDownloaded = await _manager.IsDownloadedAsync(siteId, opts.LocalDirectory, file);

                    if (isDownloaded)
                    {
                        continue;
                    }

                    _logger.LogInformation($"The file[{file}] downloading...");

                    var localPath = Path.Combine(opts.LocalDirectory, file);
                    if (File.Exists(localPath))
                    {
                        File.Delete(localPath);
                    }

                    using (var stream = new FileStream(localPath, FileMode.Create))
                    {
                        var remoteDir  = opts.RemoteDirectory.TrimStart('/').TrimEnd('/').Replace('\\', '/');
                        var remotePath = $"/{remoteDir}/{file}";
                        await sftp.DownloadFileAsync(remotePath, stream);
                    }

                    hasNewFile = true;
                    _logger.LogInformation($"The file[{localPath}] was downloaded successfully.");
                }

                await sftp.DisconnectAsync();

                if (hasNewFile)
                {
                    _manager.TryRefreshSavePoint(siteId);
                }

                return(files.Select(it => Path.Combine(opts.LocalDirectory, it)).ToArray());
            }
            catch (Exception e)
            {
                var filesToRemove = files?.Select(it => Path.Combine(opts.LocalDirectory, it)).ToArray();
                _manager.TryRemoveSavePoint(siteId, filesToRemove);
                _logger.LogError($"{nameof(DownloadAsync)} has a unknown exception, ex: {e}");
                return(null);
            }
            finally
            {
                _isDownloading = 0;
            }
        }