diff --git a/Shokofin/SignalR/SignalRConnectionManager.cs b/Shokofin/SignalR/SignalRConnectionManager.cs index d75909d5..3d9ae7cd 100644 --- a/Shokofin/SignalR/SignalRConnectionManager.cs +++ b/Shokofin/SignalR/SignalRConnectionManager.cs @@ -30,6 +30,10 @@ public class SignalRConnectionManager : IDisposable private string LastConfigKey = string.Empty; + public bool IsUsable => CanConnect(Plugin.Instance.Configuration); + + public bool IsActive => Connection != null; + public HubConnectionState State => Connection == null ? HubConnectionState.Disconnected : Connection.State; public SignalRConnectionManager(ILogger logger, ShokoResolveManager resolveManager, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor) @@ -121,7 +125,7 @@ private Task OnDisconnected(Exception? exception) public void Disconnect() => DisconnectAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - private async Task DisconnectAsync() + public async Task DisconnectAsync() { if (Connection == null) return; @@ -133,19 +137,16 @@ private async Task DisconnectAsync() await connection.DisposeAsync(); } - public void ResetConnection(bool autoConnect) - => ResetConnection(Plugin.Instance.Configuration, autoConnect); - - private void ResetConnection(PluginConfiguration config, bool autoConnect) - => ResetConnectionAsync(config, autoConnect).ConfigureAwait(false).GetAwaiter().GetResult(); + public Task ResetConnectionAsync() + => ResetConnectionAsync(Plugin.Instance.Configuration, true); - public Task ResetConnectionAsync(bool autoConnect) - => ResetConnectionAsync(Plugin.Instance.Configuration, autoConnect); + private void ResetConnection(PluginConfiguration config, bool shouldConnect) + => ResetConnectionAsync(config, shouldConnect).ConfigureAwait(false).GetAwaiter().GetResult(); - private async Task ResetConnectionAsync(PluginConfiguration config, bool autoConnect) + private async Task ResetConnectionAsync(PluginConfiguration config, bool shouldConnect) { await DisconnectAsync(); - if (autoConnect) + if (shouldConnect) await ConnectAsync(config); } diff --git a/Shokofin/Web/SignalRApiController.cs b/Shokofin/Web/SignalRApiController.cs new file mode 100644 index 00000000..38d7b13a --- /dev/null +++ b/Shokofin/Web/SignalRApiController.cs @@ -0,0 +1,104 @@ +using System; +using System.Net.Http; +using System.Net.Mime; +using System.Reflection; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.Extensions.Logging; +using Shokofin.API; +using Shokofin.API.Models; +using Shokofin.SignalR; + +#nullable enable +namespace Shokofin.Web; + +/// +/// Pushbullet notifications controller. +/// +[ApiController] +[Route("Plugin/Shokofin/SignalR")] +[Produces(MediaTypeNames.Application.Json)] +public class SignalRApiController : ControllerBase +{ + private readonly ILogger Logger; + + private readonly SignalRConnectionManager ConnectionManager; + + /// + /// Initializes a new instance of the class. + /// + public SignalRApiController(ILogger logger, SignalRConnectionManager connectionManager) + { + Logger = logger; + ConnectionManager = connectionManager; + } + + /// + /// Get the current status of the connection to Shoko Server. + /// + [HttpGet("Status")] + public ShokoSignalRStatus GetStatus() + { + return new() + { + IsUsable = ConnectionManager.IsUsable, + IsActive = ConnectionManager.IsActive, + State = ConnectionManager.State, + }; + } + + /// + /// Connect or reconnect to Shoko Server. + /// + [HttpPost("Connect")] + public async Task ConnectAsync() + { + try { + await ConnectionManager.ResetConnectionAsync(); + return Ok(); + } + catch (Exception ex) { + Logger.LogError(ex, "Failed to connect to server."); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + + /// + /// Disconnect from Shoko Server. + /// + [HttpPost("Disconnect")] + public async Task DisconnectAsync() + { + try { + await ConnectionManager.DisconnectAsync(); + return Ok(); + } + catch (Exception ex) { + Logger.LogError(ex, "Failed to disconnect from server."); + return StatusCode(StatusCodes.Status500InternalServerError); + + } + } +} + +public class ShokoSignalRStatus +{ + /// + /// Determines if we can establish a connection to the server. + /// + public bool IsUsable { get; set; } + + /// + /// Determines if the connection manager is currently active. + /// + public bool IsActive { get; set; } + + /// + /// The current state of the connection. + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public HubConnectionState State { get; set; } +} \ No newline at end of file