private static async Task Execute(string settingsFilePath) { if (!File.Exists(settingsFilePath)) { Console.WriteLine($"{settingsFilePath} file not exist"); return; } var settings = new FileSettingsReader <ToolSettings>(settingsFilePath); var logFactory = LogFactory.Create() .AddConsole(); var assetServce = new AssetsService(new Uri(settings.CurrentValue.AssetServiceUrl)); var retryPolicy = Policy.Handle <RetryNeededException>() .WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry: (ex, delay, context, tsk) => { Console.WriteLine($"Retrying exception {ex.ToAsyncString()}"); }); var clientAccountService = new Lazy <ClientAccountClient>(() => new ClientAccountClient(settings.CurrentValue.ClientAccountUrl ?? throw new ArgumentNullException(settings.CurrentValue.ClientAccountUrl))); IEnumerable <Asset> assets; if (!string.IsNullOrEmpty(settings.CurrentValue.AssetId)) { var asset = await assetServce.AssetGetAsync(settings.CurrentValue.AssetId); if (asset == null) { Console.WriteLine($"Asset not found {settings.CurrentValue.AssetId}"); return; } assets = new [] { asset }; } else { assets = await assetServce.AssetGetAllAsync(); } var balanceReaders = BalanceReaderFactory.GetBalanceReaders(assetServce, settings.CurrentValue).ToArray(); const string csvDeliminator = ";"; string header = $"ClientId;Address;Amount;AssetId;ReceivedAmount;SpentAmount;TransactionsCount{Environment.NewLine}"; await File.AppendAllTextAsync(settings.CurrentValue.ResultFilePath, header); var counter = 0; string continuationToken = null; var relatedAssetsDictionary = new ConcurrentDictionary <Type, IEnumerable <Asset> >(); do { IEnumerable <string> clientIds; if (string.IsNullOrEmpty(settings.CurrentValue.ClientIdsFilePath)) { Console.WriteLine("Retrieving client ids batch"); var response = await clientAccountService.Value.GetIdsAsync(continuationToken); continuationToken = response.ContinuationToken; clientIds = response.Ids; } else { clientIds = await File.ReadAllLinesAsync(settings.CurrentValue.ClientIdsFilePath); } if (string.IsNullOrEmpty(settings.CurrentValue.AssetId) && settings.CurrentValue.IncludeZeroBalances) { throw new ArgumentException("If AssetId is omitted, IncludeZeroBalances should be false."); } foreach (var clientId in clientIds) { IEnumerable <(IBalanceReader balanceReader, string address)> addresses; switch (settings.CurrentValue.WalletType) { case WalletTypes.Private: addresses = await GetPrivateWalletAddresses(clientId, logFactory, settings, balanceReaders); break; case WalletTypes.Deposit: addresses = await GetDepositWallets(clientId, logFactory, settings, balanceReaders); break; default: throw new ArgumentException("Unknown switch", nameof(ToolSettings.WalletType)); } foreach (var balanceReaderAddresses in addresses.GroupBy(p => p.balanceReader.GetType())) { var balanceReader = balanceReaderAddresses.First().balanceReader; //cache enumeration var relatedAssets = relatedAssetsDictionary.GetOrAdd(balanceReader.GetType(), (type) => balanceReader.SelectRelatedAssetsAsync(assets).Result.ToList()); foreach (var address in balanceReader.SelectUniqueAddresses(balanceReaderAddresses.Select(p => p.address))) { try { var blockchainBalances = await retryPolicy.ExecuteAsync( () => balanceReader.ReadBalance(relatedAssets, address)); var transactionsInfo = await retryPolicy.ExecuteAsync( () => balanceReader.GetTransactionsInfoAsync(relatedAssets, address, settings.CurrentValue.AssetId, settings.CurrentValue.PrivateWalletsCount.FromDate, settings.CurrentValue.PrivateWalletsCount.FromBlock)); foreach (var blockchainBalance in blockchainBalances .Where(p => p.amount != 0 || settings.CurrentValue.IncludeZeroBalances)) { await File.AppendAllTextAsync(settings.CurrentValue.ResultFilePath, string.Join(csvDeliminator, clientId, blockchainBalance.address, blockchainBalance.amount.ToString(CultureInfo.InvariantCulture), blockchainBalance.assetId, transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.ReceivedAmount.ToString(CultureInfo.InvariantCulture) : "-", transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.SpentAmount.ToString(CultureInfo.InvariantCulture) : "-", transactionsInfo.AssetId == blockchainBalance.assetId ? transactionsInfo.TransactionsCount.ToString(CultureInfo.InvariantCulture) : "-" ) + Environment.NewLine); } } catch (Exception e) { Console.WriteLine($"Exception during processing balance for client {clientId}, address: {address}: {e.ToAsyncString()}"); await File.AppendAllTextAsync(settings.CurrentValue.ErrorFilePath, string.Join(csvDeliminator, DateTime.UtcNow, clientId, address, e.ToAsyncString()) + Environment.NewLine); } } } counter++; Console.WriteLine($"[{DateTime.UtcNow}] {clientId} done -- {counter}"); } } while (continuationToken != null); Console.WriteLine("All done"); }