mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-12 02:08:27 -04:00
- creds.yml now loads and reloads properly (from the current directory, like credentials.json) - added empty creds.yml to repo, and added it to .gitignore
215 lines
7.1 KiB
C#
215 lines
7.1 KiB
C#
using NadekoBot.Extensions;
|
|
using Newtonsoft.Json;
|
|
using StackExchange.Redis;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using Discord;
|
|
using Discord.WebSocket;
|
|
|
|
namespace NadekoBot.Services
|
|
{
|
|
public class RedisCache : IDataCache
|
|
{
|
|
public ConnectionMultiplexer Redis { get; }
|
|
|
|
public IImageCache LocalImages { get; }
|
|
public ILocalDataCache LocalData { get; }
|
|
|
|
private readonly string _redisKey;
|
|
private readonly EndPoint _redisEndpoint;
|
|
|
|
public RedisCache(ConnectionMultiplexer redis, IBotCredentials creds, DiscordSocketClient client)
|
|
{
|
|
Redis = redis;
|
|
_redisEndpoint = Redis.GetEndPoints().First();
|
|
LocalImages = new RedisImagesCache(Redis, creds);
|
|
LocalData = new RedisLocalDataCache(Redis, creds, client.ShardId);
|
|
_redisKey = creds.RedisKey();
|
|
}
|
|
|
|
// things here so far don't need the bot id
|
|
// because it's a good thing if different bots
|
|
// which are hosted on the same PC
|
|
// can re-use the same image/anime data
|
|
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(Uri key)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
byte[] x = await _db.StringGetAsync("image_" + key).ConfigureAwait(false);
|
|
return (x != null, x);
|
|
}
|
|
|
|
public Task SetImageDataAsync(Uri key, byte[] data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
return _db.StringSetAsync("image_" + key, data);
|
|
}
|
|
|
|
public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
string x = await _db.StringGetAsync("anime_" + key).ConfigureAwait(false);
|
|
return (x != null, x);
|
|
}
|
|
|
|
public Task SetAnimeDataAsync(string key, string data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
return _db.StringSetAsync("anime_" + key, data, expiry: TimeSpan.FromHours(3));
|
|
}
|
|
|
|
public async Task<(bool Success, string Data)> TryGetNovelDataAsync(string key)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
string x = await _db.StringGetAsync("novel_" + key).ConfigureAwait(false);
|
|
return (x != null, x);
|
|
}
|
|
|
|
public Task SetNovelDataAsync(string key, string data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
return _db.StringSetAsync("novel_" + key, data, expiry: TimeSpan.FromHours(3));
|
|
}
|
|
|
|
private readonly object timelyLock = new object();
|
|
public TimeSpan? AddTimelyClaim(ulong id, int period)
|
|
{
|
|
if (period == 0)
|
|
return null;
|
|
lock (timelyLock)
|
|
{
|
|
var time = TimeSpan.FromHours(period);
|
|
var _db = Redis.GetDatabase();
|
|
if ((bool?)_db.StringGet($"{_redisKey}_timelyclaim_{id}") is null)
|
|
{
|
|
_db.StringSet($"{_redisKey}_timelyclaim_{id}", true, time);
|
|
return null;
|
|
}
|
|
return _db.KeyTimeToLive($"{_redisKey}_timelyclaim_{id}");
|
|
}
|
|
}
|
|
|
|
public void RemoveAllTimelyClaims()
|
|
{
|
|
var server = Redis.GetServer(_redisEndpoint);
|
|
var _db = Redis.GetDatabase();
|
|
foreach (var k in server.Keys(pattern: $"{_redisKey}_timelyclaim_*"))
|
|
{
|
|
_db.KeyDelete(k, CommandFlags.FireAndForget);
|
|
}
|
|
}
|
|
|
|
public bool TryAddAffinityCooldown(ulong userId, out TimeSpan? time)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
time = _db.KeyTimeToLive($"{_redisKey}_affinity_{userId}");
|
|
if (time is null)
|
|
{
|
|
time = TimeSpan.FromMinutes(30);
|
|
_db.StringSet($"{_redisKey}_affinity_{userId}", true, time);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool TryAddDivorceCooldown(ulong userId, out TimeSpan? time)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
time = _db.KeyTimeToLive($"{_redisKey}_divorce_{userId}");
|
|
if (time is null)
|
|
{
|
|
time = TimeSpan.FromHours(6);
|
|
_db.StringSet($"{_redisKey}_divorce_{userId}", true, time);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public Task SetStreamDataAsync(string url, string data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
return _db.StringSetAsync($"{_redisKey}_stream_{url}", data, expiry: TimeSpan.FromHours(6));
|
|
}
|
|
|
|
public bool TryGetStreamData(string url, out string dataStr)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
dataStr = _db.StringGet($"{_redisKey}_stream_{url}");
|
|
|
|
return !string.IsNullOrWhiteSpace(dataStr);
|
|
}
|
|
|
|
public TimeSpan? TryAddRatelimit(ulong id, string name, int expireIn)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
if (_db.StringSet($"{_redisKey}_ratelimit_{id}_{name}",
|
|
0, // i don't use the value
|
|
TimeSpan.FromSeconds(expireIn),
|
|
When.NotExists))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _db.KeyTimeToLive($"{_redisKey}_ratelimit_{id}_{name}");
|
|
}
|
|
|
|
public bool TryGetEconomy(out string data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
if ((data = _db.StringGet($"{_redisKey}_economy")) != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void SetEconomy(string data)
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
_db.StringSet($"{_redisKey}_economy",
|
|
data,
|
|
expiry: TimeSpan.FromMinutes(3));
|
|
}
|
|
|
|
public async Task<TOut> GetOrAddCachedDataAsync<TParam, TOut>(string key, Func<TParam, Task<TOut>> factory, TParam param, TimeSpan expiry) where TOut : class
|
|
{
|
|
var _db = Redis.GetDatabase();
|
|
|
|
RedisValue data = await _db.StringGetAsync(key).ConfigureAwait(false);
|
|
if (!data.HasValue)
|
|
{
|
|
var obj = await factory(param).ConfigureAwait(false);
|
|
|
|
if (obj is null)
|
|
return default(TOut);
|
|
|
|
await _db.StringSetAsync(key, JsonConvert.SerializeObject(obj),
|
|
expiry: expiry).ConfigureAwait(false);
|
|
|
|
return obj;
|
|
}
|
|
return (TOut)JsonConvert.DeserializeObject(data, typeof(TOut));
|
|
}
|
|
|
|
public DateTime GetLastCurrencyDecay()
|
|
{
|
|
var db = Redis.GetDatabase();
|
|
|
|
var str = (string)db.StringGet($"{_redisKey}_last_currency_decay");
|
|
if(string.IsNullOrEmpty(str))
|
|
return DateTime.MinValue;
|
|
|
|
return JsonConvert.DeserializeObject<DateTime>(str);
|
|
}
|
|
|
|
public void SetLastCurrencyDecay()
|
|
{
|
|
var db = Redis.GetDatabase();
|
|
|
|
db.StringSet($"{_redisKey}_last_currency_decay", JsonConvert.SerializeObject(DateTime.UtcNow));
|
|
}
|
|
}
|
|
}
|