feat(gateway): initial commit

This commit is contained in:
spiral
2022-04-11 15:55:10 -04:00
parent 8e5b987b2c
commit fadf007abc
12 changed files with 2487 additions and 1 deletions

View File

@@ -73,6 +73,8 @@ public class Bot
}
};
_services.Resolve<RedisGatewayService>().OnEventReceived += (evt) => OnEventReceived(0, evt);
// Init the shard stuff
_services.Resolve<ShardInfoService>().Init();

View File

@@ -21,6 +21,8 @@ public class BotConfig
public string? GatewayQueueUrl { get; set; }
public bool UseRedisRatelimiter { get; set; } = false;
public string? RedisGatewayUrl { get; set; }
public string? DiscordBaseUrl { get; set; }
public bool DisableErrorReporting { get; set; } = false;

View File

@@ -74,7 +74,12 @@ public class Init
// Start the Discord shards themselves (handlers already set up)
logger.Information("Connecting to Discord");
await StartCluster(services);
if (config.RedisGatewayUrl != null)
await services.Resolve<RedisGatewayService>().Start();
else
await StartCluster(services);
logger.Information("Connected! All is good (probably).");
// Lastly, we just... wait. Everything else is handled in the DiscordClient event loop
@@ -98,6 +103,7 @@ public class Init
// - Wraps the given function in an exception handler that properly logs errors
// - Adds a SIGINT (Ctrl-C) listener through Console.CancelKeyPress to gracefully shut down
// - Adds a SIGTERM (kill, systemctl stop, docker stop) listener through AppDomain.ProcessExit (same as above)
// todo: move run-clustered.sh to here
var logger = services.Resolve<ILogger>().ForContext<Init>();
var shutdown = new TaskCompletionSource<object>();

View File

@@ -43,6 +43,7 @@ public class BotModule: Module
};
}).AsSelf().SingleInstance();
builder.RegisterType<Cluster>().AsSelf().SingleInstance();
builder.RegisterType<RedisGatewayService>().AsSelf().SingleInstance();
builder.Register(c => { return new MemoryDiscordCache(); }).AsSelf().As<IDiscordCache>().SingleInstance();
builder.RegisterType<PrivateChannelService>().AsSelf().SingleInstance();

View File

@@ -0,0 +1,63 @@
using System.Text.Json;
using Serilog;
using StackExchange.Redis;
using Myriad.Gateway;
using Myriad.Serialization;
namespace PluralKit.Bot;
public class RedisGatewayService
{
private readonly BotConfig _config;
private readonly JsonSerializerOptions _jsonSerializerOptions;
private ConnectionMultiplexer _redis;
private ILogger _logger;
public RedisGatewayService(BotConfig config, ILogger logger)
{
_jsonSerializerOptions = new JsonSerializerOptions().ConfigureForMyriad();
_config = config;
_logger = logger.ForContext<RedisGatewayService>();
}
public event Func<IGatewayEvent, Task>? OnEventReceived;
public async Task Start()
{
_redis = await ConnectionMultiplexer.ConnectAsync(_config.RedisGatewayUrl);
var channel = await _redis.GetSubscriber().SubscribeAsync("evt");
channel.OnMessage(Handle);
}
public async Task Handle(ChannelMessage message)
{
var packet = JsonSerializer.Deserialize<GatewayPacket>(message.Message, _jsonSerializerOptions);
if (packet.Opcode != GatewayOpcode.Dispatch) return;
var evt = DeserializeEvent(packet.EventType, (JsonElement)packet.Payload);
if (evt == null) return;
await OnEventReceived(evt);
}
private IGatewayEvent? DeserializeEvent(string eventType, JsonElement payload)
{
if (!IGatewayEvent.EventTypes.TryGetValue(eventType, out var clrType))
{
_logger.Debug("Received unknown event type {EventType}", eventType);
return null;
}
try
{
_logger.Verbose("Deserializing {EventType} to {ClrType}", eventType, clrType);
return JsonSerializer.Deserialize(payload.GetRawText(), clrType, _jsonSerializerOptions) as IGatewayEvent;
}
catch (JsonException e)
{
_logger.Error(e, "Error deserializing event {EventType} to {ClrType}", eventType, clrType);
return null;
}
}
}