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();
}
}
}