Skip to content

Commit 35cf9df

Browse files
committed
infra: attempt to improve bot
1 parent e6a0a36 commit 35cf9df

1 file changed

Lines changed: 78 additions & 8 deletions

File tree

src/TTX.Infrastructure/Twitch/Chat/TwitchBot.cs

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using TwitchLib.Client;
44
using TwitchLib.Client.Events;
55
using TwitchLib.Client.Models;
6+
using TwitchLib.Communication.Clients;
7+
using TwitchLib.Communication.Models;
68
using Message = TTX.App.Interfaces.Chat.Message;
79

810
namespace TTX.Infrastructure.Twitch.Chat;
@@ -11,28 +13,46 @@ public sealed class TwitchBot : IAsyncDisposable
1113
{
1214
public bool IsConnected => _client.IsConnected;
1315
public event EventHandler<Message> OnMessage = null!;
14-
public int ChannelCount => _client.JoinedChannels.Count;
16+
public int ChannelCount => _channels.Count;
1517
private readonly CancellationTokenSource _cts = new();
1618
private readonly ILogger<TwitchBot> _logger;
1719
private readonly TwitchClient _client;
1820
private readonly Channel<string> _joinChannel = Channel.CreateUnbounded<string>();
21+
private readonly HashSet<string> _channels = new(StringComparer.OrdinalIgnoreCase);
1922

2023
public TwitchBot(ILogger<TwitchBot> logger, ILoggerFactory loggerFactory)
2124
{
2225
_logger = logger;
23-
_client = new TwitchClient(loggerFactory: loggerFactory);
26+
ClientOptions clientOptions = new(
27+
reconnectionPolicy: new ReconnectionPolicy(3_000)
28+
);
29+
_client = new TwitchClient(
30+
new WebSocketClient(clientOptions),
31+
loggerFactory: loggerFactory
32+
);
2433

2534
_client.Initialize(new ConnectionCredentials());
2635
_client.OnMessageReceived += OnMessageReceived;
27-
_client.OnConnected += async (_, _) => { _ = OnConnected(); };
36+
_client.OnConnected += OnClientConnected;
37+
_client.OnReconnected += OnClientReconnected;
38+
_client.OnDisconnected += OnClientDisconnected;
39+
_client.OnConnectionError += OnConnectionError;
2840
_client.OnFailureToReceiveJoinConfirmation += OnFailureToReceiveJoinConfirmation;
2941
}
3042

3143
public Task Start() => _client.ConnectAsync();
3244

33-
public ValueTask AddChannel(string channel) => _joinChannel.Writer.WriteAsync(channel);
45+
public ValueTask AddChannel(string channel)
46+
{
47+
_channels.Add(channel);
48+
return _joinChannel.Writer.WriteAsync(channel);
49+
}
3450

35-
public Task RemoveChannel(string channel) => _client.LeaveChannelAsync(channel);
51+
public async Task RemoveChannel(string channel)
52+
{
53+
_channels.Remove(channel);
54+
await _client.LeaveChannelAsync(channel);
55+
}
3656

3757
private Task OnMessageReceived(object? _, OnMessageReceivedArgs e)
3858
{
@@ -44,14 +64,60 @@ private Task OnFailureToReceiveJoinConfirmation(object? _, OnFailureToReceiveJoi
4464
{
4565
if (_logger.IsEnabled(LogLevel.Warning))
4666
{
47-
_logger.LogWarning("Failed to join {channel}: {error}", e.Exception.Channel, e.Exception.Details);
67+
_logger.LogWarning("Failed to join {Channel}: {Error}", e.Exception.Channel, e.Exception.Details);
4868
}
49-
5069
_joinChannel.Writer.TryWrite(e.Exception.Channel);
70+
71+
return Task.CompletedTask;
72+
}
73+
74+
private Task OnClientConnected(object? _, OnConnectedEventArgs e)
75+
{
76+
if (_logger.IsEnabled(LogLevel.Information))
77+
{
78+
_logger.LogInformation("TwitchBot connected as {Username}", e.BotUsername);
79+
}
80+
81+
_ = DrainJoinQueue();
82+
return Task.CompletedTask;
83+
}
84+
85+
private Task OnClientReconnected(object? _, OnConnectedEventArgs e)
86+
{
87+
if (_logger.IsEnabled(LogLevel.Information))
88+
{
89+
_logger.LogInformation("TwitchBot reconnected as {Username}", e.BotUsername);
90+
}
91+
92+
foreach (string channel in _channels)
93+
{
94+
_joinChannel.Writer.TryWrite(channel);
95+
}
96+
97+
return Task.CompletedTask;
98+
}
99+
100+
private Task OnClientDisconnected(object? _, OnDisconnectedArgs e)
101+
{
102+
if (_logger.IsEnabled(LogLevel.Warning))
103+
{
104+
_logger.LogWarning("TwitchBot disconnected");
105+
}
106+
107+
return Task.CompletedTask;
108+
}
109+
110+
private Task OnConnectionError(object? _, OnConnectionErrorArgs e)
111+
{
112+
if (_logger.IsEnabled(LogLevel.Error))
113+
{
114+
_logger.LogError("TwitchBot connection error: {Message}", e.Error.Message);
115+
}
116+
51117
return Task.CompletedTask;
52118
}
53119

54-
private async Task OnConnected()
120+
private async Task DrainJoinQueue()
55121
{
56122
while (!_cts.Token.IsCancellationRequested && await _joinChannel.Reader.WaitToReadAsync())
57123
{
@@ -65,6 +131,10 @@ private async Task OnConnected()
65131
public async ValueTask DisposeAsync()
66132
{
67133
_client.OnMessageReceived -= OnMessageReceived;
134+
_client.OnConnected -= OnClientConnected;
135+
_client.OnReconnected -= OnClientReconnected;
136+
_client.OnDisconnected -= OnClientDisconnected;
137+
_client.OnConnectionError -= OnConnectionError;
68138
_client.OnFailureToReceiveJoinConfirmation -= OnFailureToReceiveJoinConfirmation;
69139
await _cts.CancelAsync();
70140
await _client.DisconnectAsync();

0 commit comments

Comments
 (0)