// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.AspNet.SignalR.Json; using Microsoft.AspNet.SignalR.Messaging; namespace Microsoft.AspNet.SignalR.Infrastructure { /// /// Default implementation. /// internal class ServerCommandHandler : IServerCommandHandler, ISubscriber, IDisposable { private readonly IMessageBus _messageBus; private readonly IServerIdManager _serverIdManager; private readonly IJsonSerializer _serializer; private IDisposable _subscription; private const int MaxMessages = 10; // The signal for all signalr servers private const string ServerSignal = "__SIGNALR__SERVER__"; private static readonly string[] ServerSignals = new[] { ServerSignal }; public ServerCommandHandler(IDependencyResolver resolver) : this(resolver.Resolve(), resolver.Resolve(), resolver.Resolve()) { } public ServerCommandHandler(IMessageBus messageBus, IServerIdManager serverIdManager, IJsonSerializer serializer) { _messageBus = messageBus; _serverIdManager = serverIdManager; _serializer = serializer; ProcessMessages(); } public Action Command { get; set; } public IList EventKeys { get { return ServerSignals; } } event Action ISubscriber.EventKeyAdded { add { } remove { } } event Action ISubscriber.EventKeyRemoved { add { } remove { } } public Action WriteCursor { get; set; } public string Identity { get { return _serverIdManager.ServerId; } } public Subscription Subscription { get; set; } public Task SendCommand(ServerCommand command) { // Store where the message originated from command.ServerId = _serverIdManager.ServerId; // Send the command to the all servers return _messageBus.Publish(_serverIdManager.ServerId, ServerSignal, _serializer.Stringify(command)); } protected virtual void Dispose(bool disposing) { if (disposing) { if (_subscription != null) { _subscription.Dispose(); } } } public void Dispose() { Dispose(true); } private void ProcessMessages() { // Process messages that come from the bus for servers _subscription = _messageBus.Subscribe(this, cursor: null, callback: HandleServerCommands, maxMessages: MaxMessages, state: null); } private Task HandleServerCommands(MessageResult result, object state) { result.Messages.Enumerate(m => ServerSignal.Equals(m.Key), (s, m) => { var command = _serializer.Parse(m.Value, m.Encoding); OnCommand(command); }, state: null); return TaskAsyncHelper.True; } private void OnCommand(ServerCommand command) { if (Command != null) { Command(command); } } } }