PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/SignalR/Connection.cs

https://github.com/kpmrafeeq/SignalR
C# | 189 lines | 165 code | 22 blank | 2 comment | 13 complexity | 28a194231e67dbb58bf6277583e7272a MD5 | raw file
Possible License(s): MIT
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using SignalR.Infrastructure;
  8. namespace SignalR
  9. {
  10. public class Connection : IConnection, ITransportConnection
  11. {
  12. private readonly IMessageBus _messageBus;
  13. private readonly IJsonSerializer _serializer;
  14. private readonly string _baseSignal;
  15. private readonly string _connectionId;
  16. private readonly HashSet<string> _signals;
  17. private readonly SafeSet<string> _groups;
  18. private readonly ITraceManager _trace;
  19. private bool _disconnected;
  20. private bool _aborted;
  21. public Connection(IMessageBus messageBus,
  22. IJsonSerializer jsonSerializer,
  23. string baseSignal,
  24. string connectionId,
  25. IEnumerable<string> signals,
  26. IEnumerable<string> groups,
  27. ITraceManager traceManager)
  28. {
  29. _messageBus = messageBus;
  30. _serializer = jsonSerializer;
  31. _baseSignal = baseSignal;
  32. _connectionId = connectionId;
  33. _signals = new HashSet<string>(signals);
  34. _groups = new SafeSet<string>(groups);
  35. _trace = traceManager;
  36. }
  37. private IEnumerable<string> Signals
  38. {
  39. get
  40. {
  41. return _signals.Concat(_groups.GetSnapshot());
  42. }
  43. }
  44. private TraceSource Trace
  45. {
  46. get
  47. {
  48. return _trace["SignalR.Connection"];
  49. }
  50. }
  51. public virtual Task Broadcast(object value)
  52. {
  53. return Send(_baseSignal, value);
  54. }
  55. public virtual Task Send(string signal, object value)
  56. {
  57. return SendMessage(signal, value);
  58. }
  59. public Task<PersistentResponse> ReceiveAsync(CancellationToken timeoutToken)
  60. {
  61. Trace.TraceInformation("Waiting for new messages");
  62. return _messageBus.GetMessages(Signals, null, timeoutToken)
  63. .Then(result => GetResponse(result));
  64. }
  65. public Task<PersistentResponse> ReceiveAsync(string messageId, CancellationToken timeoutToken)
  66. {
  67. Trace.TraceInformation("Waiting for messages from {0}.", messageId);
  68. return _messageBus.GetMessages(Signals, messageId, timeoutToken)
  69. .Then(result => GetResponse(result));
  70. }
  71. public Task SendCommand(SignalCommand command)
  72. {
  73. return SendMessage(SignalCommand.AddCommandSuffix(_connectionId), command);
  74. }
  75. private PersistentResponse GetResponse(MessageResult result)
  76. {
  77. // Do a single sweep through the results to process commands and extract values
  78. var messageValues = ProcessResults(result.Messages);
  79. var response = new PersistentResponse
  80. {
  81. MessageId = result.LastMessageId,
  82. Messages = messageValues,
  83. Disconnect = _disconnected,
  84. Aborted = _aborted
  85. };
  86. PopulateResponseState(response);
  87. Trace.TraceInformation("Connection '{0}' received {1} messages, last id {2}", _connectionId, result.Messages.Count, result.LastMessageId);
  88. return response;
  89. }
  90. private List<object> ProcessResults(IList<Message> source)
  91. {
  92. var messageValues = new List<object>();
  93. foreach (var message in source)
  94. {
  95. if (SignalCommand.IsCommand(message))
  96. {
  97. var command = WrappedValue.Unwrap<SignalCommand>(message.Value, _serializer);
  98. ProcessCommand(command);
  99. }
  100. else
  101. {
  102. messageValues.Add(WrappedValue.Unwrap(message.Value, _serializer));
  103. }
  104. }
  105. return messageValues;
  106. }
  107. private void ProcessCommand(SignalCommand command)
  108. {
  109. switch (command.Type)
  110. {
  111. case CommandType.AddToGroup:
  112. _groups.Add((string)command.Value);
  113. break;
  114. case CommandType.RemoveFromGroup:
  115. _groups.Remove((string)command.Value);
  116. break;
  117. case CommandType.Disconnect:
  118. _disconnected = true;
  119. break;
  120. case CommandType.Abort:
  121. _aborted = true;
  122. break;
  123. }
  124. }
  125. private Task SendMessage(string key, object value)
  126. {
  127. TraceSend(key, value);
  128. var wrappedValue = new WrappedValue(value, _serializer);
  129. return _messageBus.Send(_connectionId, key, wrappedValue).Catch();
  130. }
  131. private void PopulateResponseState(PersistentResponse response)
  132. {
  133. // Set the groups on the outgoing transport data
  134. if (_groups.Count > 0)
  135. {
  136. response.TransportData["Groups"] = _groups.GetSnapshot();
  137. }
  138. }
  139. private void TraceSend(string key, object value)
  140. {
  141. var command = value as SignalCommand;
  142. if (command != null)
  143. {
  144. if (command.Type == CommandType.AddToGroup)
  145. {
  146. Trace.TraceInformation("Sending Add to group '{0}'.", command.Value);
  147. }
  148. else if (command.Type == CommandType.RemoveFromGroup)
  149. {
  150. Trace.TraceInformation("Sending Remove from group '{0}'.", command.Value);
  151. }
  152. else if (command.Type == CommandType.Abort)
  153. {
  154. Trace.TraceInformation("Sending Aborted command '{0}'", _connectionId);
  155. }
  156. else
  157. {
  158. Trace.TraceInformation("Sending message to '{0}'", key);
  159. }
  160. }
  161. else
  162. {
  163. Trace.TraceInformation("Sending message to '{0}'", key);
  164. }
  165. }
  166. }
  167. }