diff --git a/TwitchLib.EventSub.Websockets.Example.NetStandard/Program.cs b/TwitchLib.EventSub.Websockets.Example.NetStandard/Program.cs index cd5276b..1e43479 100644 --- a/TwitchLib.EventSub.Websockets.Example.NetStandard/Program.cs +++ b/TwitchLib.EventSub.Websockets.Example.NetStandard/Program.cs @@ -24,7 +24,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) => services.AddLogging(); services.AddTwitchLibEventSubWebsockets(); - services.AddHostedService(); + services.AddHostedService(); }); } } \ No newline at end of file diff --git a/TwitchLib.EventSub.Websockets.Example.NetStandard/WebsocketHostedServiceWithoutDI.cs b/TwitchLib.EventSub.Websockets.Example.NetStandard/WebsocketHostedServiceWithoutDI.cs new file mode 100644 index 0000000..0e060e7 --- /dev/null +++ b/TwitchLib.EventSub.Websockets.Example.NetStandard/WebsocketHostedServiceWithoutDI.cs @@ -0,0 +1,77 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using TwitchLib.EventSub.Websockets.Core.EventArgs; +using TwitchLib.EventSub.Websockets.Core.EventArgs.Channel; + +namespace TwitchLib.EventSub.Websockets.Example.NetStandard +{ + public class WebsocketHostedServiceWithoutDI : IHostedService + { + private readonly ILogger _logger; + private readonly EventSubWebsocketClient _eventSubWebsocketClient; + + public WebsocketHostedServiceWithoutDI(ILogger logger, ILoggerFactory loggerFactory) + { + _logger = logger; + _eventSubWebsocketClient = new EventSubWebsocketClient(loggerFactory); + + _eventSubWebsocketClient.WebsocketConnected += OnWebsocketConnected; + _eventSubWebsocketClient.WebsocketDisconnected += OnWebsocketDisconnected; + _eventSubWebsocketClient.WebsocketReconnected += OnWebsocketReconnected; + _eventSubWebsocketClient.ErrorOccurred += OnErrorOccurred; + + _eventSubWebsocketClient.ChannelFollow += OnChannelFollow; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + await _eventSubWebsocketClient.ConnectAsync(); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + await _eventSubWebsocketClient.DisconnectAsync(); + } + + private async Task OnErrorOccurred(object sender, ErrorOccuredArgs e) + { + _logger.LogError($"Websocket {_eventSubWebsocketClient.SessionId} - Error occurred!"); + } + + private async Task OnChannelFollow(object sender, ChannelFollowArgs e) + { + var eventData = e.Notification.Payload.Event; + _logger.LogInformation($"{eventData.UserName} followed {eventData.BroadcasterUserName} at {eventData.FollowedAt}"); + } + + private async Task OnWebsocketConnected(object sender, WebsocketConnectedArgs e) + { + _logger.LogInformation($"Websocket {_eventSubWebsocketClient.SessionId} connected!"); + + if (!e.IsRequestedReconnect) + { + // subscribe to topics + } + } + + private async Task OnWebsocketDisconnected(object sender, EventArgs e) + { + _logger.LogError($"Websocket {_eventSubWebsocketClient.SessionId} disconnected!"); + + // Don't do this in production. You should implement a better reconnect strategy + while (!await _eventSubWebsocketClient.ReconnectAsync()) + { + _logger.LogError("Websocket reconnect failed!"); + await Task.Delay(1000); + } + } + + private async Task OnWebsocketReconnected(object sender, EventArgs e) + { + _logger.LogWarning($"Websocket {_eventSubWebsocketClient.SessionId} reconnected"); + } + } +} \ No newline at end of file diff --git a/TwitchLib.EventSub.Websockets/EventSubWebsocketClient.cs b/TwitchLib.EventSub.Websockets/EventSubWebsocketClient.cs index bb0a7c0..8cd9752 100644 --- a/TwitchLib.EventSub.Websockets/EventSubWebsocketClient.cs +++ b/TwitchLib.EventSub.Websockets/EventSubWebsocketClient.cs @@ -2,10 +2,12 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging.Abstractions; using TwitchLib.EventSub.Websockets.Client; using TwitchLib.EventSub.Websockets.Core.EventArgs; using TwitchLib.EventSub.Websockets.Core.EventArgs.Channel; @@ -266,6 +268,7 @@ public class EventSubWebsocketClient private Dictionary> _handlers; private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IServiceProvider _serviceProvider; private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions @@ -300,6 +303,37 @@ public EventSubWebsocketClient(ILogger logger, IEnumera _reconnectRequested = false; } + /// + /// Instantiates an EventSubWebsocketClient used to subscribe to EventSub notifications via Websockets. + /// + /// LoggerFactory used to construct Loggers for the EventSubWebsocketClient and underlying classes + public EventSubWebsocketClient(ILoggerFactory loggerFactory = null) + { + _loggerFactory = loggerFactory; + + _logger = _loggerFactory != null + ? _loggerFactory.CreateLogger() + : NullLogger.Instance; + + _websocketClient = _loggerFactory != null + ? new WebsocketClient(_loggerFactory.CreateLogger()) + : new WebsocketClient(); + + _websocketClient.OnDataReceived += OnDataReceived; + _websocketClient.OnErrorOccurred += OnErrorOccurred; + + var handlers = typeof(INotificationHandler) + .Assembly.ExportedTypes + .Where(x => typeof(INotificationHandler).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) + .Select(Activator.CreateInstance).Cast() + .ToList(); + + PrepareHandlers(handlers); + + _reconnectComplete = false; + _reconnectRequested = false; + } + /// /// Connect to Twitch EventSub Websockets /// @@ -357,7 +391,7 @@ private async Task ReconnectAsync(Uri url) var reconnectClient = _serviceProvider != null ? _serviceProvider.GetRequiredService() - : new WebsocketClient(null); + : new WebsocketClient(_loggerFactory?.CreateLogger()); reconnectClient.OnDataReceived += OnDataReceived; reconnectClient.OnErrorOccurred += OnErrorOccurred; @@ -403,7 +437,7 @@ private async Task ReconnectAsync(Uri url) _websocketClient = _serviceProvider != null ? _serviceProvider.GetRequiredService() - : new WebsocketClient(null); + : new WebsocketClient(_loggerFactory?.CreateLogger()); _websocketClient.OnDataReceived += OnDataReceived; _websocketClient.OnErrorOccurred += OnErrorOccurred; diff --git a/TwitchLib.EventSub.Websockets/Extensions/ServiceCollectionExtensions.cs b/TwitchLib.EventSub.Websockets/Extensions/ServiceCollectionExtensions.cs index 492a874..a8f4ce1 100644 --- a/TwitchLib.EventSub.Websockets/Extensions/ServiceCollectionExtensions.cs +++ b/TwitchLib.EventSub.Websockets/Extensions/ServiceCollectionExtensions.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System; +using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using TwitchLib.EventSub.Websockets.Client; using TwitchLib.EventSub.Websockets.Core.Handler; @@ -42,7 +44,7 @@ private static IServiceCollection AddNotificationHandlers(this IServiceCollectio public static IServiceCollection AddTwitchLibEventSubWebsockets(this IServiceCollection services) { services.TryAddTransient(); - services.TryAddSingleton(); + services.TryAddSingleton(x => new EventSubWebsocketClient(x.GetRequiredService>(), x.GetRequiredService>(), x.GetRequiredService(), x.GetRequiredService())); services.AddNotificationHandlers(typeof(INotificationHandler)); return services; }