Changed various locking mechanisms.

This commit is contained in:
Tom
2025-03-29 20:28:36 +00:00
parent eddd9e6403
commit fb04f4003f
11 changed files with 272 additions and 155 deletions

View File

@@ -27,7 +27,7 @@ namespace TwitchChatTTS.Twitch.Redemptions
private readonly AudioPlaybackEngine _playback;
private readonly ILogger _logger;
private readonly Random _random;
private readonly object _lock;
private readonly ReaderWriterLockSlim _rwls;
public RedemptionManager(
@@ -50,7 +50,7 @@ namespace TwitchChatTTS.Twitch.Redemptions
_playback = playback;
_logger = logger;
_random = new Random();
_lock = new object();
_rwls = new ReaderWriterLockSlim();
var topic = _bus.GetTopic("redemptions_initiation");
topic.Subscribe(data =>
@@ -110,16 +110,15 @@ namespace TwitchChatTTS.Twitch.Redemptions
private void Add(string twitchRedemptionId, string redemptionId)
{
lock (_lock)
_rwls.EnterWriteLock();
try
{
if (!_redeems.TryGetValue(twitchRedemptionId, out var redeems))
_redeems.Add(twitchRedemptionId, redeems = new List<string>());
var item = _redemptions.TryGetValue(redemptionId, out var r) ? r : null;
if (item == null)
{
return;
}
var redemptions = redeems.Select(r => _redemptions.TryGetValue(r, out var rr) ? rr : null);
bool added = false;
@@ -138,12 +137,17 @@ namespace TwitchChatTTS.Twitch.Redemptions
if (!added)
redeems.Add(redemptionId);
}
finally
{
_rwls.ExitWriteLock();
}
_logger.Debug($"Added redemption action [redemption id: {redemptionId}][twitch redemption id: {twitchRedemptionId}]");
}
private void Add(string twitchRedemptionId, Redemption item)
{
lock (_lock)
_rwls.EnterWriteLock();
try
{
if (!_redeems.TryGetValue(twitchRedemptionId, out var redemptionNames))
_redeems.Add(twitchRedemptionId, redemptionNames = new List<string>());
@@ -165,6 +169,10 @@ namespace TwitchChatTTS.Twitch.Redemptions
if (!added)
redemptionNames.Add(item.Id);
}
finally
{
_rwls.ExitWriteLock();
}
_logger.Debug($"Added redemption action [redemption id: {item.Id}][twitch redemption id: {twitchRedemptionId}]");
}
@@ -419,7 +427,8 @@ namespace TwitchChatTTS.Twitch.Redemptions
public IEnumerable<RedeemableAction> Get(string twitchRedemptionId)
{
lock (_lock)
_rwls.EnterReadLock();
try
{
if (_redeems.TryGetValue(twitchRedemptionId, out var redemptionIds))
return redemptionIds.Select(r => _redemptions.TryGetValue(r, out var redemption) ? redemption : null)
@@ -427,15 +436,19 @@ namespace TwitchChatTTS.Twitch.Redemptions
.Select(r => _actions.TryGetValue(r!.ActionName, out var action) ? action : null)
.Where(a => a != null)!;
}
finally
{
_rwls.ExitReadLock();
}
return [];
}
public void Initialize()
{
_logger.Debug($"Redemption manager is about to initialize [redemption count: {_redemptions.Count()}][action count: {_actions.Count}]");
lock (_lock)
_rwls.EnterWriteLock();
try
{
_logger.Debug($"Redemption manager is about to initialize [redemption count: {_redemptions.Count()}][action count: {_actions.Count}]");
_redeems.Clear();
var ordered = _redemptions.Select(r => r.Value).Where(r => r != null).OrderBy(r => r.Order);
@@ -463,18 +476,31 @@ namespace TwitchChatTTS.Twitch.Redemptions
}
}
}
finally
{
_rwls.ExitWriteLock();
}
_logger.Debug("All redemptions added. Redemption Manager is ready.");
}
public bool RemoveAction(string actionName)
{
return _actions.Remove(actionName);
_rwls.EnterWriteLock();
try
{
return _actions.Remove(actionName);
}
finally
{
_rwls.ExitWriteLock();
}
}
public bool RemoveRedemption(string redemptionId)
{
lock (_lock)
_rwls.EnterWriteLock();
try
{
if (!_redemptions.TryGetValue(redemptionId, out var redemption))
{
@@ -490,6 +516,10 @@ namespace TwitchChatTTS.Twitch.Redemptions
return true;
}
}
finally
{
_rwls.ExitWriteLock();
}
return false;
}
@@ -507,7 +537,8 @@ namespace TwitchChatTTS.Twitch.Redemptions
public bool Update(Redemption redemption)
{
lock (_lock)
_rwls.EnterWriteLock();
try
{
if (_redemptions.TryGetValue(redemption.Id, out var r))
{
@@ -548,6 +579,10 @@ namespace TwitchChatTTS.Twitch.Redemptions
return true;
}
}
finally
{
_rwls.ExitWriteLock();
}
_logger.Warning($"Cannot find redemption by name [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}]");
return false;
@@ -555,12 +590,20 @@ namespace TwitchChatTTS.Twitch.Redemptions
public bool Update(RedeemableAction action)
{
if (_actions.TryGetValue(action.Name, out var a))
_rwls.EnterWriteLock();
try
{
a.Type = action.Type;
a.Data = action.Data;
_logger.Debug($"Updated redeemable action in redemption manager [action name: {action.Name}]");
return true;
if (_actions.TryGetValue(action.Name, out var a))
{
a.Type = action.Type;
a.Data = action.Data;
_logger.Debug($"Updated redeemable action in redemption manager [action name: {action.Name}]");
return true;
}
}
finally
{
_rwls.ExitWriteLock();
}
_logger.Warning($"Cannot find redeemable action by name [action name: {action.Name}]");

View File

@@ -39,7 +39,7 @@ namespace TwitchChatTTS.Twitch.Socket.Handlers
_logger.Warning($"Twitch connection has {timeLeft} before it is revoked. Refreshing the token is soon required.");
else
{
_logger.Error("Twitch connection has its permissions revoked. Refresh the token. Twitch client will not be connecting.");
_logger.Error($"Twitch connection has its permissions revoked. Refresh the token. Twitch client will not be connecting. [expired at: {twitchConnection.ExpiresAt}]");
return;
}

View File

@@ -18,21 +18,22 @@ namespace TwitchChatTTS.Twitch.Socket
private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger;
private readonly object _lock;
private readonly Mutex _mutex;
public TwitchConnectionManager(IServiceProvider serviceProvider, ILogger logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
_lock = new object();
_mutex = new Mutex();
}
public TwitchWebsocketClient GetBackupClient()
{
lock (_lock)
try
{
_mutex.WaitOne();
if (_identified == null)
throw new InvalidOperationException("Cannot get backup Twitch client yet. Waiting for identification.");
if (_backup != null)
@@ -40,12 +41,17 @@ namespace TwitchChatTTS.Twitch.Socket
return CreateNewClient();
}
finally
{
_mutex.ReleaseMutex();
}
}
public TwitchWebsocketClient GetWorkingClient()
{
lock (_lock)
try
{
_mutex.WaitOne();
if (_identified == null)
{
return CreateNewClient();
@@ -53,6 +59,10 @@ namespace TwitchChatTTS.Twitch.Socket
return _identified;
}
finally
{
_mutex.ReleaseMutex();
}
}
private TwitchWebsocketClient CreateNewClient()
@@ -74,8 +84,9 @@ namespace TwitchChatTTS.Twitch.Socket
private async Task OnDisconnection(TwitchWebsocketClient client)
{
bool reconnecting = false;
lock (_lock)
try
{
_mutex.WaitOne();
if (_identified?.UID == client.UID)
{
_logger.Debug($"Identified Twitch client has disconnected [client: {client.UID}][main: {_identified.UID}][backup: {_backup?.UID}]");
@@ -92,19 +103,25 @@ namespace TwitchChatTTS.Twitch.Socket
else
_logger.Warning($"Twitch client disconnected from unknown source [client: {client.UID}][main: {_identified?.UID}][backup: {_backup?.UID}]");
}
finally
{
_mutex.ReleaseMutex();
}
if (reconnecting)
{
var newClient = GetWorkingClient();
await newClient.Reconnect();
}
}
private async Task OnIdentified(TwitchWebsocketClient client)
{
bool clientDisconnect = false;
lock (_lock)
try
{
_mutex.WaitOne();
if (_identified == null || _identified.ReceivedReconnecting)
{
if (_backup != null && _backup.UID == client.UID)
@@ -125,10 +142,14 @@ namespace TwitchChatTTS.Twitch.Socket
_logger.Warning($"Twitch client has been identified, but isn't main or backup [client: {client.UID}][main: {_identified.UID}][backup: {_backup?.UID}]");
clientDisconnect = true;
}
}
if (clientDisconnect)
await client.DisconnectAsync(new SocketDisconnectionEventArgs("Closed", "No need for a tertiary client."));
if (clientDisconnect)
client.DisconnectAsync(new SocketDisconnectionEventArgs("Closed", "No need for a tertiary client.")).Wait();
}
finally
{
_mutex.ReleaseMutex();
}
}
}
}

View File

@@ -17,15 +17,11 @@ namespace TwitchChatTTS.Twitch.Socket
private readonly IDictionary<string, string> _subscriptions;
private readonly IBackoff _backoff;
private readonly Configuration _configuration;
private bool _disconnected;
private readonly object _lock;
public event EventHandler<EventArgs>? OnIdentified;
public string UID { get; }
public string URL;
public bool Connected { get; private set; }
public bool Identified { get; private set; }
public string? SessionId { get; private set; }
public bool ReceivedReconnecting { get; set; }
public bool TwitchReconnected { get; set; }
@@ -46,13 +42,14 @@ namespace TwitchChatTTS.Twitch.Socket
_backoff = backoff;
_configuration = configuration;
_subscriptions = new Dictionary<string, string>();
_lock = new object();
_messageTypes = new Dictionary<string, Type>();
_messageTypes.Add("session_keepalive", typeof(object));
_messageTypes.Add("session_welcome", typeof(SessionWelcomeMessage));
_messageTypes.Add("session_reconnect", typeof(SessionWelcomeMessage));
_messageTypes.Add("notification", typeof(NotificationMessage));
_messageTypes = new Dictionary<string, Type>
{
{ "session_keepalive", typeof(object) },
{ "session_welcome", typeof(SessionWelcomeMessage) },
{ "session_reconnect", typeof(SessionWelcomeMessage) },
{ "notification", typeof(NotificationMessage) }
};
UID = Guid.NewGuid().ToString("D");
@@ -88,25 +85,12 @@ namespace TwitchChatTTS.Twitch.Socket
_logger.Information($"Initializing Twitch websocket client.");
OnConnected += (sender, e) =>
{
Connected = true;
_logger.Information("Twitch websocket client connected.");
_disconnected = false;
};
OnDisconnected += (sender, e) =>
{
lock (_lock)
{
if (_disconnected)
return;
_disconnected = true;
}
_logger.Information($"Twitch websocket client disconnected [status: {e.Status}][reason: {e.Reason}][client: {UID}]");
Connected = false;
Identified = false;
};
}
@@ -126,7 +110,6 @@ namespace TwitchChatTTS.Twitch.Socket
public void Identify(string sessionId)
{
Identified = true;
SessionId = sessionId;
OnIdentified?.Invoke(this, EventArgs.Empty);
}