diff --git a/CH.CQRS/CH.CQRS.csproj b/CH.CQRS/CH.CQRS.csproj index 11530f8..bff4ccf 100644 --- a/CH.CQRS/CH.CQRS.csproj +++ b/CH.CQRS/CH.CQRS.csproj @@ -16,6 +16,7 @@ + diff --git a/CH.CQRS/Service/CryptoStats/CryptoService.cs b/CH.CQRS/Service/CryptoStats/CryptoService.cs index 880a486..fc1a557 100644 --- a/CH.CQRS/Service/CryptoStats/CryptoService.cs +++ b/CH.CQRS/Service/CryptoStats/CryptoService.cs @@ -1,12 +1,13 @@  +using CH.CryptoStats.CoinGecko; using CH.CryptoStats.CoinMarketCap; namespace CH.CQRS.Service.CryptoStats; -public class CryptoService(CoinMarketCapService coinMarketCap) +public class CryptoService(CoinGeckoService coinGecko) { public async Task GetCryptoStatsAsync(CancellationToken cancellationToken) { - var crypto = await coinMarketCap.GetCryptoStatsAsync("bitcoin", "cad", cancellationToken); + var crypto = await coinGecko.GetCryptoStatsAsync("bitcoin", "cad", cancellationToken); } } diff --git a/CH.CryptoStats.CoinGecko/CoinGecko.cs b/CH.CryptoStats.CoinGecko/CoinGecko.cs deleted file mode 100644 index 11dfa4d..0000000 --- a/CH.CryptoStats.CoinGecko/CoinGecko.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using CH.CryptoStats.Abstractions; - -namespace CH.CryptoStats.CoinGecko; - -public class CoinGecko : ICryptoStats -{ - //https://docs.coingecko.com/reference/coins-id - public Task GetCryptoStatsAsync(string cryptoName, string currency, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task ParseCryptoStats(JsonDocument jsonDocument, string currency, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } -} diff --git a/CH.CryptoStats.CoinGecko/CoinGeckoEntity.cs b/CH.CryptoStats.CoinGecko/CoinGeckoEntity.cs new file mode 100644 index 0000000..bac0ff5 --- /dev/null +++ b/CH.CryptoStats.CoinGecko/CoinGeckoEntity.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; +namespace CH.CryptoStats.CoinGecko; +public class CoinGeckoEntity + { + [JsonPropertyName("symbol")] + public required string Symbol { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + [JsonPropertyName("current_price")] + public decimal Price { get; set; } + [JsonPropertyName("market_cap")] + public decimal MarketCap { get; set; } + [JsonPropertyName("fully_diluted_valuation")] + public decimal FullyDilutedValuation { get; set; } + [JsonPropertyName("circulating_supply")] + public decimal CirculatingSupply { get; set; } + [JsonPropertyName("total_supply")] + public decimal TotalSupply { get; set; } + [JsonPropertyName("max_supply")] + public decimal MaxSupply { get; set; } + + [JsonPropertyName("last_updated")] + public DateTime LastUpdated { get; set; } + } \ No newline at end of file diff --git a/CH.CryptoStats.CoinGecko/CoinGeckoModule.cs b/CH.CryptoStats.CoinGecko/CoinGeckoModule.cs index 4f454a8..85cbc51 100644 --- a/CH.CryptoStats.CoinGecko/CoinGeckoModule.cs +++ b/CH.CryptoStats.CoinGecko/CoinGeckoModule.cs @@ -9,7 +9,7 @@ public class CoinGeckoModule : IModule { public IServiceCollection ConfigureServices(IServiceCollection services) { - services.AddScoped(); + services.AddScoped(); return services; } } diff --git a/CH.CryptoStats.CoinGecko/CoinGeckoService.cs b/CH.CryptoStats.CoinGecko/CoinGeckoService.cs new file mode 100644 index 0000000..1daecdc --- /dev/null +++ b/CH.CryptoStats.CoinGecko/CoinGeckoService.cs @@ -0,0 +1,38 @@ +using CH.CryptoStats.Abstractions; +using Microsoft.Extensions.Configuration; +using System.Net.Http.Json; +using System.Text.Json; +using CH.Energy.Abstractions.Enum; + +namespace CH.CryptoStats.CoinGecko; + +public class CoinGeckoService(IConfiguration configuration, HttpClient httpClient) : ICryptoStats +{ + public async Task GetCryptoStatsAsync(string cryptoName, string currency, CancellationToken cancellationToken) + { + var apiKey = configuration.GetValue("CoinGecko:ApiKey"); + var apiUrl = configuration.GetValue("CoinGecko:ApiUrl"); + var response = await httpClient.GetAsync($"{apiUrl}?ids={cryptoName}&vs_currency={currency}&x_cg_demo_api_key={apiKey}",cancellationToken); + var jsonResponse = await response.Content.ReadFromJsonAsync>(cancellationToken); + return ParseCryptoStats(jsonResponse.FirstOrDefault(), currency, cancellationToken).Result; + } + + private Task ParseCryptoStats(CoinGeckoEntity coinGeckoEntity, string currency, CancellationToken cancellationToken) + { + + var cryptoStats = new Abstractions.CryptoStats + { + Name = coinGeckoEntity.Name, + Symbol = coinGeckoEntity.Symbol, + MaxSupply = coinGeckoEntity.MaxSupply, + CirculatingSupply = coinGeckoEntity.CirculatingSupply, + TotalSupply = coinGeckoEntity.TotalSupply, + Currency = (Currency)System.Enum.Parse(typeof(Currency), currency.ToUpper()), + UpdatedAt = coinGeckoEntity.LastUpdated, + Price = coinGeckoEntity.Price, + MarketCap = coinGeckoEntity.MarketCap, + FullyDilutedMarketCap = coinGeckoEntity.FullyDilutedValuation + }; + return Task.FromResult(cryptoStats); + } +} diff --git a/CH.CryptoStats.CoinMarketCap/CH.CryptoStats.CoinMarketCap.csproj b/CH.CryptoStats.CoinMarketCap/CH.CryptoStats.CoinMarketCap.csproj index 359c8bb..06aa80e 100644 --- a/CH.CryptoStats.CoinMarketCap/CH.CryptoStats.CoinMarketCap.csproj +++ b/CH.CryptoStats.CoinMarketCap/CH.CryptoStats.CoinMarketCap.csproj @@ -14,5 +14,6 @@ + diff --git a/CH.CryptoStats.CoinMarketCap/CoinMarketCapEntity.cs b/CH.CryptoStats.CoinMarketCap/CoinMarketCapEntity.cs index 2752375..598ae5e 100644 --- a/CH.CryptoStats.CoinMarketCap/CoinMarketCapEntity.cs +++ b/CH.CryptoStats.CoinMarketCap/CoinMarketCapEntity.cs @@ -11,9 +11,9 @@ public class CoinMarketCapEntity [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public required string Name { get; set; } [JsonPropertyName("symbol")] - public string Symbol { get; set; } + public required string Symbol { get; set; } [JsonPropertyName("max_supply")] public int MaxSupply { get; set; } [JsonPropertyName("circulating_supply")] @@ -27,6 +27,7 @@ public class CoinMarketCapEntity } public class ApiResponse { + [JsonPropertyName("data")] public required Dictionary Data { get; set; } } @@ -43,9 +44,9 @@ public class CurrencyValue [JsonPropertyName("price")] public decimal Price { get; set; } [JsonPropertyName("volume_24h")] - public decimal Volume24h { get; set; } + public decimal Volume24H { get; set; } [JsonPropertyName("volume_change_24h")] - public decimal VolumeChange24h { get; set; } + public decimal VolumeChange24H { get; set; } [JsonPropertyName("market_cap")] public decimal MarketCap { get; set; } [JsonPropertyName("market_cap_dominance")] diff --git a/CH.CryptoStats.CoinMarketCap/CoinMarketCapService.cs b/CH.CryptoStats.CoinMarketCap/CoinMarketCapService.cs index ab76ec6..fa1c7c2 100644 --- a/CH.CryptoStats.CoinMarketCap/CoinMarketCapService.cs +++ b/CH.CryptoStats.CoinMarketCap/CoinMarketCapService.cs @@ -2,6 +2,8 @@ using Microsoft.Extensions.Configuration; using System.Net.Http.Json; using System.Text.Json; +using CH.Energy.Abstractions.Enum; + namespace CH.CryptoStats.CoinMarketCap; public class CoinMarketCapService(HttpClient httpClient, IConfiguration configuration) : ICryptoStats @@ -18,6 +20,7 @@ public class CoinMarketCapService(HttpClient httpClient, IConfiguration configur private Task ParseCryptoStats(CoinMarketCapEntity coinMarketCapEntity, string currency, CancellationToken cancellationToken) { + var quoteData = coinMarketCapEntity.Quote.CAD ?? coinMarketCapEntity.Quote.USD; var cryptoStats = new Abstractions.CryptoStats { Name = coinMarketCapEntity.Name, @@ -25,20 +28,14 @@ public class CoinMarketCapService(HttpClient httpClient, IConfiguration configur MaxSupply = coinMarketCapEntity.MaxSupply, CirculatingSupply = coinMarketCapEntity.CirculatingSupply, TotalSupply = coinMarketCapEntity.TotalSupply, - Currency = currency.ToUpper(), + Currency = (Currency)System.Enum.Parse(typeof(Currency), currency.ToUpper()), UpdatedAt = DateTime.Parse(coinMarketCapEntity.LastUpdated), - Price = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.Price : coinMarketCapEntity.Quote.CAD.Price, - Volume24H = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.Volume24h : coinMarketCapEntity.Quote.CAD.Volume24h, - VolumeChange24H = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.VolumeChange24h : coinMarketCapEntity.Quote.CAD.VolumeChange24h, - MarketCap = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.MarketCap : coinMarketCapEntity.Quote.CAD.MarketCap, - MarketCapDominance = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.MarketCapDominance : coinMarketCapEntity.Quote.CAD.MarketCapDominance, - FullyDilutedMarketCap = coinMarketCapEntity.Quote.CAD == null ? - coinMarketCapEntity.Quote.USD.FullyDilutedMarketCap : coinMarketCapEntity.Quote.CAD.FullyDilutedMarketCap + Price = quoteData.Price, + Volume24H = quoteData.Volume24H, + VolumeChange24H = quoteData.VolumeChange24H, + MarketCap = quoteData.MarketCap, + MarketCapDominance = quoteData.MarketCapDominance, + FullyDilutedMarketCap = quoteData.FullyDilutedMarketCap }; return Task.FromResult(cryptoStats); } diff --git a/CH.CryptoStats/CH.CryptoStats.Abstractions.csproj b/CH.CryptoStats/CH.CryptoStats.Abstractions.csproj index c9141d6..ba4fe7f 100644 --- a/CH.CryptoStats/CH.CryptoStats.Abstractions.csproj +++ b/CH.CryptoStats/CH.CryptoStats.Abstractions.csproj @@ -12,4 +12,7 @@ + + + diff --git a/CH.CryptoStats/CryptoStats.cs b/CH.CryptoStats/CryptoStats.cs index 5c985c9..f589b0f 100644 --- a/CH.CryptoStats/CryptoStats.cs +++ b/CH.CryptoStats/CryptoStats.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using CH.Energy.Abstractions.Enum; namespace CH.CryptoStats.Abstractions; @@ -10,10 +11,10 @@ public class CryptoStats { public required string Name { get; set; } public required string Symbol { get; set; } - public long MaxSupply { get; set; } - public long CirculatingSupply { get; set; } - public long TotalSupply { get; set; } - public required string Currency { get; set; } + public decimal MaxSupply { get; set; } + public decimal CirculatingSupply { get; set; } + public decimal TotalSupply { get; set; } + public required Currency Currency { get; set; } public DateTime UpdatedAt { get; set; } public decimal Price { get; set; } public decimal Volume24H { get; set; } diff --git a/CH.Enum/CH.Enum.csproj b/CH.Enum/CH.Enum.csproj new file mode 100644 index 0000000..3a63532 --- /dev/null +++ b/CH.Enum/CH.Enum.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/CH.Enum/Currency.cs b/CH.Enum/Currency.cs new file mode 100644 index 0000000..638c271 --- /dev/null +++ b/CH.Enum/Currency.cs @@ -0,0 +1,7 @@ +namespace CH.Energy.Abstractions.Enum; + +public enum Currency +{ + USD, + CAD, +} \ No newline at end of file diff --git a/ConstellationHeating.sln b/ConstellationHeating.sln index 0ef0fe0..fa03266 100644 --- a/ConstellationHeating.sln +++ b/ConstellationHeating.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.Abstractions", "C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.HydroQuebec", "CH.Energy.HydroQuebec\CH.Energy.HydroQuebec.csproj", "{91BB50CF-87B6-40A0-BB70-B42B7208167A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Enum", "CH.Enum\CH.Enum.csproj", "{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,6 +65,10 @@ Global {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Debug|Any CPU.Build.0 = Debug|Any CPU {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.ActiveCfg = Release|Any CPU {91BB50CF-87B6-40A0-BB70-B42B7208167A}.Release|Any CPU.Build.0 = Release|Any CPU + {45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE