You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
6.2 KiB
188 lines
6.2 KiB
8 months ago
|
using System;
|
||
|
using System.Collections.Concurrent;
|
||
|
|
||
|
using BestHTTP.Connections;
|
||
|
using BestHTTP.Logger;
|
||
|
|
||
|
// Required for ConcurrentQueue.Clear extension.
|
||
|
using BestHTTP.Extensions;
|
||
|
|
||
|
namespace BestHTTP.Core
|
||
|
{
|
||
|
public enum ConnectionEvents
|
||
|
{
|
||
|
StateChange,
|
||
|
ProtocolSupport
|
||
|
}
|
||
|
|
||
|
public
|
||
|
#if CSHARP_7_OR_LATER
|
||
|
readonly
|
||
|
#endif
|
||
|
struct ConnectionEventInfo
|
||
|
{
|
||
|
public readonly ConnectionBase Source;
|
||
|
|
||
|
public readonly ConnectionEvents Event;
|
||
|
|
||
|
public readonly HTTPConnectionStates State;
|
||
|
|
||
|
public readonly HostProtocolSupport ProtocolSupport;
|
||
|
|
||
|
public readonly HTTPRequest Request;
|
||
|
|
||
|
public ConnectionEventInfo(ConnectionBase sourceConn, ConnectionEvents @event)
|
||
|
{
|
||
|
this.Source = sourceConn;
|
||
|
this.Event = @event;
|
||
|
|
||
|
this.State = HTTPConnectionStates.Initial;
|
||
|
|
||
|
this.ProtocolSupport = HostProtocolSupport.Unknown;
|
||
|
|
||
|
this.Request = null;
|
||
|
}
|
||
|
|
||
|
public ConnectionEventInfo(ConnectionBase sourceConn, HTTPConnectionStates newState)
|
||
|
{
|
||
|
this.Source = sourceConn;
|
||
|
|
||
|
this.Event = ConnectionEvents.StateChange;
|
||
|
|
||
|
this.State = newState;
|
||
|
|
||
|
this.ProtocolSupport = HostProtocolSupport.Unknown;
|
||
|
|
||
|
this.Request = null;
|
||
|
}
|
||
|
|
||
|
public ConnectionEventInfo(ConnectionBase sourceConn, HostProtocolSupport protocolSupport)
|
||
|
{
|
||
|
this.Source = sourceConn;
|
||
|
this.Event = ConnectionEvents.ProtocolSupport;
|
||
|
|
||
|
this.State = HTTPConnectionStates.Initial;
|
||
|
|
||
|
this.ProtocolSupport = protocolSupport;
|
||
|
|
||
|
this.Request = null;
|
||
|
}
|
||
|
|
||
|
public ConnectionEventInfo(ConnectionBase sourceConn, HTTPRequest request)
|
||
|
{
|
||
|
this.Source = sourceConn;
|
||
|
|
||
|
this.Event = ConnectionEvents.StateChange;
|
||
|
|
||
|
this.State = HTTPConnectionStates.ClosedResendRequest;
|
||
|
|
||
|
this.ProtocolSupport = HostProtocolSupport.Unknown;
|
||
|
|
||
|
this.Request = request;
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
return string.Format("[ConnectionEventInfo SourceConnection: {0}, Event: {1}, State: {2}, ProtocolSupport: {3}]",
|
||
|
this.Source.ToString(), this.Event, this.State, this.ProtocolSupport);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class ConnectionEventHelper
|
||
|
{
|
||
|
private static ConcurrentQueue<ConnectionEventInfo> connectionEventQueue = new ConcurrentQueue<ConnectionEventInfo>();
|
||
|
|
||
|
#pragma warning disable 0649
|
||
|
public static Action<ConnectionEventInfo> OnEvent;
|
||
|
#pragma warning restore
|
||
|
|
||
|
public static void EnqueueConnectionEvent(ConnectionEventInfo @event)
|
||
|
{
|
||
|
if (HTTPManager.Logger.Level == Loglevels.All)
|
||
|
HTTPManager.Logger.Information("ConnectionEventHelper", "Enqueue connection event: " + @event.ToString(), @event.Source.Context);
|
||
|
|
||
|
connectionEventQueue.Enqueue(@event);
|
||
|
}
|
||
|
|
||
|
internal static void Clear()
|
||
|
{
|
||
|
connectionEventQueue.Clear();
|
||
|
}
|
||
|
|
||
|
internal static void ProcessQueue()
|
||
|
{
|
||
|
ConnectionEventInfo connectionEvent;
|
||
|
while (connectionEventQueue.TryDequeue(out connectionEvent))
|
||
|
{
|
||
|
if (HTTPManager.Logger.Level == Loglevels.All)
|
||
|
HTTPManager.Logger.Information("ConnectionEventHelper", "Processing connection event: " + connectionEvent.ToString(), connectionEvent.Source.Context);
|
||
|
|
||
|
if (OnEvent != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
OnEvent(connectionEvent);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
HTTPManager.Logger.Exception("ConnectionEventHelper", "ProcessQueue", ex, connectionEvent.Source.Context);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (connectionEvent.Source.LastProcessedUri == null)
|
||
|
{
|
||
|
HTTPManager.Logger.Information("ConnectionEventHelper", String.Format("Ignoring ConnectionEventInfo({0}) because its LastProcessedUri is null!", connectionEvent.ToString()));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (connectionEvent.Event)
|
||
|
{
|
||
|
case ConnectionEvents.StateChange:
|
||
|
HandleConnectionStateChange(connectionEvent);
|
||
|
break;
|
||
|
|
||
|
case ConnectionEvents.ProtocolSupport:
|
||
|
HostManager.GetHost(connectionEvent.Source.LastProcessedUri.Host)
|
||
|
.GetHostDefinition(connectionEvent.Source.ServerAddress)
|
||
|
.AddProtocol(connectionEvent.ProtocolSupport);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void HandleConnectionStateChange(ConnectionEventInfo @event)
|
||
|
{
|
||
|
var connection = @event.Source;
|
||
|
|
||
|
switch (@event.State)
|
||
|
{
|
||
|
case HTTPConnectionStates.Recycle:
|
||
|
HostManager.GetHost(connection.LastProcessedUri.Host)
|
||
|
.GetHostDefinition(connection.ServerAddress)
|
||
|
.RecycleConnection(connection)
|
||
|
.TryToSendQueuedRequests();
|
||
|
|
||
|
break;
|
||
|
|
||
|
case HTTPConnectionStates.WaitForProtocolShutdown:
|
||
|
HostManager.GetHost(connection.LastProcessedUri.Host)
|
||
|
.GetHostDefinition(connection.ServerAddress)
|
||
|
.RemoveConnection(connection, @event.State);
|
||
|
break;
|
||
|
|
||
|
case HTTPConnectionStates.Closed:
|
||
|
case HTTPConnectionStates.ClosedResendRequest:
|
||
|
// in case of ClosedResendRequest
|
||
|
if (@event.Request != null)
|
||
|
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(@event.Request, RequestEvents.Resend));
|
||
|
|
||
|
HostManager.GetHost(connection.LastProcessedUri.Host)
|
||
|
.GetHostDefinition(connection.ServerAddress)
|
||
|
.RemoveConnection(connection, @event.State)
|
||
|
.TryToSendQueuedRequests();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|