2023-06-21 06:28:40 +00:00
|
|
|
|
using Logging;
|
2023-04-13 07:33:10 +00:00
|
|
|
|
using Utils;
|
2023-04-12 11:53:55 +00:00
|
|
|
|
|
2023-09-12 11:32:06 +00:00
|
|
|
|
namespace Core
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2023-09-14 13:40:15 +00:00
|
|
|
|
public interface IHttp
|
|
|
|
|
{
|
2024-03-25 14:46:45 +00:00
|
|
|
|
T OnClient<T>(Func<HttpClient, T> action);
|
2024-03-26 08:10:06 +00:00
|
|
|
|
T OnClient<T>(Func<HttpClient, T> action, string description);
|
2024-06-05 07:20:00 +00:00
|
|
|
|
T OnClient<T>(Func<HttpClient, T> action, Retry retry);
|
2024-03-26 08:10:06 +00:00
|
|
|
|
IEndpoint CreateEndpoint(Address address, string baseUrl, string? logAlias = null);
|
2023-09-14 13:40:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal class Http : IHttp
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-08-01 09:19:05 +00:00
|
|
|
|
private static object lockLock = new object();
|
2024-07-25 08:10:11 +00:00
|
|
|
|
private static readonly Dictionary<string, object> httpLocks = new Dictionary<string, object>();
|
2023-09-11 14:57:57 +00:00
|
|
|
|
private readonly ILog log;
|
2023-05-04 06:55:20 +00:00
|
|
|
|
private readonly ITimeSet timeSet;
|
2023-08-13 09:19:35 +00:00
|
|
|
|
private readonly Action<HttpClient> onClientCreated;
|
2024-07-25 08:10:11 +00:00
|
|
|
|
private readonly string id;
|
2023-04-12 11:53:55 +00:00
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
internal Http(string id, ILog log, ITimeSet timeSet)
|
|
|
|
|
: this(id, log, timeSet, DoNothing)
|
2023-08-13 09:19:35 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
internal Http(string id, ILog log, ITimeSet timeSet, Action<HttpClient> onClientCreated)
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
this.id = id;
|
2023-04-30 08:08:32 +00:00
|
|
|
|
this.log = log;
|
2023-05-04 06:55:20 +00:00
|
|
|
|
this.timeSet = timeSet;
|
2023-08-13 09:19:35 +00:00
|
|
|
|
this.onClientCreated = onClientCreated;
|
2024-03-25 14:46:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T OnClient<T>(Func<HttpClient, T> action)
|
|
|
|
|
{
|
2024-03-26 08:10:06 +00:00
|
|
|
|
return OnClient(action, GetDescription());
|
2023-04-12 11:53:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-26 08:10:06 +00:00
|
|
|
|
public T OnClient<T>(Func<HttpClient, T> action, string description)
|
2024-06-05 07:20:00 +00:00
|
|
|
|
{
|
|
|
|
|
var retry = new Retry(description, timeSet.HttpRetryTimeout(), timeSet.HttpCallRetryDelay(), f => { });
|
|
|
|
|
return OnClient(action, retry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T OnClient<T>(Func<HttpClient, T> action, Retry retry)
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-03-26 08:10:06 +00:00
|
|
|
|
var client = GetClient();
|
2023-04-12 11:53:55 +00:00
|
|
|
|
|
2023-10-24 07:41:37 +00:00
|
|
|
|
return LockRetry(() =>
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-03-26 08:10:06 +00:00
|
|
|
|
return action(client);
|
2024-06-05 07:20:00 +00:00
|
|
|
|
}, retry);
|
2023-08-31 09:19:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-26 08:10:06 +00:00
|
|
|
|
public IEndpoint CreateEndpoint(Address address, string baseUrl, string? logAlias = null)
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-03-26 08:10:06 +00:00
|
|
|
|
return new Endpoint(log, this, address, baseUrl, logAlias);
|
2023-04-12 11:53:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-26 08:10:06 +00:00
|
|
|
|
private string GetDescription()
|
2023-04-30 08:08:32 +00:00
|
|
|
|
{
|
2024-03-26 08:10:06 +00:00
|
|
|
|
return DebugStack.GetCallerName(skipFrames: 2);
|
2023-04-30 08:08:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 07:20:00 +00:00
|
|
|
|
private T LockRetry<T>(Func<T> operation, Retry retry)
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
2024-07-25 08:10:11 +00:00
|
|
|
|
var httpLock = GetLock();
|
2023-10-24 07:41:37 +00:00
|
|
|
|
lock (httpLock)
|
|
|
|
|
{
|
2024-06-05 07:20:00 +00:00
|
|
|
|
return retry.Run(operation);
|
2023-10-24 07:41:37 +00:00
|
|
|
|
}
|
2023-04-19 08:42:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-25 08:10:11 +00:00
|
|
|
|
private object GetLock()
|
|
|
|
|
{
|
2024-08-01 09:19:05 +00:00
|
|
|
|
lock (lockLock) // I had to.
|
|
|
|
|
{
|
|
|
|
|
if (!httpLocks.ContainsKey(id)) httpLocks.Add(id, new object());
|
|
|
|
|
return httpLocks[id];
|
|
|
|
|
}
|
2024-07-25 08:10:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 06:55:20 +00:00
|
|
|
|
private HttpClient GetClient()
|
2023-04-12 11:53:55 +00:00
|
|
|
|
{
|
|
|
|
|
var client = new HttpClient();
|
2023-07-17 13:21:10 +00:00
|
|
|
|
client.Timeout = timeSet.HttpCallTimeout();
|
2023-08-13 09:19:35 +00:00
|
|
|
|
onClientCreated(client);
|
2023-04-12 11:53:55 +00:00
|
|
|
|
return client;
|
|
|
|
|
}
|
2023-08-13 09:19:35 +00:00
|
|
|
|
|
|
|
|
|
private static void DoNothing(HttpClient client)
|
|
|
|
|
{
|
|
|
|
|
}
|
2023-04-12 11:53:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|