feat: introduced caching in the server + Added serilog

This commit is contained in:
Mikhail Shabanov committed 2021-06-04 23:04:03 +02:00
1 parent 8c9770f8a0
commit 638489a842
25 files changed
+365 -33

No files matched your search

@@ -24,7 +24,7 @@ type Mutation {
"Updates the necessary dictionaries in database.\n\n\n**Returns:**\nInformation about what was updated." "Updates the necessary dictionaries in database.\n\n\n**Returns:**\nInformation about what was updated."
updateDictionaries("Determines what dictionaries should be updated." updateDictionariesRequest: UpdateDictionariesRequestInput!): [UpdateDictionariesResponseItem!]! updateDictionaries("Determines what dictionaries should be updated." updateDictionariesRequest: UpdateDictionariesRequestInput!): [UpdateDictionariesResponseItem!]!
"Gathers all account information" "Gathers all account information"
gatherAccountInformation("Account region" realmType: RealmType! "AccountId" accountId: Long! "Request language" requestLanguage: RequestLanguage!): AccountInfoResponse! gatherAccountInformation("Account region" realmType: RealmType! "AccountId" accountId: Long! "Request language" requestLanguage: RequestLanguage!): DateTime!
"This method accepts GitHub oauth code, and returns JWT token with GutHub user as claim" "This method accepts GitHub oauth code, and returns JWT token with GutHub user as claim"
gitHubAuthenticate("OAuth code can be generated by this URL https:\/\/github.com\/login\/oauth\/authorize?client_id={yourClientId}" oauthCode: String!): String! gitHubAuthenticate("OAuth code can be generated by this URL https:\/\/github.com\/login\/oauth\/authorize?client_id={yourClientId}" oauthCode: String!): String!
} }
@@ -1,4 +1,5 @@
using System.Threading.Tasks; using System;
using System.Threading.Tasks;
using HotChocolate; using HotChocolate;
using HotChocolate.AspNetCore.Authorization; using HotChocolate.AspNetCore.Authorization;
using HotChocolate.Types; using HotChocolate.Types;
@@ -43,7 +44,7 @@ namespace WotBlitzStatisticsPro.GraphQl.Mutation
/// <param name="requestLanguage">Request language</param> /// <param name="requestLanguage">Request language</param>
/// <param name="wgToken">Wargaming authentication token</param> /// <param name="wgToken">Wargaming authentication token</param>
/// <returns></returns> /// <returns></returns>
public Task<AccountInfoResponse> GatherAccountInformation( public Task<DateTime> GatherAccountInformation(
RealmType realmType, RealmType realmType,
long accountId, long accountId,
RequestLanguage requestLanguage, RequestLanguage requestLanguage,
+31 -3
View File
@@ -1,5 +1,9 @@
using System;
using System.IO;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Serilog;
namespace WotBlitzStatisticsPro.GraphQl namespace WotBlitzStatisticsPro.GraphQl
{ {
@@ -7,12 +11,36 @@ namespace WotBlitzStatisticsPro.GraphQl
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
CreateHostBuilder(args).Build().Run(); var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
.AddEnvironmentVariables()
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
try
{
Log.Information("Starting web host");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args) Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => .UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{ {
webBuilder.UseStartup<Startup>(); webBuilder.UseStartup<Startup>();
}); });
@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using HotChocolate.Types; using HotChocolate.Types;
using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.Common.Model; using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.Logic; using WotBlitzStatisticsPro.Logic;
+5 -1
View File
@@ -14,6 +14,7 @@ using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Serilog;
using WotBlitzStatisticsPro.Common; using WotBlitzStatisticsPro.Common;
using WotBlitzStatisticsPro.Common.Model; using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.GraphQl.GitHubOauth; using WotBlitzStatisticsPro.GraphQl.GitHubOauth;
@@ -37,7 +38,10 @@ namespace WotBlitzStatisticsPro.GraphQl
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
var wgApiConfig = new WargamingApiSettings(); //services.AddLogging(loggingBuilder =>
// loggingBuilder.AddSerilog(dispose: true));
var wgApiConfig = new WargamingApiSettings();
Configuration.GetSection("WargamingApi").Bind(wgApiConfig); Configuration.GetSection("WargamingApi").Bind(wgApiConfig);
var mongoConfig = new MongoSettings(); var mongoConfig = new MongoSettings();
@@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.4" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.10.0" /> <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
</ItemGroup> </ItemGroup>
@@ -1,9 +1,25 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft": "Warning", "Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" }
],
"Enrich": [ "FromLogContext" ]
} }
}
} }
@@ -0,0 +1,17 @@
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" }
],
"Enrich": [ "FromLogContext" ]
}
}
+25 -4
View File
@@ -14,9 +14,30 @@
"Mongo": { "Mongo": {
"ConnectionString": "*", "ConnectionString": "*",
"DatabaseName": "*" "DatabaseName": "*"
}, },
"GitHubOAuth": { "GitHubOAuth": {
"ClientId": "YourClientId", "ClientId": "YourClientId",
"ClientSecret": "YourSecret" "ClientSecret": "YourSecret"
} },
} "Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {Message:lj} |{SourceContext}|{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext" ]
}
}
@@ -4,6 +4,7 @@ using AutoMapper;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.DataAccess.Model.Accounts; using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
using WotBlitzStatisticsPro.Logic.Model;
using WotBlitzStatisticsPro.Logic.Pipeline; using WotBlitzStatisticsPro.Logic.Pipeline;
using WotBlitzStatisticsPro.WgApiClient; using WotBlitzStatisticsPro.WgApiClient;
using WotBlitzStatisticsPro.WgApiClient.Model; using WotBlitzStatisticsPro.WgApiClient.Model;
@@ -15,19 +16,36 @@ namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
private readonly IWargamingApiClient _wargamingApi; private readonly IWargamingApiClient _wargamingApi;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly ILogger<GetAccountInfoOperation> _logger; private readonly ILogger<GetAccountInfoOperation> _logger;
private readonly StatisticsCache _cache;
public GetAccountInfoOperation( public GetAccountInfoOperation(
IWargamingApiClient wargamingApi, IWargamingApiClient wargamingApi,
IMapper mapper, IMapper mapper,
ILogger<GetAccountInfoOperation> logger) ILogger<GetAccountInfoOperation> logger,
StatisticsCache cache)
{ {
_wargamingApi = wargamingApi; _wargamingApi = wargamingApi;
_mapper = mapper; _mapper = mapper;
_logger = logger; _logger = logger;
_cache = cache;
} }
public async Task Invoke(IOperationContext context, Func<IOperationContext, Task>? next) public async Task Invoke(IOperationContext context, Func<IOperationContext, Task>? next)
{ {
// Store info to AccountInfo and in AccountInfoHistory
var contextData = context.Get<AccountInformationPipelineContextData>();
var cache = _cache.GetAccountData(context.Request.AccountId);
if (cache != null)
{
contextData.AccountInfo = cache.AccountInfo;
contextData.AccountInfoHistory = cache.AccountInfoHistory;
_logger.LogInformation($"Account data for account {context.Request.AccountId} got from cache");
if (next != null) await next.Invoke(context);
return;
}
var accountInfo = await var accountInfo = await
_wargamingApi.GetPlayerAccountInfo(context.Request.AccountId, context.Request.RealmType, context.Request.RequestLanguage, context.Request.AuthenticationToken); _wargamingApi.GetPlayerAccountInfo(context.Request.AccountId, context.Request.RealmType, context.Request.RequestLanguage, context.Request.AuthenticationToken);
@@ -38,14 +56,14 @@ namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
return; return;
} }
// Store info to AccountInfo and in AccountInfoHistory
var contextData = context.Get<AccountInformationPipelineContextData>();
contextData.AccountInfo = _mapper.Map<WotAccountInfo, AccountInfo>(accountInfo); contextData.AccountInfo = _mapper.Map<WotAccountInfo, AccountInfo>(accountInfo);
contextData.AccountInfo.Realm = context.Request.RealmType; contextData.AccountInfo.Realm = context.Request.RealmType;
contextData.AccountInfoHistory = new AccountInfoHistory(context.Request.AccountId, contextData.AccountInfo.LastBattleTime); contextData.AccountInfoHistory = new AccountInfoHistory(context.Request.AccountId, contextData.AccountInfo.LastBattleTime);
_mapper.Map(accountInfo.Statistics?.All, contextData.AccountInfoHistory); _mapper.Map(accountInfo.Statistics?.All, contextData.AccountInfoHistory);
_cache.SetAccountData(context.Request.AccountId, new AccountDataCache(contextData.AccountInfo, contextData.AccountInfoHistory));
if (next != null) await next.Invoke(context); if (next != null) await next.Invoke(context);
} }
} }
@@ -6,6 +6,7 @@ using AutoMapper;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.DataAccess.Model.Accounts; using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
using WotBlitzStatisticsPro.Logic.Model;
using WotBlitzStatisticsPro.Logic.Pipeline; using WotBlitzStatisticsPro.Logic.Pipeline;
using WotBlitzStatisticsPro.WgApiClient; using WotBlitzStatisticsPro.WgApiClient;
@@ -16,21 +17,36 @@ namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
private readonly IWargamingTanksApiClient _wargamingApi; private readonly IWargamingTanksApiClient _wargamingApi;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly ILogger<GetTanksInfoOperation> _logger; private readonly ILogger<GetTanksInfoOperation> _logger;
private readonly StatisticsCache _cache;
public GetTanksInfoOperation( public GetTanksInfoOperation(
IWargamingTanksApiClient wargamingApi, IWargamingTanksApiClient wargamingApi,
IMapper mapper, IMapper mapper,
ILogger<GetTanksInfoOperation> logger) ILogger<GetTanksInfoOperation> logger,
StatisticsCache cache)
{ {
_wargamingApi = wargamingApi; _wargamingApi = wargamingApi;
_mapper = mapper; _mapper = mapper;
_logger = logger; _logger = logger;
_cache = cache;
} }
public async Task Invoke(IOperationContext context, Func<IOperationContext, Task>? next) public async Task Invoke(IOperationContext context, Func<IOperationContext, Task>? next)
{ {
var contextData = context.Get<AccountInformationPipelineContextData>(); var contextData = context.Get<AccountInformationPipelineContextData>();
var cache = _cache.GetTanksData(context.Request.AccountId);
if (cache != null)
{
contextData.Tanks = cache.TankInfo;
contextData.TanksHistory = cache.TankInfoHistory;
_logger.LogInformation($"Account tanks data for account {context.Request.AccountId} got from cache");
if (next != null) await next.Invoke(context);
return;
}
var tanksInfo = await var tanksInfo = await
_wargamingApi.GetPlayerAccountTanksInfo(context.Request.AccountId, context.Request.RealmType, context.Request.RequestLanguage); _wargamingApi.GetPlayerAccountTanksInfo(context.Request.AccountId, context.Request.RealmType, context.Request.RequestLanguage);
@@ -54,6 +70,8 @@ namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
contextData.TanksHistory[stat.TankId] = stat; contextData.TanksHistory[stat.TankId] = stat;
}); });
_cache.SetTanksData(context.Request.AccountId, new TanksDataCache(contextData.Tanks, contextData.TanksHistory));
if (next != null) await next.Invoke(context); if (next != null) await next.Invoke(context);
} }
} }
@@ -8,7 +8,7 @@ namespace WotBlitzStatisticsPro.Logic
{ {
Task<AccountInfoResponse> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage); Task<AccountInfoResponse> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage);
Task<AccountInfoResponse> GatherAndSaveAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage, string wargamingToken); Task<DateTime> GatherAndSaveAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage, string wargamingToken);
Task<AccountInfoHistoryResponse> GetAccountInfoHistory(RealmType realm, long accountId, DateTime startDate, Task<AccountInfoHistoryResponse> GetAccountInfoHistory(RealmType realm, long accountId, DateTime startDate,
RequestLanguage requestLanguage); RequestLanguage requestLanguage);
@@ -0,0 +1,17 @@
using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
namespace WotBlitzStatisticsPro.Logic.Model
{
public class AccountDataCache
{
public AccountDataCache(AccountInfo accountInfo, AccountInfoHistory accountInfoHistory)
{
AccountInfo = accountInfo;
AccountInfoHistory = accountInfoHistory;
}
public AccountInfo AccountInfo { get; }
public AccountInfoHistory AccountInfoHistory { get; }
}
}
@@ -0,0 +1,28 @@
using System;
namespace WotBlitzStatisticsPro.Logic.Model
{
public class CacheItem<T>
{
private const int ExpirationTimeoutInMinutes = 60;
private DateTime? _lastRefreshed = null;
private T? _itemData = default(T);
public long AccountId { get; set; }
public bool IsExpired => _lastRefreshed != null &&
(DateTime.Now - _lastRefreshed.Value).TotalMinutes > ExpirationTimeoutInMinutes;
public T? Data
{
get => _itemData;
set
{
_itemData = value;
_lastRefreshed = DateTime.Now;
}
}
}
}
@@ -0,0 +1,84 @@
using System.Collections.Generic;
namespace WotBlitzStatisticsPro.Logic.Model
{
public class StatisticsCache
{
private readonly Dictionary<long, CacheItem<AccountDataCache>> _accountsCache = new();
private readonly Dictionary<long, CacheItem<TanksDataCache>> _tanksCache = new();
public AccountDataCache? GetAccountData(long accountId)
{
if (!_accountsCache.ContainsKey(accountId) || _accountsCache[accountId].IsExpired)
{
return null;
}
return _accountsCache[accountId].Data;
}
public TanksDataCache? GetTanksData(long accountId)
{
if (!_tanksCache.ContainsKey(accountId) || _tanksCache[accountId].IsExpired)
{
return null;
}
return _tanksCache[accountId].Data;
}
public void SetAccountData(long accountId, AccountDataCache data)
{
if (!_accountsCache.ContainsKey(accountId))
{
_accountsCache.Add(accountId, new CacheItem<AccountDataCache>());
ClearExpiredAccounts();
}
_accountsCache[accountId].Data = data;
}
public void SetTanksData(long accountId, TanksDataCache data)
{
if (!_tanksCache.ContainsKey(accountId))
{
_tanksCache.Add(accountId, new CacheItem<TanksDataCache>());
ClearExpiredTanks();
}
_tanksCache[accountId].Data = data;
}
private void ClearExpiredAccounts()
{
var expired = new List<long>();
foreach (var cacheItem in _accountsCache)
{
if (cacheItem.Value.IsExpired)
{
expired.Add(cacheItem.Key);
}
}
foreach (var expiredKey in expired)
{
_accountsCache.Remove(expiredKey);
}
}
private void ClearExpiredTanks()
{
var expired = new List<long>();
foreach (var cacheItem in _tanksCache)
{
if (cacheItem.Value.IsExpired)
{
expired.Add(cacheItem.Key);
}
}
foreach (var expiredKey in expired)
{
_accountsCache.Remove(expiredKey);
}
}
}
}
@@ -0,0 +1,18 @@
using System.Collections.Generic;
using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
namespace WotBlitzStatisticsPro.Logic.Model
{
public class TanksDataCache
{
public TanksDataCache(List<TankInfo> tankInfo, Dictionary<long, TankInfoHistory> tankInfoHistory)
{
TankInfo = tankInfo;
TankInfoHistory = tankInfoHistory;
}
public List<TankInfo> TankInfo { get; }
public Dictionary<long, TankInfoHistory> TankInfoHistory { get; }
}
}
@@ -5,6 +5,7 @@ using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
using WotBlitzStatisticsPro.Logic.Calculations;
using WotBlitzStatisticsPro.Logic.Pipeline; using WotBlitzStatisticsPro.Logic.Pipeline;
namespace WotBlitzStatisticsPro.Logic namespace WotBlitzStatisticsPro.Logic
@@ -58,7 +59,7 @@ namespace WotBlitzStatisticsPro.Logic
return contextData?.Response ?? new AccountInfoResponse(); return contextData?.Response ?? new AccountInfoResponse();
} }
public async Task<AccountInfoResponse> GatherAndSaveAccountInformation( public async Task<DateTime> GatherAndSaveAccountInformation(
RealmType realm, RealmType realm,
long accountId, long accountId,
RequestLanguage requestLanguage, RequestLanguage requestLanguage,
@@ -78,7 +79,6 @@ namespace WotBlitzStatisticsPro.Logic
.AddOperation<GetTanksInfoOperation>() .AddOperation<GetTanksInfoOperation>()
.AddOperation<CalculateStatisticsOperation>() .AddOperation<CalculateStatisticsOperation>()
.AddOperation<SaveAccountAndTanksOperation>() .AddOperation<SaveAccountAndTanksOperation>()
.AddOperation<BuildAccountInfoResponseOperation>()
; ;
var firstOperation = pipeline.Build(); var firstOperation = pipeline.Build();
@@ -95,7 +95,7 @@ namespace WotBlitzStatisticsPro.Logic
throw; throw;
} }
return contextData?.Response ?? new AccountInfoResponse(); return contextData?.AccountInfo?.LastBattleTime.ToDateTime() ?? new DateTime(1970,1,1);
} }
public async Task<AccountInfoHistoryResponse> GetAccountInfoHistory(RealmType realm, long accountId, DateTime startDate, RequestLanguage requestLanguage) public async Task<AccountInfoHistoryResponse> GetAccountInfoHistory(RealmType realm, long accountId, DateTime startDate, RequestLanguage requestLanguage)
@@ -7,6 +7,7 @@ using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.DataAccess; using WotBlitzStatisticsPro.DataAccess;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
using WotBlitzStatisticsPro.Logic.Dictionaries; using WotBlitzStatisticsPro.Logic.Dictionaries;
using WotBlitzStatisticsPro.Logic.Model;
using WotBlitzStatisticsPro.Logic.Pipeline; using WotBlitzStatisticsPro.Logic.Pipeline;
using WotBlitzStatisticsPro.WgApiClient; using WotBlitzStatisticsPro.WgApiClient;
@@ -19,6 +20,7 @@ namespace WotBlitzStatisticsPro.Logic
public static void ConfigureServices(IServiceCollection services) public static void ConfigureServices(IServiceCollection services)
{ {
services.AddSingleton<StatisticsCache>();
ConfigureDictionariesFactory(services); ConfigureDictionariesFactory(services);
ConfigureOperationsFactory(services); ConfigureOperationsFactory(services);
WotBlitzStatisticsDataAccessInstaller.ConfigureServices(services); WotBlitzStatisticsDataAccessInstaller.ConfigureServices(services);
@@ -9,6 +9,7 @@ using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
using WotBlitzStatisticsPro.Logic.Model;
namespace WotBlitzStatisticsPro.Tests.OperationStepsTests namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
{ {
@@ -17,16 +18,19 @@ namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
{ {
private GetAccountInfoOperation _operation; private GetAccountInfoOperation _operation;
private AccountInformationPipelineContextData _contextData; private AccountInformationPipelineContextData _contextData;
private StatisticsCache _cache;
[SetUp] [SetUp]
public void Init() public void Init()
{ {
InitAutoMapper(); InitAutoMapper();
InitWgApiClient(); InitWgApiClient();
_cache = new StatisticsCache();
_operation = new GetAccountInfoOperation( _operation = new GetAccountInfoOperation(
WargamingApiClient, WargamingApiClient,
Mapper, Mapper,
(new Mock<ILogger<GetAccountInfoOperation>>()).Object); (new Mock<ILogger<GetAccountInfoOperation>>()).Object,
_cache);
_contextData = new AccountInformationPipelineContextData(); _contextData = new AccountInformationPipelineContextData();
} }
@@ -51,6 +55,21 @@ namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
var expectedAccountInfoHistory = var expectedAccountInfoHistory =
await File.ReadAllTextAsync(GetFixturePath("MappedAccountHistory.json")); await File.ReadAllTextAsync(GetFixturePath("MappedAccountHistory.json"));
accountInfoHistorySerialized.Should().Be(expectedAccountInfoHistory); accountInfoHistorySerialized.Should().Be(expectedAccountInfoHistory);
// ToDo: Check cache
Assert.Fail("Implement test");
}
[Test]
public async Task ShouldGetAndSaveAccountInfoInformationIfCacheExpired()
{
Assert.Fail("Implement test");
}
[Test]
public async Task ShouldReadDataFromCacheIfItIsNotEmpty()
{
Assert.Fail("Implement test");
} }
} }
} }
@@ -8,6 +8,7 @@ using NUnit.Framework;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.OperationContext;
using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations; using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
using WotBlitzStatisticsPro.Logic.Model;
namespace WotBlitzStatisticsPro.Tests.OperationStepsTests namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
{ {
@@ -16,16 +17,21 @@ namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
{ {
private GetTanksInfoOperation _operation; private GetTanksInfoOperation _operation;
private AccountInformationPipelineContextData _contextData; private AccountInformationPipelineContextData _contextData;
private StatisticsCache _cache;
[SetUp] [SetUp]
public void Init() public void Init()
{ {
InitAutoMapper(); InitAutoMapper();
InitWgApiClient(); InitWgApiClient();
_cache = new StatisticsCache();
_operation = new GetTanksInfoOperation( _operation = new GetTanksInfoOperation(
WargamingTanksApiClient, WargamingTanksApiClient,
Mapper, Mapper,
(new Mock<ILogger<GetTanksInfoOperation>>()).Object); (new Mock<ILogger<GetTanksInfoOperation>>()).Object,
_cache);
_contextData = new AccountInformationPipelineContextData(); _contextData = new AccountInformationPipelineContextData();
} }
@@ -50,6 +56,21 @@ namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
var expectedTanksHistory = var expectedTanksHistory =
await File.ReadAllTextAsync(GetFixturePath("MappedTanksHistory.json")); await File.ReadAllTextAsync(GetFixturePath("MappedTanksHistory.json"));
tanksHistorySerialized.Should().Be(expectedTanksHistory); tanksHistorySerialized.Should().Be(expectedTanksHistory);
// ToDo: Check cache
Assert.Fail("Implement test");
}
[Test]
public async Task ShouldGetAndSaveTankInfoInformationIfCacheExpired()
{
Assert.Fail("Implement test");
}
[Test]
public async Task ShouldReadDataFromCacheIfItIsNotEmpty()
{
Assert.Fail("Implement test");
} }
} }
@@ -7,6 +7,7 @@ using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper; using AutoMapper;
using Microsoft.Extensions.Logging;
using Moq; using Moq;
using Moq.Protected; using Moq.Protected;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -97,7 +98,10 @@ namespace WotBlitzStatisticsPro.Tests.OperationStepsTests
ItExpr.IsAny<CancellationToken>()) ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(tanksInfoResponse); .ReturnsAsync(tanksInfoResponse);
var client = new WargamingApiClient(new HttpClient(handlerMock.Object), settingsMock.Object); var client = new WargamingApiClient(
new HttpClient(handlerMock.Object),
settingsMock.Object,
(new Mock<ILogger<WagramingApiClientBase>>()).Object);
WargamingApiClient = client; WargamingApiClient = client;
WargamingTanksApiClient = client; WargamingTanksApiClient = client;
} }
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.Common; using WotBlitzStatisticsPro.Common;
using WotBlitzStatisticsPro.Common.Model; using WotBlitzStatisticsPro.Common.Model;
@@ -19,14 +20,17 @@ namespace WotBlitzStatisticsPro.WgApiClient
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly IWargamingApiSettings _wargamingApiSettings; private readonly IWargamingApiSettings _wargamingApiSettings;
private readonly ILogger<WagramingApiClientBase> _logger;
public WagramingApiClientBase( public WagramingApiClientBase(
HttpClient httpClient, HttpClient httpClient,
IWargamingApiSettings wargamingApiSettings) IWargamingApiSettings wargamingApiSettings,
ILogger<WagramingApiClientBase> logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_wargamingApiSettings = wargamingApiSettings; _wargamingApiSettings = wargamingApiSettings;
_blitzApiUrls[RealmType.Eu] = "https://api.wotblitz.eu/wotb/"; _logger = logger;
_blitzApiUrls[RealmType.Eu] = "https://api.wotblitz.eu/wotb/";
_blitzApiUrls[RealmType.Ru] = "https://api.wotblitz.ru/wotb/"; _blitzApiUrls[RealmType.Ru] = "https://api.wotblitz.ru/wotb/";
_blitzApiUrls[RealmType.Na] = "https://api.wotblitz.com/wotb/"; _blitzApiUrls[RealmType.Na] = "https://api.wotblitz.com/wotb/";
_blitzApiUrls[RealmType.Asia] = "https://api.wotblitz.asia/wotb/"; _blitzApiUrls[RealmType.Asia] = "https://api.wotblitz.asia/wotb/";
@@ -53,6 +57,9 @@ namespace WotBlitzStatisticsPro.WgApiClient
var responseString = await response.Content.ReadAsStringAsync(); var responseString = await response.Content.ReadAsStringAsync();
var responseBody = JsonConvert.DeserializeObject<ResponseBody<T>>(responseString); var responseBody = JsonConvert.DeserializeObject<ResponseBody<T>>(responseString);
_logger.LogInformation($"HTTP GET {uri} - {responseBody.Status}");
switch (responseBody.Status) switch (responseBody.Status)
{ {
case "ok": case "ok":
@@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.Common; using WotBlitzStatisticsPro.Common;
using WotBlitzStatisticsPro.Common.Model; using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.WgApiClient.Model; using WotBlitzStatisticsPro.WgApiClient.Model;
@@ -10,7 +11,10 @@ namespace WotBlitzStatisticsPro.WgApiClient
public class WargamingAchievementsApiClient: WagramingApiClientBase, public class WargamingAchievementsApiClient: WagramingApiClientBase,
IWargamingAchievementsApiClient IWargamingAchievementsApiClient
{ {
public WargamingAchievementsApiClient(HttpClient httpClient, IWargamingApiSettings wargamingApiSettings) : base(httpClient, wargamingApiSettings) public WargamingAchievementsApiClient(
HttpClient httpClient,
IWargamingApiSettings wargamingApiSettings,
ILogger<WagramingApiClientBase> logger) : base(httpClient, wargamingApiSettings, logger)
{ {
} }
@@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using WotBlitzStatisticsPro.Common; using WotBlitzStatisticsPro.Common;
using WotBlitzStatisticsPro.Common.Model; using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.WgApiClient.Model; using WotBlitzStatisticsPro.WgApiClient.Model;
@@ -15,7 +16,8 @@ namespace WotBlitzStatisticsPro.WgApiClient
{ {
public WargamingApiClient( public WargamingApiClient(
HttpClient httpClient, HttpClient httpClient,
IWargamingApiSettings wargamingApiSettings) : base(httpClient, wargamingApiSettings) IWargamingApiSettings wargamingApiSettings,
ILogger<WagramingApiClientBase> logger) : base(httpClient, wargamingApiSettings, logger)
{ {
} }
@@ -6,6 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup> </ItemGroup>