From 2aead404494981fdfa601b7b86d28768be43e4c8 Mon Sep 17 00:00:00 2001 From: spiral Date: Thu, 13 Jan 2022 12:26:25 -0500 Subject: [PATCH] feat: add Redis identify ratelimiter --- Myriad/Gateway/Cluster.cs | 23 ++- Myriad/Gateway/GatewaySettings.cs | 1 + Myriad/Gateway/Limit/RedisRatelimiter.cs | 46 ++++++ Myriad/Myriad.csproj | 1 + Myriad/packages.lock.json | 163 ++++++++++++++++++---- PluralKit.Bot/BotConfig.cs | 1 + PluralKit.Bot/Init.cs | 11 +- PluralKit.Bot/Modules.cs | 1 + PluralKit.Bot/packages.lock.json | 109 ++++++++++++++- PluralKit.Core/CoreConfig.cs | 1 + PluralKit.Core/Modules/DataStoreModule.cs | 2 + PluralKit.Core/PluralKit.Core.csproj | 3 +- PluralKit.Core/Services/RedisService.cs | 14 ++ PluralKit.Core/packages.lock.json | 108 +++++++++++++- docker-compose.yml | 5 + 15 files changed, 449 insertions(+), 40 deletions(-) create mode 100644 Myriad/Gateway/Limit/RedisRatelimiter.cs create mode 100644 PluralKit.Core/Services/RedisService.cs diff --git a/Myriad/Gateway/Cluster.cs b/Myriad/Gateway/Cluster.cs index 8575b123..42916f7d 100644 --- a/Myriad/Gateway/Cluster.cs +++ b/Myriad/Gateway/Cluster.cs @@ -5,6 +5,8 @@ using Myriad.Types; using Serilog; +using StackExchange.Redis; + namespace Myriad.Gateway; public class Cluster @@ -25,14 +27,14 @@ public class Cluster public IReadOnlyDictionary Shards => _shards; public event Action? ShardCreated; - public async Task Start(GatewayInfo.Bot info) + public async Task Start(GatewayInfo.Bot info, ConnectionMultiplexer? conn = null) { - await Start(info.Url, 0, info.Shards - 1, info.Shards, info.SessionStartLimit.MaxConcurrency); + await Start(info.Url, 0, info.Shards - 1, info.Shards, info.SessionStartLimit.MaxConcurrency, conn); } - public async Task Start(string url, int shardMin, int shardMax, int shardTotal, int recommendedConcurrency) + public async Task Start(string url, int shardMin, int shardMax, int shardTotal, int recommendedConcurrency, ConnectionMultiplexer? conn = null) { - _ratelimiter = GetRateLimiter(recommendedConcurrency); + _ratelimiter = GetRateLimiter(recommendedConcurrency, conn); var shardCount = shardMax - shardMin + 1; _logger.Information("Starting {ShardCount} of {ShardTotal} shards (#{ShardMin}-#{ShardMax}) at {Url}", @@ -73,12 +75,21 @@ public class Cluster return Math.Min(_gatewaySettings.MaxShardConcurrency.Value, recommendedConcurrency); } - private IGatewayRatelimiter GetRateLimiter(int recommendedConcurrency) + private IGatewayRatelimiter GetRateLimiter(int recommendedConcurrency, ConnectionMultiplexer? conn = null) { + var concurrency = GetActualShardConcurrency(recommendedConcurrency); + + if (_gatewaySettings.UseRedisRatelimiter) + { + if (conn != null) + return new RedisRatelimiter(_logger, conn, concurrency); + else + _logger.Warning("Tried to get Redis ratelimiter but connection is null! Continuing with local ratelimiter."); + } + if (_gatewaySettings.GatewayQueueUrl != null) return new TwilightGatewayRatelimiter(_logger, _gatewaySettings.GatewayQueueUrl); - var concurrency = GetActualShardConcurrency(recommendedConcurrency); return new LocalGatewayRatelimiter(_logger, concurrency); } } \ No newline at end of file diff --git a/Myriad/Gateway/GatewaySettings.cs b/Myriad/Gateway/GatewaySettings.cs index f29e2321..d4156e20 100644 --- a/Myriad/Gateway/GatewaySettings.cs +++ b/Myriad/Gateway/GatewaySettings.cs @@ -4,6 +4,7 @@ public record GatewaySettings { public string Token { get; init; } public GatewayIntent Intents { get; init; } + public bool UseRedisRatelimiter { get; init; } = false; public int? MaxShardConcurrency { get; init; } public string? GatewayQueueUrl { get; init; } } \ No newline at end of file diff --git a/Myriad/Gateway/Limit/RedisRatelimiter.cs b/Myriad/Gateway/Limit/RedisRatelimiter.cs new file mode 100644 index 00000000..ab50f287 --- /dev/null +++ b/Myriad/Gateway/Limit/RedisRatelimiter.cs @@ -0,0 +1,46 @@ +using Serilog; + +using StackExchange.Redis; + +namespace Myriad.Gateway.Limit; + +public class RedisRatelimiter: IGatewayRatelimiter +{ + private readonly ILogger _logger; + private readonly ConnectionMultiplexer _redis; + + private int _concurrency { get; init; } + + // todo: these might need to be tweaked a little + private static TimeSpan expiry = TimeSpan.FromSeconds(5); + private static TimeSpan retryInterval = TimeSpan.FromSeconds(1); + + public RedisRatelimiter(ILogger logger, ConnectionMultiplexer redis, int concurrency) + { + _logger = logger.ForContext(); + _redis = redis; + _concurrency = concurrency; + } + + public async Task Identify(int shard) + { + _logger.Information("Shard {ShardId}: requesting identify from Redis", shard); + var key = "pluralkit:identify:" + (shard % _concurrency).ToString(); + await AcquireLock(key); + } + + public async Task AcquireLock(string key) + { + var conn = _redis.GetDatabase(); + + async Task TryAcquire() + { + _logger.Verbose("Trying to acquire lock on key {key} from Redis...", key); + await Task.Delay(retryInterval); + return await conn!.StringSetAsync(key, 0, expiry, When.NotExists); + } + + var acquired = false; + while (!acquired) acquired = await TryAcquire(); + } +} \ No newline at end of file diff --git a/Myriad/Myriad.csproj b/Myriad/Myriad.csproj index 89ad23c5..9302dc8b 100644 --- a/Myriad/Myriad.csproj +++ b/Myriad/Myriad.csproj @@ -24,6 +24,7 @@ + diff --git a/Myriad/packages.lock.json b/Myriad/packages.lock.json index 37b0efbe..76d05ffc 100644 --- a/Myriad/packages.lock.json +++ b/Myriad/packages.lock.json @@ -1,31 +1,140 @@ { - "version": 1, - "dependencies": { - "net6.0": { - "Polly": { - "type": "Direct", - "requested": "[7.2.1, )", - "resolved": "7.2.1", - "contentHash": "Od8SnPlpQr+PuAS0YzY3jgtzaDNknlIuAaldN2VEIyTvm/wCg22C5nUkUV1BEG8rIsub5RFMoV/NEQ0tM/+7Uw==" - }, - "Polly.Contrib.WaitAndRetry": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA==" - }, - "Serilog": { - "type": "Direct", - "requested": "[2.10.0, )", - "resolved": "2.10.0", - "contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA==" - }, - "System.Linq.Async": { - "type": "Direct", - "requested": "[5.0.0, )", - "resolved": "5.0.0", - "contentHash": "cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==" - } + "version": 1, + "dependencies": { + "net6.0": { + "Polly": { + "type": "Direct", + "requested": "[7.2.1, )", + "resolved": "7.2.1", + "contentHash": "Od8SnPlpQr+PuAS0YzY3jgtzaDNknlIuAaldN2VEIyTvm/wCg22C5nUkUV1BEG8rIsub5RFMoV/NEQ0tM/+7Uw==" + }, + "Polly.Contrib.WaitAndRetry": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA==" + }, + "Serilog": { + "type": "Direct", + "requested": "[2.10.0, )", + "resolved": "2.10.0", + "contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA==" + }, + "StackExchange.Redis": { + "type": "Direct", + "requested": "[2.2.88, )", + "resolved": "2.2.88", + "contentHash": "JJi1jcO3/ZiamBhlsC/TR8aZmYf+nqpGzMi0HRRCy5wJkUPmMnRp0kBA6V84uhU8b531FHSdTDaFCAyCUJomjA==", + "dependencies": { + "Pipelines.Sockets.Unofficial": "2.2.0", + "System.Diagnostics.PerformanceCounter": "5.0.0" } + }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "Bh6blKG8VAKvXiLe2L+sEsn62nc1Ij34MrNxepD2OCrS5cpCwQa9MeLyhVQPQ/R4Wlzwuy6wMK8hLb11QPDRsQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0" + } + }, + "Pipelines.Sockets.Unofficial": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "7hzHplEIVOGBl5zOQZGX/DiJDHjq+RVRVrYgDiqXb6RriqWAdacXxp+XO9WSrATCEXyNOUOQg9aqQArsjase/A==", + "dependencies": { + "System.IO.Pipelines": "5.0.0" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "aM7cbfEfVNlEEOj3DsZP+2g9NRwbkyiAv2isQEzw7pnkDg9ekCU2m1cdJLM02Uq691OaCS91tooaxcEn8d0q5w==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "5.0.0", + "System.Security.Permissions": "5.0.0" + } + }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "kcQWWtGVC3MWMNXdMDWfrmIlFZZ2OdoeT6pSNVRtk9+Sa7jwdPiMlNwb0ZQcS7NRlT92pCfmjRtkSWUW3RAKwg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "Microsoft.Win32.Registry": "5.0.0", + "System.Configuration.ConfigurationManager": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SztFwAnpfKC8+sEKXAFxCBWhKQaEd97EiOL7oZJZP56zbqnLpmxACWA8aGseaUExciuEAUuR9dY8f7HkTRAdnw==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "5.0.0" + } + }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "irMYm3vhVgRsYvHTU5b2gsT2CwT/SMM6LZFzuJjpIvT5Z4CshxNsaoBC1X/LltwuR3Opp8d6jOS/60WwOb7Q2Q==" + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "HGxMSAFAPLNoxBvSfW08vHde0F9uh7BjASwu6JF9JnXuEPhCY3YUqURn0+bQV/4UWeaqymmrHWV+Aw9riQCtCA==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "uE8juAhEkp7KDBCdjDIE3H9R1HJuEHqeqX8nLX9gmYKWwsqk3T5qZlPx8qle5DPKimC/Fy3AFTdV7HamgCh9qQ==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Windows.Extensions": "5.0.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "c1ho9WU9ZxMZawML+ssPKZfdnrg/OjR3pe0m9v8230z3acqphwvPJqzAkH54xRYm5ntZHGG1EPP3sux9H3qSPg==", + "dependencies": { + "System.Drawing.Common": "5.0.0" + } + } } + } } \ No newline at end of file diff --git a/PluralKit.Bot/BotConfig.cs b/PluralKit.Bot/BotConfig.cs index 7fc32232..19d9316d 100644 --- a/PluralKit.Bot/BotConfig.cs +++ b/PluralKit.Bot/BotConfig.cs @@ -19,6 +19,7 @@ public class BotConfig public ClusterSettings? Cluster { get; set; } public string? GatewayQueueUrl { get; set; } + public bool UseRedisRatelimiter { get; set; } = false; public string? DiscordBaseUrl { get; set; } diff --git a/PluralKit.Bot/Init.cs b/PluralKit.Bot/Init.cs index b95d56d5..aa866a4c 100644 --- a/PluralKit.Bot/Init.cs +++ b/PluralKit.Bot/Init.cs @@ -42,6 +42,11 @@ public class Init opts.DisableTaskUnobservedTaskExceptionCapture(); }); + // initialize Redis + var coreConfig = services.Resolve(); + var redis = services.Resolve(); + await redis.InitAsync(coreConfig); + var config = services.Resolve(); if (config.Cluster == null) { @@ -141,6 +146,8 @@ public class Init { var info = await services.Resolve().GetGatewayBot(); + var redis = services.Resolve(); + var cluster = services.Resolve(); var config = services.Resolve(); @@ -155,11 +162,11 @@ public class Init var shardMin = (int)Math.Round(totalShards * (float)nodeIndex / totalNodes); var shardMax = (int)Math.Round(totalShards * (float)(nodeIndex + 1) / totalNodes) - 1; - await cluster.Start(info.Url, shardMin, shardMax, totalShards, info.SessionStartLimit.MaxConcurrency); + await cluster.Start(info.Url, shardMin, shardMax, totalShards, info.SessionStartLimit.MaxConcurrency, redis.Connection); } else { - await cluster.Start(info); + await cluster.Start(info, redis.Connection); } } } \ No newline at end of file diff --git a/PluralKit.Bot/Modules.cs b/PluralKit.Bot/Modules.cs index 50e4d454..60ed490c 100644 --- a/PluralKit.Bot/Modules.cs +++ b/PluralKit.Bot/Modules.cs @@ -31,6 +31,7 @@ public class BotModule: Module Token = botConfig.Token, MaxShardConcurrency = botConfig.MaxShardConcurrency, GatewayQueueUrl = botConfig.GatewayQueueUrl, + UseRedisRatelimiter = botConfig.UseRedisRatelimiter, Intents = GatewayIntent.Guilds | GatewayIntent.DirectMessages | GatewayIntent.DirectMessageReactions | diff --git a/PluralKit.Bot/packages.lock.json b/PluralKit.Bot/packages.lock.json index ca64e4c8..a0114f78 100644 --- a/PluralKit.Bot/packages.lock.json +++ b/PluralKit.Bot/packages.lock.json @@ -294,8 +294,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -312,6 +312,23 @@ "System.Runtime": "4.3.0" } }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "Bh6blKG8VAKvXiLe2L+sEsn62nc1Ij34MrNxepD2OCrS5cpCwQa9MeLyhVQPQ/R4Wlzwuy6wMK8hLb11QPDRsQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0" + } + }, "NETStandard.Library": { "type": "Transitive", "resolved": "1.6.1", @@ -402,6 +419,14 @@ "Npgsql": "4.1.5" } }, + "Pipelines.Sockets.Unofficial": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "7hzHplEIVOGBl5zOQZGX/DiJDHjq+RVRVrYgDiqXb6RriqWAdacXxp+XO9WSrATCEXyNOUOQg9aqQArsjase/A==", + "dependencies": { + "System.IO.Pipelines": "5.0.0" + } + }, "Polly": { "type": "Transitive", "resolved": "7.2.1", @@ -631,6 +656,15 @@ "dapper": "1.50.5" } }, + "StackExchange.Redis": { + "type": "Transitive", + "resolved": "2.2.88", + "contentHash": "JJi1jcO3/ZiamBhlsC/TR8aZmYf+nqpGzMi0HRRCy5wJkUPmMnRp0kBA6V84uhU8b531FHSdTDaFCAyCUJomjA==", + "dependencies": { + "Pipelines.Sockets.Unofficial": "2.2.0", + "System.Diagnostics.PerformanceCounter": "5.0.0" + } + }, "System.AppContext": { "type": "Transitive", "resolved": "4.3.0", @@ -671,6 +705,15 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "aM7cbfEfVNlEEOj3DsZP+2g9NRwbkyiAv2isQEzw7pnkDg9ekCU2m1cdJLM02Uq691OaCS91tooaxcEn8d0q5w==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "5.0.0", + "System.Security.Permissions": "5.0.0" + } + }, "System.Console": { "type": "Transitive", "resolved": "4.3.0", @@ -698,6 +741,17 @@ "resolved": "4.7.1", "contentHash": "j81Lovt90PDAq8kLpaJfJKV/rWdWuEk6jfV+MBkee33vzYLEUsy4gXK8laa9V2nZlLM9VM9yA/OOQxxPEJKAMw==" }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "kcQWWtGVC3MWMNXdMDWfrmIlFZZ2OdoeT6pSNVRtk9+Sa7jwdPiMlNwb0ZQcS7NRlT92pCfmjRtkSWUW3RAKwg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "Microsoft.Win32.Registry": "5.0.0", + "System.Configuration.ConfigurationManager": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Diagnostics.Tools": { "type": "Transitive", "resolved": "4.3.0", @@ -718,6 +772,14 @@ "System.Runtime": "4.3.0" } }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SztFwAnpfKC8+sEKXAFxCBWhKQaEd97EiOL7oZJZP56zbqnLpmxACWA8aGseaUExciuEAUuR9dY8f7HkTRAdnw==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "5.0.0" + } + }, "System.Globalization": { "type": "Transitive", "resolved": "4.3.0", @@ -833,6 +895,11 @@ "System.Runtime": "4.3.0" } }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "irMYm3vhVgRsYvHTU5b2gsT2CwT/SMM6LZFzuJjpIvT5Z4CshxNsaoBC1X/LltwuR3Opp8d6jOS/60WwOb7Q2Q==" + }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1089,6 +1156,15 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.Algorithms": { "type": "Transitive", "resolved": "4.3.0", @@ -1201,6 +1277,11 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "HGxMSAFAPLNoxBvSfW08vHde0F9uh7BjASwu6JF9JnXuEPhCY3YUqURn0+bQV/4UWeaqymmrHWV+Aw9riQCtCA==" + }, "System.Security.Cryptography.X509Certificates": { "type": "Transitive", "resolved": "4.3.0", @@ -1233,6 +1314,20 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "uE8juAhEkp7KDBCdjDIE3H9R1HJuEHqeqX8nLX9gmYKWwsqk3T5qZlPx8qle5DPKimC/Fy3AFTdV7HamgCh9qQ==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Windows.Extensions": "5.0.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, "System.Text.Encoding": { "type": "Transitive", "resolved": "4.3.0", @@ -1306,6 +1401,14 @@ "System.Runtime": "4.3.0" } }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "c1ho9WU9ZxMZawML+ssPKZfdnrg/OjR3pe0m9v8230z3acqphwvPJqzAkH54xRYm5ntZHGG1EPP3sux9H3qSPg==", + "dependencies": { + "System.Drawing.Common": "5.0.0" + } + }, "System.Xml.ReaderWriter": { "type": "Transitive", "resolved": "4.3.0", @@ -1353,6 +1456,7 @@ "Polly": "7.2.1", "Polly.Contrib.WaitAndRetry": "1.1.1", "Serilog": "2.10.0", + "StackExchange.Redis": "2.2.88", "System.Linq.Async": "5.0.0" } }, @@ -1388,6 +1492,7 @@ "Serilog.Sinks.File": "4.1.0", "SqlKata": "2.3.7", "SqlKata.Execution": "2.3.7", + "StackExchange.Redis": "2.2.88", "System.Interactive.Async": "5.0.0", "ipnetwork2": "2.5.381" } diff --git a/PluralKit.Core/CoreConfig.cs b/PluralKit.Core/CoreConfig.cs index e74aa589..7623005d 100644 --- a/PluralKit.Core/CoreConfig.cs +++ b/PluralKit.Core/CoreConfig.cs @@ -5,6 +5,7 @@ namespace PluralKit.Core; public class CoreConfig { public string Database { get; set; } + public string RedisAddr { get; set; } public string SentryUrl { get; set; } public string InfluxUrl { get; set; } public string InfluxDb { get; set; } diff --git a/PluralKit.Core/Modules/DataStoreModule.cs b/PluralKit.Core/Modules/DataStoreModule.cs index d7b99d00..e6ecdcd5 100644 --- a/PluralKit.Core/Modules/DataStoreModule.cs +++ b/PluralKit.Core/Modules/DataStoreModule.cs @@ -14,6 +14,8 @@ public class DataStoreModule: Module builder.RegisterType().As().SingleInstance(); builder.RegisterType().AsSelf().SingleInstance(); + builder.RegisterType().AsSelf().SingleInstance(); + builder.RegisterType().AsSelf().SingleInstance(); builder.Populate(new ServiceCollection().AddMemoryCache()); diff --git a/PluralKit.Core/PluralKit.Core.csproj b/PluralKit.Core/PluralKit.Core.csproj index c2335dac..a5a5ea70 100644 --- a/PluralKit.Core/PluralKit.Core.csproj +++ b/PluralKit.Core/PluralKit.Core.csproj @@ -46,6 +46,7 @@ + @@ -54,7 +55,7 @@ - + diff --git a/PluralKit.Core/Services/RedisService.cs b/PluralKit.Core/Services/RedisService.cs new file mode 100644 index 00000000..c608cfed --- /dev/null +++ b/PluralKit.Core/Services/RedisService.cs @@ -0,0 +1,14 @@ +using StackExchange.Redis; + +namespace PluralKit.Core; + +public class RedisService +{ + public ConnectionMultiplexer Connection { get; set; } + + public async Task InitAsync(CoreConfig config) + { + if (config.RedisAddr != null) + Connection = await ConnectionMultiplexer.ConnectAsync(config.RedisAddr); + } +} \ No newline at end of file diff --git a/PluralKit.Core/packages.lock.json b/PluralKit.Core/packages.lock.json index 94fd7341..7f20b6d4 100644 --- a/PluralKit.Core/packages.lock.json +++ b/PluralKit.Core/packages.lock.json @@ -294,6 +294,16 @@ "dapper": "1.50.5" } }, + "StackExchange.Redis": { + "type": "Direct", + "requested": "[2.2.88, )", + "resolved": "2.2.88", + "contentHash": "JJi1jcO3/ZiamBhlsC/TR8aZmYf+nqpGzMi0HRRCy5wJkUPmMnRp0kBA6V84uhU8b531FHSdTDaFCAyCUJomjA==", + "dependencies": { + "Pipelines.Sockets.Unofficial": "2.2.0", + "System.Diagnostics.PerformanceCounter": "5.0.0" + } + }, "System.Interactive.Async": { "type": "Direct", "requested": "[5.0.0, )", @@ -453,8 +463,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -471,6 +481,23 @@ "System.Runtime": "4.3.0" } }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "Bh6blKG8VAKvXiLe2L+sEsn62nc1Ij34MrNxepD2OCrS5cpCwQa9MeLyhVQPQ/R4Wlzwuy6wMK8hLb11QPDRsQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0" + } + }, "NETStandard.Library": { "type": "Transitive", "resolved": "1.6.1", @@ -522,6 +549,14 @@ "System.Xml.XDocument": "4.3.0" } }, + "Pipelines.Sockets.Unofficial": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "7hzHplEIVOGBl5zOQZGX/DiJDHjq+RVRVrYgDiqXb6RriqWAdacXxp+XO9WSrATCEXyNOUOQg9aqQArsjase/A==", + "dependencies": { + "System.IO.Pipelines": "5.0.0" + } + }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { "type": "Transitive", "resolved": "4.3.0", @@ -687,6 +722,15 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "aM7cbfEfVNlEEOj3DsZP+2g9NRwbkyiAv2isQEzw7pnkDg9ekCU2m1cdJLM02Uq691OaCS91tooaxcEn8d0q5w==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "5.0.0", + "System.Security.Permissions": "5.0.0" + } + }, "System.Console": { "type": "Transitive", "resolved": "4.3.0", @@ -714,6 +758,17 @@ "resolved": "4.7.1", "contentHash": "j81Lovt90PDAq8kLpaJfJKV/rWdWuEk6jfV+MBkee33vzYLEUsy4gXK8laa9V2nZlLM9VM9yA/OOQxxPEJKAMw==" }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "kcQWWtGVC3MWMNXdMDWfrmIlFZZ2OdoeT6pSNVRtk9+Sa7jwdPiMlNwb0ZQcS7NRlT92pCfmjRtkSWUW3RAKwg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "Microsoft.Win32.Registry": "5.0.0", + "System.Configuration.ConfigurationManager": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Diagnostics.Tools": { "type": "Transitive", "resolved": "4.3.0", @@ -734,6 +789,14 @@ "System.Runtime": "4.3.0" } }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SztFwAnpfKC8+sEKXAFxCBWhKQaEd97EiOL7oZJZP56zbqnLpmxACWA8aGseaUExciuEAUuR9dY8f7HkTRAdnw==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "5.0.0" + } + }, "System.Globalization": { "type": "Transitive", "resolved": "4.3.0", @@ -841,6 +904,11 @@ "System.Runtime": "4.3.0" } }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "irMYm3vhVgRsYvHTU5b2gsT2CwT/SMM6LZFzuJjpIvT5Z4CshxNsaoBC1X/LltwuR3Opp8d6jOS/60WwOb7Q2Q==" + }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1097,6 +1165,15 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.Algorithms": { "type": "Transitive", "resolved": "4.3.0", @@ -1209,6 +1286,11 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "HGxMSAFAPLNoxBvSfW08vHde0F9uh7BjASwu6JF9JnXuEPhCY3YUqURn0+bQV/4UWeaqymmrHWV+Aw9riQCtCA==" + }, "System.Security.Cryptography.X509Certificates": { "type": "Transitive", "resolved": "4.3.0", @@ -1241,6 +1323,20 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "uE8juAhEkp7KDBCdjDIE3H9R1HJuEHqeqX8nLX9gmYKWwsqk3T5qZlPx8qle5DPKimC/Fy3AFTdV7HamgCh9qQ==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Windows.Extensions": "5.0.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, "System.Text.Encoding": { "type": "Transitive", "resolved": "4.3.0", @@ -1314,6 +1410,14 @@ "System.Runtime": "4.3.0" } }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "c1ho9WU9ZxMZawML+ssPKZfdnrg/OjR3pe0m9v8230z3acqphwvPJqzAkH54xRYm5ntZHGG1EPP3sux9H3qSPg==", + "dependencies": { + "System.Drawing.Common": "5.0.0" + } + }, "System.Xml.ReaderWriter": { "type": "Transitive", "resolved": "4.3.0", diff --git a/docker-compose.yml b/docker-compose.yml index 669e86f9..ba2ad6f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: command: ["bin/PluralKit.Bot.dll"] environment: - "PluralKit:Database=Host=db;Username=postgres;Password=postgres;Database=postgres;Maximum Pool Size=1000" + - "PluralKit:RedisAddr=redis" - "PluralKit:InfluxUrl=http://influx:8086" - "PluralKit:InfluxDb=pluralkit" - "PluralKit:LogDir=/var/log/pluralkit" @@ -49,6 +50,10 @@ services: - "POSTGRES_PASSWORD=postgres" restart: unless-stopped + redis: + image: redis:alpine + restart: unless-stopped + influx: image: influxdb:1.8 volumes: