/SignalR/Connection.cs

https://github.com/einari/SignalR · C# · 149 lines · 128 code · 19 blank · 2 comment · 3 complexity · f422e1aa8b921a118a8e35b5c933cd06 MD5 · raw file

  1. using System.Collections.Generic;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using SignalR.Infrastructure;
  7. namespace SignalR
  8. {
  9. public class Connection : IConnection, IReceivingConnection
  10. {
  11. private readonly IMessageBus _messageBus;
  12. private readonly IJsonSerializer _serializer;
  13. private readonly string _baseSignal;
  14. private readonly string _connectionId;
  15. private readonly HashSet<string> _signals;
  16. private readonly HashSet<string> _groups;
  17. private readonly ITraceManager _trace;
  18. private bool _disconnected;
  19. public Connection(IMessageBus messageBus,
  20. IJsonSerializer jsonSerializer,
  21. string baseSignal,
  22. string connectionId,
  23. IEnumerable<string> signals,
  24. IEnumerable<string> groups,
  25. ITraceManager traceManager)
  26. {
  27. _messageBus = messageBus;
  28. _serializer = jsonSerializer;
  29. _baseSignal = baseSignal;
  30. _connectionId = connectionId;
  31. _signals = new HashSet<string>(signals);
  32. _groups = new HashSet<string>(groups);
  33. _trace = traceManager;
  34. }
  35. private IEnumerable<string> Signals
  36. {
  37. get
  38. {
  39. return _signals.Concat(_groups);
  40. }
  41. }
  42. public virtual Task Broadcast(object value)
  43. {
  44. return Broadcast(_baseSignal, value);
  45. }
  46. public virtual Task Broadcast(string key, object value)
  47. {
  48. return SendMessage(key, value);
  49. }
  50. public Task Send(object value)
  51. {
  52. return SendMessage(_connectionId, value);
  53. }
  54. public Task<PersistentResponse> ReceiveAsync(CancellationToken timeoutToken)
  55. {
  56. return _messageBus.GetMessages(Signals, null, timeoutToken)
  57. .Then(result => GetResponse(result));
  58. }
  59. public Task<PersistentResponse> ReceiveAsync(string messageId, CancellationToken timeoutToken)
  60. {
  61. return _messageBus.GetMessages(Signals, messageId, timeoutToken)
  62. .Then(result => GetResponse(result));
  63. }
  64. public Task SendCommand(SignalCommand command)
  65. {
  66. return SendMessage(SignalCommand.AddCommandSuffix(_connectionId), command);
  67. }
  68. private PersistentResponse GetResponse(MessageResult result)
  69. {
  70. // Do a single sweep through the results to process commands and extract values
  71. var messageValues = ProcessResults(result.Messages);
  72. var response = new PersistentResponse
  73. {
  74. MessageId = result.LastMessageId,
  75. Messages = messageValues,
  76. Disconnect = _disconnected,
  77. TimedOut = result.TimedOut
  78. };
  79. PopulateResponseState(response);
  80. _trace.Source.TraceInformation("Connection: Connection {0} received {1} messages, last id {2}", _connectionId, result.Messages.Count, result.LastMessageId);
  81. Debug.WriteLine("Connection: Connection {0} received {1} messages, last id {2}", _connectionId, result.Messages.Count, result.LastMessageId);
  82. return response;
  83. }
  84. private List<object> ProcessResults(IList<Message> source)
  85. {
  86. var messageValues = new List<object>();
  87. foreach (var message in source)
  88. {
  89. if (SignalCommand.IsCommand(message))
  90. {
  91. var command = WrappedValue.Unwrap<SignalCommand>(message.Value, _serializer);
  92. ProcessCommand(command);
  93. }
  94. else
  95. {
  96. messageValues.Add(WrappedValue.Unwrap(message.Value, _serializer));
  97. }
  98. }
  99. return messageValues;
  100. }
  101. private void ProcessCommand(SignalCommand command)
  102. {
  103. switch (command.Type)
  104. {
  105. case CommandType.AddToGroup:
  106. _groups.Add((string)command.Value);
  107. break;
  108. case CommandType.RemoveFromGroup:
  109. _groups.Remove((string)command.Value);
  110. break;
  111. case CommandType.Disconnect:
  112. _disconnected = true;
  113. break;
  114. }
  115. }
  116. private Task SendMessage(string key, object value)
  117. {
  118. Debug.WriteLine("Connection: Sending {0} {1}", key, value);
  119. return _messageBus.Send(_connectionId, key, new WrappedValue(value, _serializer)).Catch();
  120. }
  121. private void PopulateResponseState(PersistentResponse response)
  122. {
  123. // Set the groups on the outgoing transport data
  124. if (_groups.Any())
  125. {
  126. response.TransportData["Groups"] = _groups;
  127. }
  128. }
  129. }
  130. }