ConnectionEvents.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Collections.Concurrent;
  3. using BestHTTP.Connections;
  4. using BestHTTP.Logger;
  5. // Required for ConcurrentQueue.Clear extension.
  6. using BestHTTP.Extensions;
  7. namespace BestHTTP.Core
  8. {
  9. public enum ConnectionEvents
  10. {
  11. StateChange,
  12. ProtocolSupport
  13. }
  14. public
  15. #if CSHARP_7_OR_LATER
  16. readonly
  17. #endif
  18. struct ConnectionEventInfo
  19. {
  20. public readonly ConnectionBase Source;
  21. public readonly ConnectionEvents Event;
  22. public readonly HTTPConnectionStates State;
  23. public readonly HostProtocolSupport ProtocolSupport;
  24. public readonly HTTPRequest Request;
  25. public ConnectionEventInfo(ConnectionBase sourceConn, ConnectionEvents @event)
  26. {
  27. this.Source = sourceConn;
  28. this.Event = @event;
  29. this.State = HTTPConnectionStates.Initial;
  30. this.ProtocolSupport = HostProtocolSupport.Unknown;
  31. this.Request = null;
  32. }
  33. public ConnectionEventInfo(ConnectionBase sourceConn, HTTPConnectionStates newState)
  34. {
  35. this.Source = sourceConn;
  36. this.Event = ConnectionEvents.StateChange;
  37. this.State = newState;
  38. this.ProtocolSupport = HostProtocolSupport.Unknown;
  39. this.Request = null;
  40. }
  41. public ConnectionEventInfo(ConnectionBase sourceConn, HostProtocolSupport protocolSupport)
  42. {
  43. this.Source = sourceConn;
  44. this.Event = ConnectionEvents.ProtocolSupport;
  45. this.State = HTTPConnectionStates.Initial;
  46. this.ProtocolSupport = protocolSupport;
  47. this.Request = null;
  48. }
  49. public ConnectionEventInfo(ConnectionBase sourceConn, HTTPRequest request)
  50. {
  51. this.Source = sourceConn;
  52. this.Event = ConnectionEvents.StateChange;
  53. this.State = HTTPConnectionStates.ClosedResendRequest;
  54. this.ProtocolSupport = HostProtocolSupport.Unknown;
  55. this.Request = request;
  56. }
  57. public override string ToString()
  58. {
  59. return string.Format("[ConnectionEventInfo SourceConnection: {0}, Event: {1}, State: {2}, ProtocolSupport: {3}]",
  60. this.Source.ToString(), this.Event, this.State, this.ProtocolSupport);
  61. }
  62. }
  63. public static class ConnectionEventHelper
  64. {
  65. private static ConcurrentQueue<ConnectionEventInfo> connectionEventQueue = new ConcurrentQueue<ConnectionEventInfo>();
  66. #pragma warning disable 0649
  67. public static Action<ConnectionEventInfo> OnEvent;
  68. #pragma warning restore
  69. public static void EnqueueConnectionEvent(ConnectionEventInfo @event)
  70. {
  71. if (HTTPManager.Logger.Level == Loglevels.All)
  72. HTTPManager.Logger.Information("ConnectionEventHelper", "Enqueue connection event: " + @event.ToString(), @event.Source.Context);
  73. connectionEventQueue.Enqueue(@event);
  74. }
  75. internal static void Clear()
  76. {
  77. connectionEventQueue.Clear();
  78. }
  79. internal static void ProcessQueue()
  80. {
  81. ConnectionEventInfo connectionEvent;
  82. while (connectionEventQueue.TryDequeue(out connectionEvent))
  83. {
  84. if (HTTPManager.Logger.Level == Loglevels.All)
  85. HTTPManager.Logger.Information("ConnectionEventHelper", "Processing connection event: " + connectionEvent.ToString(), connectionEvent.Source.Context);
  86. if (OnEvent != null)
  87. {
  88. try
  89. {
  90. OnEvent(connectionEvent);
  91. }
  92. catch (Exception ex)
  93. {
  94. HTTPManager.Logger.Exception("ConnectionEventHelper", "ProcessQueue", ex, connectionEvent.Source.Context);
  95. }
  96. }
  97. if (connectionEvent.Source.LastProcessedUri == null)
  98. {
  99. HTTPManager.Logger.Warning("ConnectionEventHelper", String.Format("Ignoring ConnectionEventInfo({0}) because its LastProcessedUri is null!", connectionEvent.ToString()));
  100. return;
  101. }
  102. switch (connectionEvent.Event)
  103. {
  104. case ConnectionEvents.StateChange:
  105. HandleConnectionStateChange(connectionEvent);
  106. break;
  107. case ConnectionEvents.ProtocolSupport:
  108. HostManager.GetHost(connectionEvent.Source.LastProcessedUri.Host)
  109. .GetHostDefinition(connectionEvent.Source.ServerAddress)
  110. .AddProtocol(connectionEvent.ProtocolSupport);
  111. break;
  112. }
  113. }
  114. }
  115. private static void HandleConnectionStateChange(ConnectionEventInfo @event)
  116. {
  117. var connection = @event.Source;
  118. switch (@event.State)
  119. {
  120. case HTTPConnectionStates.Recycle:
  121. HostManager.GetHost(connection.LastProcessedUri.Host)
  122. .GetHostDefinition(connection.ServerAddress)
  123. .RecycleConnection(connection)
  124. .TryToSendQueuedRequests();
  125. break;
  126. case HTTPConnectionStates.WaitForProtocolShutdown:
  127. HostManager.GetHost(connection.LastProcessedUri.Host)
  128. .GetHostDefinition(connection.ServerAddress)
  129. .RemoveConnection(connection, @event.State);
  130. break;
  131. case HTTPConnectionStates.Closed:
  132. case HTTPConnectionStates.ClosedResendRequest:
  133. // in case of ClosedResendRequest
  134. if (@event.Request != null)
  135. RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(@event.Request, RequestEvents.Resend));
  136. HostManager.GetHost(connection.LastProcessedUri.Host)
  137. .GetHostDefinition(connection.ServerAddress)
  138. .RemoveConnection(connection, @event.State)
  139. .TryToSendQueuedRequests();
  140. break;
  141. }
  142. }
  143. }
  144. }