WebHook : UseFireAndForget + Delay (#803)

* UseFireAndForget

* ...

* delay

* async

* updated code accorsing to proposal

* Change nuget to package reference for WireMock.Net.Console.Net472.Classic, move the new FireAndForget into the main mapping, out of individual webhook mappings making it all or nothing, update tests, change Middleware to await or not the firing of all webhooks. Update models as needed. (#804)

Co-authored-by: Matt Philmon <Matt_Philmon@carmax.com>

* small update

* Tweak middleware and fix bug in example (#806)

Co-authored-by: Matt Philmon <Matt_Philmon@carmax.com>

* .ConfigureAwait(false)

Co-authored-by: mattisking <mattisking@gmail.com>
Co-authored-by: Matt Philmon <Matt_Philmon@carmax.com>
This commit is contained in:
Stef Heyenrath
2022-09-12 20:30:40 +02:00
committed by GitHub
parent 13a06b9b38
commit 98a0f2fa28
22 changed files with 670 additions and 460 deletions

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Stef.Validation;
using WireMock.Models;
@@ -17,6 +19,7 @@ namespace WireMock.Http;
internal class WebhookSender
{
private const string ClientIp = "::1";
private static readonly ThreadLocal<Random> Random = new(() => new Random(DateTime.UtcNow.Millisecond));
private readonly WireMockServerSettings _settings;
@@ -25,20 +28,26 @@ internal class WebhookSender
_settings = Guard.NotNull(settings);
}
public Task<HttpResponseMessage> SendAsync(HttpClient client, IMapping mapping, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
public async Task<HttpResponseMessage> SendAsync(
HttpClient client,
IMapping mapping,
IWebhookRequest webhookRequest,
IRequestMessage originalRequestMessage,
IResponseMessage originalResponseMessage
)
{
Guard.NotNull(client);
Guard.NotNull(mapping);
Guard.NotNull(request);
Guard.NotNull(webhookRequest);
Guard.NotNull(originalRequestMessage);
Guard.NotNull(originalResponseMessage);
IBodyData? bodyData;
IDictionary<string, WireMockList<string>>? headers;
if (request.UseTransformer == true)
if (webhookRequest.UseTransformer == true)
{
ITransformer responseMessageTransformer;
switch (request.TransformerType)
switch (webhookRequest.TransformerType)
{
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(_settings.FileSystemHandler, _settings.HandlebarsRegistrationCallback);
@@ -47,26 +56,26 @@ internal class WebhookSender
case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, request.TransformerType);
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType);
responseMessageTransformer = new Transformer(factoryDotLiquid);
break;
default:
throw new NotImplementedException($"TransformerType '{request.TransformerType}' is not supported.");
throw new NotImplementedException($"TransformerType '{webhookRequest.TransformerType}' is not supported.");
}
(bodyData, headers) = responseMessageTransformer.Transform(mapping, originalRequestMessage, originalResponseMessage, request.BodyData, request.Headers, request.TransformerReplaceNodeOptions);
(bodyData, headers) = responseMessageTransformer.Transform(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.Headers, webhookRequest.TransformerReplaceNodeOptions);
}
else
{
bodyData = request.BodyData;
headers = request.Headers;
bodyData = webhookRequest.BodyData;
headers = webhookRequest.Headers;
}
// Create RequestMessage
var requestMessage = new RequestMessage(
new UrlDetails(request.Url),
request.Method,
new UrlDetails(webhookRequest.Url),
webhookRequest.Method,
ClientIp,
bodyData,
headers?.ToDictionary(x => x.Key, x => x.Value.ToArray())
@@ -76,9 +85,30 @@ internal class WebhookSender
};
// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, request.Url);
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, webhookRequest.Url);
// Delay (if required)
if (TryGetDelay(webhookRequest, out var delay))
{
await Task.Delay(delay.Value).ConfigureAwait(false);
}
// Call the URL
return client.SendAsync(httpRequestMessage);
return await client.SendAsync(httpRequestMessage).ConfigureAwait(false);
}
private static bool TryGetDelay(IWebhookRequest webhookRequest, [NotNullWhen(true)] out int? delay)
{
delay = webhookRequest.Delay;
var minimumDelay = webhookRequest.MinimumRandomDelay;
var maximumDelay = webhookRequest.MaximumRandomDelay;
if (minimumDelay is not null && maximumDelay is not null && maximumDelay >= minimumDelay)
{
delay = Random.Value!.Next(minimumDelay.Value, maximumDelay.Value);
return true;
}
return delay is not null;
}
}