using System; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Configuration; using Microsoft.Owin.Hosting; using Owin; using Plume.Core.Logging; using Shuttle.Servers.Hubs; using Shuttle.Servers.Managers.Clients; using Shuttle.Servers.Managers.Events; using Shuttle.Servers.Managers.Items; using Shuttle.Servers.Managers.Notifications; namespace Shuttle.Servers { public class SignalrServer : ISignalrServer { private readonly string _url; private ILogger _logger; private IClientManager _clientManager; private IItemDepository _itemDepository; private IOperationNotificationListener _operationNotificationListener; private IEventNotificationListener _eventNotificationListener; private IDisposable _webApplication; public bool IsInitialized { get; private set; } public SignalrServer(string url) { _url = url ?? throw new ArgumentNullException(nameof(url)); } public void Initialize(ILogger logger, IClientManager clientManager, IItemDepository itemDepository, IOperationNotificationListener operationNotificationListener, IEventNotificationListener eventNotificationListener) { if (IsInitialized) { throw new InvalidOperationException("Server already initialized."); } _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _clientManager = clientManager ?? throw new ArgumentNullException(nameof(clientManager)); _itemDepository = itemDepository ?? throw new ArgumentNullException(nameof(itemDepository)); _operationNotificationListener = operationNotificationListener ?? throw new ArgumentNullException(nameof(operationNotificationListener)); _eventNotificationListener = eventNotificationListener ?? throw new ArgumentNullException(nameof(eventNotificationListener)); IsInitialized = true; _logger.Info("Server initialized."); } public void Start() { if (!IsInitialized) { throw new InvalidOperationException($"Server not initialized. Call {nameof(Initialize)} first."); } if (_webApplication != null) { throw new InvalidOperationException("Server already started."); } _logger.Debug($"Starting server on '{_url}'..."); try { _webApplication = WebApp.Start(_url, ConfigureSignalR); _logger.Info($"Server started at '{_url}'."); } catch (Exception e) { _logger.Error($"Unable to start SignalR server: {e}", e); } } /// /// Configure how the Hubs will be instantiated /// /// private void ConfigureSignalR(IAppBuilder appBuilder) { _logger.Debug("Configuring SignalR..."); HubConfiguration hubConfiguration = new HubConfiguration(); // configure hubs instantiation hubConfiguration.Resolver.Register(typeof(ClientHub), () => new ClientHub(_clientManager)); hubConfiguration.Resolver.Register(typeof(NotificationHub), () => new NotificationHub(_clientManager, _operationNotificationListener, _eventNotificationListener)); hubConfiguration.Resolver.Register(typeof(ItemHub), () => new ItemHub(_clientManager, _itemDepository)); hubConfiguration.EnableDetailedErrors = true; // set timeout values IConfigurationManager configurationManager = (IConfigurationManager)hubConfiguration.Resolver.GetService(typeof(IConfigurationManager)); configurationManager.DisconnectTimeout = TimeSpan.FromSeconds(6); // minimum value allowed by SignalR configurationManager.MaxIncomingWebSocketMessageSize = 262144; // Magic method mapping Hubs to actual routes appBuilder.MapSignalR(hubConfiguration); _logger.Debug("SignalR configured."); } public void Dispose() { _webApplication?.Dispose(); } } }