Abstract away cache. 2 implementations: redis and memory

This commit is contained in:
Kwoth
2022-06-23 13:07:45 +00:00
parent 1716c69132
commit 210da263ad
75 changed files with 11525 additions and 1547 deletions

View File

@@ -31,9 +31,10 @@ public sealed class PatronageService
private readonly DiscordSocketClient _client;
private readonly ISubscriptionHandler _subsHandler;
private readonly IEmbedBuilderService _eb;
private readonly ConnectionMultiplexer _redis;
private readonly IBotCredentials _creds;
private readonly TypedKey<bool> _quotaKey;
private static readonly TypedKey<long> _quotaKey
= new($"quota:last_hourly_reset");
private readonly IBotCache _cache;
public PatronageService(
PatronageConfig pConf,
@@ -41,18 +42,14 @@ public sealed class PatronageService
DiscordSocketClient client,
ISubscriptionHandler subsHandler,
IEmbedBuilderService eb,
ConnectionMultiplexer redis,
IBotCredentials creds)
IBotCache cache)
{
_pConf = pConf;
_db = db;
_client = client;
_subsHandler = subsHandler;
_eb = eb;
_redis = redis;
_creds = creds;
_quotaKey = new TypedKey<bool>($"{_creds.RedisKey()}:quota:last_hourly_reset");
_cache = cache;
}
public Task OnReadyAsync()
@@ -101,11 +98,10 @@ public sealed class PatronageService
var now = DateTime.UtcNow;
var lastRun = DateTime.MinValue;
var rdb = _redis.GetDatabase();
var lastVal = await rdb.StringGetAsync(_quotaKey.Key);
if (lastVal != default)
var result = await _cache.GetAsync(_quotaKey);
if (result.TryGetValue(out var lastVal) && lastVal != default)
{
lastRun = DateTime.FromBinary((long)lastVal);
lastRun = DateTime.FromBinary(lastVal);
}
var nowDate = now.ToDateOnly();
@@ -130,8 +126,6 @@ public sealed class PatronageService
HourlyCount = 0,
DailyCount = 0,
});
await rdb.StringSetAsync(_quotaKey.Key, true);
}
else if (now.Hour != lastRun.Hour) // if it's not, just reset hourly quotas
{
@@ -143,7 +137,7 @@ public sealed class PatronageService
}
// assumes that the code above runs in less than an hour
await rdb.StringSetAsync(_quotaKey.Key, now.ToBinary());
await _cache.AddAsync(_quotaKey, now.ToBinary());
await tran.CommitAsync();
}
catch (Exception ex)

View File

@@ -1,23 +1,24 @@
#nullable disable
using NadekoBot.Common.ModuleBehaviors;
using NadekoBot.Modules.Utility.Common;
using Newtonsoft.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Utility.Services;
public class ConverterService : INService, IReadyExecutor
{
public ConvertUnit[] Units
=> _cache.Redis.GetDatabase().StringGet("converter_units").ToString().MapJson<ConvertUnit[]>();
private static readonly TypedKey<List<ConvertUnit>> _convertKey =
new("convert:units");
private readonly TimeSpan _updateInterval = new(12, 0, 0);
private readonly DiscordSocketClient _client;
private readonly IDataCache _cache;
private readonly IBotCache _cache;
private readonly IHttpClientFactory _httpFactory;
public ConverterService(
DiscordSocketClient client,
IDataCache cache,
IBotCache cache,
IHttpClientFactory factory)
{
_client = client;
@@ -48,7 +49,7 @@ public class ConverterService : INService, IReadyExecutor
{
using var http = _httpFactory.CreateClient();
var res = await http.GetStringAsync("https://convertapi.nadeko.bot/latest");
return JsonConvert.DeserializeObject<Rates>(res);
return JsonSerializer.Deserialize<Rates>(res);
}
private async Task UpdateCurrency()
@@ -61,29 +62,38 @@ public class ConverterService : INService, IReadyExecutor
Modifier = decimal.One,
UnitType = unitTypeString
};
var range = currencyRates.ConversionRates.Select(u => new ConvertUnit
var units = currencyRates.ConversionRates.Select(u => new ConvertUnit
{
Triggers = new[] { u.Key },
Modifier = u.Value,
UnitType = unitTypeString
})
.ToArray();
.ToList();
var fileData = JsonConvert.DeserializeObject<ConvertUnit[]>(File.ReadAllText("data/units.json"))
?.Where(x => x.UnitType != "currency");
if (fileData is null)
return;
var data = JsonConvert.SerializeObject(range.Append(baseType).Concat(fileData).ToList());
_cache.Redis.GetDatabase().StringSet("converter_units", data);
var stream = File.OpenRead("data/units.json");
var defaultUnits = await JsonSerializer.DeserializeAsync<ConvertUnit[]>(stream);
if(defaultUnits is not null)
units.AddRange(defaultUnits);
units.Add(baseType);
await _cache.AddAsync(_convertKey, units);
}
public async Task<IReadOnlyList<ConvertUnit>> GetUnitsAsync()
=> (await _cache.GetAsync(_convertKey)).TryGetValue(out var list)
? list
: Array.Empty<ConvertUnit>();
}
public class Rates
{
[JsonPropertyName("base")]
public string Base { get; set; }
[JsonPropertyName("date")]
public DateTime Date { get; set; }
[JsonProperty("rates")]
[JsonPropertyName("rates")]
public Dictionary<string, decimal> ConversionRates { get; set; }
}

View File

@@ -11,7 +11,7 @@ public partial class Utility
[Cmd]
public async partial Task ConvertList()
{
var units = _service.Units;
var units = await _service.GetUnitsAsync();
var embed = _eb.Create().WithTitle(GetText(strs.convertlist)).WithOkColor();
@@ -29,9 +29,10 @@ public partial class Utility
[Priority(0)]
public async partial Task Convert(string origin, string target, decimal value)
{
var originUnit = _service.Units.FirstOrDefault(x
var units = await _service.GetUnitsAsync();
var originUnit = units.FirstOrDefault(x
=> x.Triggers.Select(y => y.ToUpperInvariant()).Contains(origin.ToUpperInvariant()));
var targetUnit = _service.Units.FirstOrDefault(x
var targetUnit = units.FirstOrDefault(x
=> x.Triggers.Select(y => y.ToUpperInvariant()).Contains(target.ToUpperInvariant()));
if (originUnit is null || targetUnit is null)
{