Added support to test against Twitch's mocked websocket & webserver. Fixed some connection problems.
This commit is contained in:
parent
3d077181fa
commit
87f3623ed6
@ -16,6 +16,8 @@ namespace TwitchChatTTS
|
|||||||
public class TwitchConfiguration {
|
public class TwitchConfiguration {
|
||||||
public IEnumerable<string>? Channels;
|
public IEnumerable<string>? Channels;
|
||||||
public bool TtsWhenOffline;
|
public bool TtsWhenOffline;
|
||||||
|
public string? WebsocketUrl;
|
||||||
|
public string? ApiUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OBSConfiguration {
|
public class OBSConfiguration {
|
||||||
|
@ -360,6 +360,9 @@ namespace TwitchChatTTS.Hermes.Socket
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Failed to disconnect from Hermes websocket server.");
|
_logger.Error(ex, "Failed to disconnect from Hermes websocket server.");
|
||||||
|
Ready = false;
|
||||||
|
LoggedIn = false;
|
||||||
|
Connected = false;
|
||||||
}
|
}
|
||||||
UserId = null;
|
UserId = null;
|
||||||
_heartbeatTimer.Enabled = false;
|
_heartbeatTimer.Enabled = false;
|
||||||
@ -381,6 +384,9 @@ namespace TwitchChatTTS.Hermes.Socket
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Failed to disconnect from Hermes websocket server.");
|
_logger.Error(ex, "Failed to disconnect from Hermes websocket server.");
|
||||||
|
Ready = false;
|
||||||
|
LoggedIn = false;
|
||||||
|
Connected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,18 +94,20 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
if (clientDisconnect)
|
if (clientDisconnect)
|
||||||
await client.DisconnectAsync(new SocketDisconnectionEventArgs("Closed", "No need for a tertiary client."));
|
await client.DisconnectAsync(new SocketDisconnectionEventArgs("Closed", "No need for a tertiary client."));
|
||||||
};
|
};
|
||||||
client.OnDisconnected += (s, e) =>
|
client.OnDisconnected += async (s, e) =>
|
||||||
{
|
{
|
||||||
|
bool reconnecting = false;
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_identified?.UID == client.UID)
|
if (_identified?.UID == client.UID)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Identified Twitch client has disconnected [client: {client.UID}][main: {_identified.UID}][backup: {_backup?.UID}]");
|
_logger.Warning($"Identified Twitch client has disconnected [client: {client.UID}][main: {_identified.UID}][backup: {_backup?.UID}]");
|
||||||
_identified = null;
|
_identified = null;
|
||||||
|
reconnecting = true;
|
||||||
}
|
}
|
||||||
else if (_backup?.UID == client.UID)
|
else if (_backup?.UID == client.UID)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Backup Twitch client has disconnected [client: {client.UID}][main: {_identified?.UID}][backup: {_backup.UID}]");
|
_logger.Warning($"Backup Twitch client has disconnected [client: {client.UID}][main: {_identified?.UID}][backup: {_backup.UID}]");
|
||||||
_backup = null;
|
_backup = null;
|
||||||
}
|
}
|
||||||
else if (client.ReceivedReconnecting)
|
else if (client.ReceivedReconnecting)
|
||||||
@ -115,6 +117,12 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
else
|
else
|
||||||
_logger.Error($"Twitch client disconnected from unknown source [client: {client.UID}][main: {_identified?.UID}][backup: {_backup?.UID}]");
|
_logger.Error($"Twitch client disconnected from unknown source [client: {client.UID}][main: {_identified?.UID}][backup: {_backup?.UID}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reconnecting)
|
||||||
|
{
|
||||||
|
var client = GetWorkingClient();
|
||||||
|
await client.Connect();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_logger.Debug("Created a Twitch websocket client.");
|
_logger.Debug("Created a Twitch websocket client.");
|
||||||
|
@ -16,6 +16,7 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
private readonly IDictionary<string, Type> _messageTypes;
|
private readonly IDictionary<string, Type> _messageTypes;
|
||||||
private readonly IDictionary<string, string> _subscriptions;
|
private readonly IDictionary<string, string> _subscriptions;
|
||||||
private readonly IBackoff _backoff;
|
private readonly IBackoff _backoff;
|
||||||
|
private readonly Configuration _configuration;
|
||||||
private DateTime _lastReceivedMessageTimestamp;
|
private DateTime _lastReceivedMessageTimestamp;
|
||||||
private bool _disconnected;
|
private bool _disconnected;
|
||||||
private readonly object _lock;
|
private readonly object _lock;
|
||||||
@ -33,6 +34,7 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
public TwitchWebsocketClient(
|
public TwitchWebsocketClient(
|
||||||
[FromKeyedServices("twitch")] IEnumerable<ITwitchSocketHandler> handlers,
|
[FromKeyedServices("twitch")] IEnumerable<ITwitchSocketHandler> handlers,
|
||||||
[FromKeyedServices("twitch")] IBackoff backoff,
|
[FromKeyedServices("twitch")] IBackoff backoff,
|
||||||
|
Configuration configuration,
|
||||||
ILogger logger
|
ILogger logger
|
||||||
) : base(logger, new JsonSerializerOptions()
|
) : base(logger, new JsonSerializerOptions()
|
||||||
{
|
{
|
||||||
@ -42,6 +44,7 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
{
|
{
|
||||||
_handlers = handlers.ToDictionary(h => h.Name, h => h);
|
_handlers = handlers.ToDictionary(h => h.Name, h => h);
|
||||||
_backoff = backoff;
|
_backoff = backoff;
|
||||||
|
_configuration = configuration;
|
||||||
_subscriptions = new Dictionary<string, string>();
|
_subscriptions = new Dictionary<string, string>();
|
||||||
_lock = new object();
|
_lock = new object();
|
||||||
|
|
||||||
@ -52,7 +55,11 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
_messageTypes.Add("notification", typeof(NotificationMessage));
|
_messageTypes.Add("notification", typeof(NotificationMessage));
|
||||||
|
|
||||||
UID = Guid.NewGuid().ToString("D");
|
UID = Guid.NewGuid().ToString("D");
|
||||||
URL = "wss://eventsub.wss.twitch.tv/ws";
|
|
||||||
|
if (_configuration.Environment == "PROD" || string.IsNullOrWhiteSpace(_configuration.Twitch?.WebsocketUrl))
|
||||||
|
URL = "wss://eventsub.wss.twitch.tv/ws";
|
||||||
|
else
|
||||||
|
URL = _configuration.Twitch.WebsocketUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -96,16 +103,10 @@ namespace TwitchChatTTS.Twitch.Socket
|
|||||||
_disconnected = true;
|
_disconnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Information($"Twitch websocket client disconnected [status: {e.Status}][reason: {e.Reason}]");
|
_logger.Information($"Twitch websocket client disconnected [status: {e.Status}][reason: {e.Reason}][client: {UID}]");
|
||||||
|
|
||||||
Connected = false;
|
Connected = false;
|
||||||
Identified = false;
|
Identified = false;
|
||||||
|
|
||||||
if (!ReceivedReconnecting)
|
|
||||||
{
|
|
||||||
_logger.Information("Attempting to reconnect to Twitch websocket server.");
|
|
||||||
await Reconnect(_backoff, async () => await Connect());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,17 +4,21 @@ using Serilog;
|
|||||||
using TwitchChatTTS.Twitch.Socket.Messages;
|
using TwitchChatTTS.Twitch.Socket.Messages;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using TwitchChatTTS;
|
||||||
|
|
||||||
public class TwitchApiClient
|
public class TwitchApiClient
|
||||||
{
|
{
|
||||||
|
private readonly Configuration _configuration;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly WebClientWrap _web;
|
private readonly WebClientWrap _web;
|
||||||
|
|
||||||
|
|
||||||
public TwitchApiClient(
|
public TwitchApiClient(
|
||||||
|
Configuration configuration,
|
||||||
ILogger logger
|
ILogger logger
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_web = new WebClientWrap(new JsonSerializerOptions()
|
_web = new WebClientWrap(new JsonSerializerOptions()
|
||||||
@ -28,19 +32,23 @@ public class TwitchApiClient
|
|||||||
{
|
{
|
||||||
var conditions = new Dictionary<string, string>() { { "user_id", userId }, { "broadcaster_user_id", broadcasterId ?? userId }, { "moderator_user_id", broadcasterId ?? userId } };
|
var conditions = new Dictionary<string, string>() { { "user_id", userId }, { "broadcaster_user_id", broadcasterId ?? userId }, { "moderator_user_id", broadcasterId ?? userId } };
|
||||||
var subscriptionData = new EventSubscriptionMessage(type, version, sessionId, conditions);
|
var subscriptionData = new EventSubscriptionMessage(type, version, sessionId, conditions);
|
||||||
var response = await _web.Post("https://api.twitch.tv/helix/eventsub/subscriptions", subscriptionData);
|
var base_url = _configuration.Environment == "PROD" || string.IsNullOrWhiteSpace(_configuration.Twitch?.ApiUrl)
|
||||||
|
? "https://api.twitch.tv/helix" : _configuration.Twitch.ApiUrl;
|
||||||
|
var response = await _web.Post($"{base_url}/eventsub/subscriptions", subscriptionData);
|
||||||
if (response.StatusCode == HttpStatusCode.Accepted)
|
if (response.StatusCode == HttpStatusCode.Accepted)
|
||||||
{
|
{
|
||||||
_logger.Debug("Twitch API call [type: create event subscription]: " + await response.Content.ReadAsStringAsync());
|
_logger.Debug($"Twitch API call [type: create event subscription][subscription type: {type}][response: {await response.Content.ReadAsStringAsync()}]");
|
||||||
return await response.Content.ReadFromJsonAsync(typeof(EventResponse<NotificationInfo>)) as EventResponse<NotificationInfo>;
|
return await response.Content.ReadFromJsonAsync(typeof(EventResponse<NotificationInfo>)) as EventResponse<NotificationInfo>;
|
||||||
}
|
}
|
||||||
_logger.Error("Twitch api failed to create event subscription for websocket: " + await response.Content.ReadAsStringAsync());
|
_logger.Error($"Twitch API call failed [type: create event subscription][subscription type: {type}][response: {await response.Content.ReadAsStringAsync()}]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteEventSubscription(string subscriptionId)
|
public async Task DeleteEventSubscription(string subscriptionId)
|
||||||
{
|
{
|
||||||
await _web.Delete("https://api.twitch.tv/helix/eventsub/subscriptions?id=" + subscriptionId);
|
var base_url = _configuration.Environment == "PROD" || string.IsNullOrWhiteSpace(_configuration.Twitch?.ApiUrl)
|
||||||
|
? "https://api.twitch.tv/helix" : _configuration.Twitch.ApiUrl;
|
||||||
|
await _web.Delete($"{base_url}/eventsub/subscriptions?id=" + subscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<EventResponse<NotificationInfo>?> GetSubscriptions(string? status = null, string? broadcasterId = null, string? after = null)
|
public async Task<EventResponse<NotificationInfo>?> GetSubscriptions(string? status = null, string? broadcasterId = null, string? after = null)
|
||||||
|
Loading…
Reference in New Issue
Block a user