<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using CoinBot.Core;
using CoinBot.Core.JsonConverters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace CoinBot.Clients.FunFair
{
    public abstract class FunFairClientBase : CoinClientBase
    {
        private const string HTTP_CLIENT_NAME = @"FunFair";

        /// <summary>
        ///     List of crypto currencies hard coded for now.
        /// </summary>
        private readonly IReadOnlyList<string> _cryptoSymbols = new[] {@"FUN"};

        /// <summary>
        ///     List of fiat currencies hard coded for now.
        /// </summary>
        private readonly IReadOnlyList<string> _fiatSymbols = new[] {@"USD"};

        private readonly JsonSerializerOptions _jsonSerializerSettings;

        protected FunFairClientBase(IHttpClientFactory httpClientFactory, ILogger logger)
            : base(httpClientFactory, HTTP_CLIENT_NAME, logger)
        {
            this._jsonSerializerSettings = new JsonSerializerOptions
                                           {
                                               IgnoreNullValues = true,
                                               PropertyNameCaseInsensitive = false,
                                               PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                                               Converters = {new DecimalAsStringConverter()}
                                           };
        }

        internal async Task<IReadOnlyCollection<FunFairWalletPriceResultPairDto>> GetBasePricesAsync()
        {
            List<(string cryptoSymbol, string fiatSymbol)> symbols =
                (from cryptoSymbol in this._cryptoSymbols from fiatSymbol in this._fiatSymbols select (cryptoSymbol, fiatSymbol)).ToList();

            try
            {
                return await Task.WhenAll(symbols.Select(this.GetCurrentPriceCommonAsync));
            }
            catch (Exception exception)
            {
                EventId eventId = new EventId(exception.HResult);
                this.Logger.LogError(eventId, exception, exception.Message);

                throw;
            }
        }

        public static void Register(IServiceCollection services, FunFairClientConfiguration? options)
        {
            if (options == null)
            {
                return;
            }

            if (!Uri.TryCreate(options.Endpoint ?? string.Empty, UriKind.Absolute, out Uri? endpoint))
            {
                return;
            }

            services.AddSingleton<IMarketClient, FunFairClientMarket>();
            services.AddSingleton<ICoinClient, FunFairClientCoin>();
            services.AddSingleton(options);

            AddHttpClientFactorySupport(services, HTTP_CLIENT_NAME, endpoint);
        }

        private Task<FunFairWalletPriceResultPairDto?> GetCurrentPriceCommonAsync((string tokenSymbol, string fiatCurrencySymbol) pair)
        {
            return this.GetCurrentPriceCommonAsync(pair.tokenSymbol, pair.fiatCurrencySymbol);
        }

        private async Task<FunFairWalletPriceResultPairDto?> GetCurrentPriceCommonAsync(string tokenSymbol, string fiatCurrencySymbol)
        {
            HttpClient client = this.CreateHttpClient();

            Uri uri = BuildUri(tokenSymbol, fiatCurrencySymbol);

            using (HttpResponseMessage response = await client.GetAsync(uri))
            {
                if (!response.IsSuccessStatusCode)
                {
                    this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: Http Error: {response.StatusCode}");

                    return null;
                }

                string msg = await response.Content.ReadAsStringAsync();

                if (string.IsNullOrWhiteSpace(msg))
                {
                    this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: No Content returned (1)");

                    return null;
                }

                FunFairWalletPriceResultDto pkt = JsonSerializer.Deserialize<FunFairWalletPriceResultDto>(msg, this._jsonSerializerSettings);

                if (pkt.Symbol == null)
                {
                    this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: No Content returned (2)");

                    return null;
                }

                this.Logger.LogDebug($"Retrieved price for {tokenSymbol}.  Currently {pkt.Price} {fiatCurrencySymbol}");

                return new FunFairWalletPriceResultPairDto(fiatCurrencySymbol, pkt.Symbol, pkt.Price, pkt.Date);
            }
        }

        private static Uri BuildUri(string tokenSymbol, string fiatCurrencySymbol)
        {
            return new Uri($"/Dev/token/{tokenSymbol}/{fiatCurrencySymbol}", UriKind.Relative);
        }
    }
}<commit_msg>Logging for when there's an unhandled exception<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using CoinBot.Core;
using CoinBot.Core.JsonConverters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace CoinBot.Clients.FunFair
{
    public abstract class FunFairClientBase : CoinClientBase
    {
        private const string HTTP_CLIENT_NAME = @"FunFair";

        /// <summary>
        ///     List of crypto currencies hard coded for now.
        /// </summary>
        private readonly IReadOnlyList<string> _cryptoSymbols = new[] {@"FUN"};

        /// <summary>
        ///     List of fiat currencies hard coded for now.
        /// </summary>
        private readonly IReadOnlyList<string> _fiatSymbols = new[] {@"USD"};

        private readonly JsonSerializerOptions _jsonSerializerSettings;

        protected FunFairClientBase(IHttpClientFactory httpClientFactory, ILogger logger)
            : base(httpClientFactory, HTTP_CLIENT_NAME, logger)
        {
            this._jsonSerializerSettings = new JsonSerializerOptions
                                           {
                                               IgnoreNullValues = true,
                                               PropertyNameCaseInsensitive = false,
                                               PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                                               Converters = {new DecimalAsStringConverter()}
                                           };
        }

        internal async Task<IReadOnlyCollection<FunFairWalletPriceResultPairDto>> GetBasePricesAsync()
        {
            List<(string cryptoSymbol, string fiatSymbol)> symbols =
                (from cryptoSymbol in this._cryptoSymbols from fiatSymbol in this._fiatSymbols select (cryptoSymbol, fiatSymbol)).ToList();

            try
            {
                return await Task.WhenAll(symbols.Select(this.GetCurrentPriceCommonAsync));
            }
            catch (Exception exception)
            {
                EventId eventId = new EventId(exception.HResult);
                this.Logger.LogError(eventId, exception, exception.Message);

                throw;
            }
        }

        public static void Register(IServiceCollection services, FunFairClientConfiguration? options)
        {
            if (options == null)
            {
                return;
            }

            if (!Uri.TryCreate(options.Endpoint ?? string.Empty, UriKind.Absolute, out Uri? endpoint))
            {
                return;
            }

            services.AddSingleton<IMarketClient, FunFairClientMarket>();
            services.AddSingleton<ICoinClient, FunFairClientCoin>();
            services.AddSingleton(options);

            AddHttpClientFactorySupport(services, HTTP_CLIENT_NAME, endpoint);
        }

        private Task<FunFairWalletPriceResultPairDto?> GetCurrentPriceCommonAsync((string tokenSymbol, string fiatCurrencySymbol) pair)
        {
            return this.GetCurrentPriceCommonAsync(pair.tokenSymbol, pair.fiatCurrencySymbol);
        }

        private async Task<FunFairWalletPriceResultPairDto?> GetCurrentPriceCommonAsync(string tokenSymbol, string fiatCurrencySymbol)
        {
            try
            {
                HttpClient client = this.CreateHttpClient();

                Uri uri = BuildUri(tokenSymbol, fiatCurrencySymbol);

                using (HttpResponseMessage response = await client.GetAsync(uri))
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: Http Error: {response.StatusCode}");

                        return null;
                    }

                    string msg = await response.Content.ReadAsStringAsync();

                    if (string.IsNullOrWhiteSpace(msg))
                    {
                        this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: No Content returned (1)");

                        return null;
                    }

                    FunFairWalletPriceResultDto pkt = JsonSerializer.Deserialize<FunFairWalletPriceResultDto>(msg, this._jsonSerializerSettings);

                    if (pkt.Symbol == null)
                    {
                        this.Logger.LogError($"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: No Content returned (2)");

                        return null;
                    }

                    this.Logger.LogDebug($"Retrieved price for {tokenSymbol}.  Currently {pkt.Price} {fiatCurrencySymbol}");

                    return new FunFairWalletPriceResultPairDto(fiatCurrencySymbol, pkt.Symbol, pkt.Price, pkt.Date);
                }
            }
            catch (Exception exception)
            {
                this.Logger.LogError(new EventId(exception.HResult), exception, $"Failed to retrieve prices for {tokenSymbol} in {fiatCurrencySymbol}: Error: {exception.Message}");

                return null;
            }
        }

        private static Uri BuildUri(string tokenSymbol, string fiatCurrencySymbol)
        {
            return new Uri($"/Dev/token/{tokenSymbol}/{fiatCurrencySymbol}", UriKind.Relative);
        }
    }
}
{'fraction_non_alphanumeric': 0.07951186957765279, 'fraction_numerical': 0.00038135189245876633, 'mean_word_length': 1.8779149519890261, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5929218', 'n_tokens_mistral': 2511, 'n_tokens_neox': 2415, 'n_words': 543}