feat: add remote config over http/redis

This commit is contained in:
alyssa 2025-03-10 15:12:56 +00:00
parent c4db95796d
commit a72afb35a0
12 changed files with 326 additions and 4 deletions

View file

@ -0,0 +1,56 @@
using Serilog;
using Newtonsoft.Json;
using WatsonWebserver.Lite;
using WatsonWebserver.Core;
namespace PluralKit.Bot;
public class HttpListenerService
{
private readonly ILogger _logger;
private readonly RuntimeConfigService _runtimeConfig;
public HttpListenerService(ILogger logger, RuntimeConfigService runtimeConfig)
{
_logger = logger.ForContext<HttpListenerService>();
_runtimeConfig = runtimeConfig;
}
public void Start(string host)
{
var server = new WebserverLite(new WebserverSettings(host, 5002), DefaultRoute);
server.Routes.PreAuthentication.Static.Add(WatsonWebserver.Core.HttpMethod.GET, "/runtime_config", RuntimeConfigGet);
server.Routes.PreAuthentication.Parameter.Add(WatsonWebserver.Core.HttpMethod.POST, "/runtime_config/{key}", RuntimeConfigSet);
server.Routes.PreAuthentication.Parameter.Add(WatsonWebserver.Core.HttpMethod.DELETE, "/runtime_config/{key}", RuntimeConfigDelete);
server.Start();
}
private async Task DefaultRoute(HttpContextBase ctx)
=> await ctx.Response.Send("hellorld");
private async Task RuntimeConfigGet(HttpContextBase ctx)
{
var config = _runtimeConfig.GetAll();
ctx.Response.Headers.Add("content-type", "application/json");
await ctx.Response.Send(JsonConvert.SerializeObject(config));
}
private async Task RuntimeConfigSet(HttpContextBase ctx)
{
var key = ctx.Request.Url.Parameters["key"];
var value = ctx.Request.DataAsString;
await _runtimeConfig.Set(key, value);
await RuntimeConfigGet(ctx);
}
private async Task RuntimeConfigDelete(HttpContextBase ctx)
{
var key = ctx.Request.Url.Parameters["key"];
await _runtimeConfig.Delete(key);
await RuntimeConfigGet(ctx);
}
}

View file

@ -0,0 +1,58 @@
using Newtonsoft.Json;
using Serilog;
using StackExchange.Redis;
using PluralKit.Core;
namespace PluralKit.Bot;
public class RuntimeConfigService
{
private readonly RedisService _redis;
private readonly ILogger _logger;
private Dictionary<string, string> settings = new();
private string RedisKey;
public RuntimeConfigService(ILogger logger, RedisService redis, BotConfig config)
{
_logger = logger.ForContext<RuntimeConfigService>();
_redis = redis;
var clusterId = config.Cluster?.NodeIndex ?? 0;
RedisKey = $"remote_config:dotnet_bot:{clusterId}";
}
public async Task LoadConfig()
{
var redisConfig = await _redis.Connection.GetDatabase().HashGetAllAsync(RedisKey);
foreach (var entry in redisConfig)
settings.Add(entry.Name, entry.Value);
var configStr = JsonConvert.SerializeObject(settings);
_logger.Information($"starting with runtime config: {configStr}");
}
public async Task Set(string key, string value)
{
await _redis.Connection.GetDatabase().HashSetAsync(RedisKey, new[] { new HashEntry(key, new RedisValue(value)) });
settings.Add(key, value);
_logger.Information($"updated runtime config: {key}={value}");
}
public async Task Delete(string key)
{
await _redis.Connection.GetDatabase().HashDeleteAsync(RedisKey, key);
settings.Remove(key);
_logger.Information($"updated runtime config: {key} removed");
}
public object? Get(string key) => settings.GetValueOrDefault(key);
public bool Exists(string key) => settings.ContainsKey(key);
public Dictionary<string, string> GetAll() => settings;
}