PluralKit/Myriad/Gateway/Cluster.cs
2021-06-08 10:19:54 +02:00

79 lines
2.7 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Myriad.Types;
using Serilog;
namespace Myriad.Gateway
{
public class Cluster
{
private readonly GatewaySettings _gatewaySettings;
private readonly ILogger _logger;
private readonly ConcurrentDictionary<int, Shard> _shards = new();
private ShardIdentifyRatelimiter? _ratelimiter;
public Cluster(GatewaySettings gatewaySettings, ILogger logger)
{
_gatewaySettings = gatewaySettings;
_logger = logger;
}
public Func<Shard, IGatewayEvent, Task>? EventReceived { get; set; }
public event Action<Shard>? ShardCreated;
public IReadOnlyDictionary<int, Shard> Shards => _shards;
public User? User => _shards.Values.Select(s => s.User).FirstOrDefault(s => s != null);
public ApplicationPartial? Application => _shards.Values.Select(s => s.Application).FirstOrDefault(s => s != null);
public async Task Start(GatewayInfo.Bot info)
{
var concurrency = GetActualShardConcurrency(info.SessionStartLimit.MaxConcurrency);
_ratelimiter = new(_logger, concurrency);
await Start(info.Url, info.Shards);
}
public async Task Start(string url, int shardCount)
{
_logger.Information("Starting {ShardCount} shards at {Url}", shardCount, url);
for (var i = 0; i < shardCount; i++)
CreateAndAddShard(url, new ShardInfo(i, shardCount));
await StartShards();
}
private async Task StartShards()
{
_logger.Information("Connecting shards...");
foreach (var shard in _shards.Values)
await shard.Start();
}
private void CreateAndAddShard(string url, ShardInfo shardInfo)
{
var shard = new Shard(_gatewaySettings, shardInfo, _ratelimiter!, url, _logger);
shard.OnEventReceived += evt => OnShardEventReceived(shard, evt);
_shards[shardInfo.ShardId] = shard;
ShardCreated?.Invoke(shard);
}
private async Task OnShardEventReceived(Shard shard, IGatewayEvent evt)
{
if (EventReceived != null)
await EventReceived(shard, evt);
}
private int GetActualShardConcurrency(int recommendedConcurrency)
{
if (_gatewaySettings.MaxShardConcurrency == null)
return recommendedConcurrency;
return Math.Min(_gatewaySettings.MaxShardConcurrency.Value, recommendedConcurrency);
}
}
}