

using IRaCIS.Core.Application.MassTransit.Consumer;
using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace IRaCIS.Core.Application.MassTransit.Consumer;

/// <summary>
/// 参考链接：https://github.com/MassTransit/MassTransit/discussions/2498
/// </summary>
public static class MediatorHttpContextScopeFilterExtensions
{
    public static void UseHttpContextScopeFilter(this IMediatorConfigurator configurator, IServiceProvider serviceProvider)
    {
        var filter = new HttpContextScopeFilter(serviceProvider.GetRequiredService<IHttpContextAccessor>());

        configurator.ConfigurePublish(x => x.UseFilter(filter));
        configurator.ConfigureSend(x => x.UseFilter(filter));
        configurator.UseFilter(filter);
    }
}

public class HttpContextScopeFilter :
    IFilter<PublishContext>,
    IFilter<SendContext>,
    IFilter<ConsumeContext>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpContextScopeFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    private void AddPayload(PipeContext context)
    {
        if (_httpContextAccessor.HttpContext == null)
            return;

        var serviceProvider = _httpContextAccessor.HttpContext.RequestServices;
        context.GetOrAddPayload(() => serviceProvider);
        context.GetOrAddPayload<IServiceScope>(() => new NoopScope(serviceProvider));
    }

    public Task Send(PublishContext context, IPipe<PublishContext> next)
    {
        AddPayload(context);
        return next.Send(context);
    }

    public Task Send(SendContext context, IPipe<SendContext> next)
    {
        AddPayload(context);
        return next.Send(context);
    }

    public Task Send(ConsumeContext context, IPipe<ConsumeContext> next)
    {
        AddPayload(context);
        return next.Send(context);
    }

    public void Probe(ProbeContext context)
    {
    }

    private class NoopScope :
        IServiceScope
    {
        public NoopScope(IServiceProvider serviceProvider)
        {
            ServiceProvider = serviceProvider;
        }

        public void Dispose()
        {
        }

        public IServiceProvider ServiceProvider { get; }
    }
}