1
This commit is contained in:
parent
4262004ae6
commit
d40e83ba9c
@ -16,9 +16,10 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\InterfaceForward.Application\InterfaceForward.Application.csproj" />
|
<ProjectReference Include="..\InterfaceForward.Application\InterfaceForward.Application.csproj" />
|
||||||
<ProjectReference Include="..\InterfaceForward.ServiceDefaults\InterfaceForward.ServiceDefaults.csproj"/>
|
<ProjectReference Include="..\InterfaceForward.ServiceDefaults\InterfaceForward.ServiceDefaults.csproj"/>
|
||||||
<PackageReference Include="Fake.Autofac" Version="8.0.1" />
|
<PackageReference Include="Fake.Autofac" Version="8.0.0-preview.3" />
|
||||||
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
|
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -32,7 +32,8 @@
|
|||||||
},
|
},
|
||||||
"FeiShuNotice": {
|
"FeiShuNotice": {
|
||||||
"Title": "InterfaceForward-Dev",
|
"Title": "InterfaceForward-Dev",
|
||||||
"Webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/255c44ff-5891-4902-9b6a-6d0250e745f7"
|
"Webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/255c44ff-5891-4902-9b6a-6d0250e745f7",
|
||||||
|
"Timeout": 20
|
||||||
},
|
},
|
||||||
"RabbitMQ": {
|
"RabbitMQ": {
|
||||||
"Default": {
|
"Default": {
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting" Version="8.2.2" />
|
<PackageReference Include="Aspire.Hosting" Version="8.2.2" />
|
||||||
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.2" />
|
||||||
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
namespace InterfaceForward.Application.Contracts.Dtos.App;
|
||||||
|
|
||||||
|
public class DeleteAppSubscribeConfigInput
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 应用key
|
||||||
|
/// </summary>
|
||||||
|
public string AppKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统接口code
|
||||||
|
/// </summary>
|
||||||
|
public string SystemInterfaceCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务商code
|
||||||
|
/// </summary>
|
||||||
|
public string ServiceProviderCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 【慎重!】删除队列(删除专用,一般false,即接口通只解除绑定,不删除队列)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDeleteQueue { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
namespace InterfaceForward.Application.Contracts.Dtos.App;
|
||||||
|
|
||||||
|
public class UpsertAppSubscribeConfigInput
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 应用key
|
||||||
|
/// </summary>
|
||||||
|
public string AppKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统接口code
|
||||||
|
/// </summary>
|
||||||
|
public string SystemInterfaceCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务商code
|
||||||
|
/// </summary>
|
||||||
|
public string ServiceProviderCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 【慎重!】mq预取数量(服务并发度,给0就是默认1)
|
||||||
|
/// </summary>
|
||||||
|
public ushort FetchCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 【慎重!】失败重回队列(一般false,即接口通不做重试,否则业务错误可能死循环)
|
||||||
|
/// </summary>
|
||||||
|
public bool FailedRequeue { get; set; }
|
||||||
|
}
|
||||||
@ -13,14 +13,12 @@ public interface IInterfaceForwardService
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="upStreamCode">系统接口code</param>
|
/// <param name="upStreamCode">系统接口code</param>
|
||||||
/// <param name="serviceProviderCode">服务商code</param>
|
/// <param name="serviceProviderCode">服务商code</param>
|
||||||
/// <param name="mainBodyId">主体id</param>
|
|
||||||
/// <param name="data">body</param>
|
/// <param name="data">body</param>
|
||||||
/// <param name="attach">额外信息,原样返回</param>
|
/// <param name="attach">额外信息,原样返回</param>
|
||||||
/// <param name="isReturnMessage">是否返回原报文</param>
|
/// <param name="isReturnMessage">是否返回原报文</param>
|
||||||
/// <param name="failedSubscribeName">失败推送订阅名,不填就不推</param>
|
/// <param name="failedSubscribeName">失败推送订阅名,不填就不推</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<InterfaceRelayUnifyResultDto> ForwardWithSubscribeAsync(string upStreamCode, string serviceProviderCode,
|
Task<InterfaceRelayUnifyResultDto> ForwardWithSubscribeAsync(string upStreamCode, string serviceProviderCode,
|
||||||
int mainBodyId,
|
|
||||||
object data, string? attach = null, bool isReturnMessage = false, string? failedSubscribeName = null);
|
object data, string? attach = null, bool isReturnMessage = false, string? failedSubscribeName = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,7 +26,6 @@ public interface IInterfaceForwardService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="upStreamCode">系统接口code</param>
|
/// <param name="upStreamCode">系统接口code</param>
|
||||||
/// <param name="serviceProviderCode">服务商code</param>
|
/// <param name="serviceProviderCode">服务商code</param>
|
||||||
/// <param name="mainBodyId">主体id</param>
|
|
||||||
/// <param name="requestId">请求id</param>
|
/// <param name="requestId">请求id</param>
|
||||||
/// <param name="data">body</param>
|
/// <param name="data">body</param>
|
||||||
/// <param name="attach">额外信息,原样返回</param>
|
/// <param name="attach">额外信息,原样返回</param>
|
||||||
@ -36,6 +33,6 @@ public interface IInterfaceForwardService
|
|||||||
/// <param name="failedSubscribeName">失败推送订阅名,不填就不推</param>
|
/// <param name="failedSubscribeName">失败推送订阅名,不填就不推</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<InterfaceRelayUnifyResultDto> ReForwardAsync(string upStreamCode, string serviceProviderCode,
|
Task<InterfaceRelayUnifyResultDto> ReForwardAsync(string upStreamCode, string serviceProviderCode,
|
||||||
int mainBodyId, Guid requestId, object data, string? attach = null,
|
Guid requestId, object data, string? attach = null,
|
||||||
bool isReturnMessage = false, string? failedSubscribeName = null);
|
bool isReturnMessage = false, string? failedSubscribeName = null);
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
namespace SJZY.InterfaceRelay.Application.Contracts;
|
namespace InterfaceForward.Application.Contracts.ForwardCore;
|
||||||
|
|
||||||
public class InterfaceForwardOptions
|
public class InterfaceForwardOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
namespace SJZY.InterfaceRelay.Application.Contracts;
|
namespace InterfaceForward.Application.Contracts.ForwardCore;
|
||||||
|
|
||||||
public class InterfaceRelayForwardReplayEvent
|
public class InterfaceRelayForwardReplayEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,16 +3,15 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class InterfaceRelayUnifyResultDto
|
public class InterfaceRelayUnifyResultDto
|
||||||
{
|
{
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public string Msg { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 请求Id
|
/// 请求Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid RequestId { get; set; }
|
public Guid RequestId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 消息
|
|
||||||
/// </summary>
|
|
||||||
public string? Message { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 原报文
|
/// 原报文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
namespace SJZY.InterfaceRelay.Application.Contracts;
|
namespace InterfaceForward.Application.Contracts;
|
||||||
|
|
||||||
public class RequestServiceProviderFailedEvent
|
public class RequestServiceProviderFailedEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,4 +9,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\InterfaceForward.Domain.Shared\InterfaceForward.Domain.Shared.csproj" />
|
<ProjectReference Include="..\InterfaceForward.Domain.Shared\InterfaceForward.Domain.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Fake.Application;
|
using Fake.Application;
|
||||||
using Fake.AspNetCore.Http;
|
using Fake.AspNetCore.Http;
|
||||||
using InterfaceForward.Repositories;
|
using InterfaceForward.Repositories;
|
||||||
|
using InterfaceForward.Repositories.Interface.Entitys;
|
||||||
using InterfaceForward.Repositories.Log.Services;
|
using InterfaceForward.Repositories.Log.Services;
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -13,7 +14,8 @@ namespace InterfaceForward.Application.Filters;
|
|||||||
public class ForwardAuthorizeFilter(
|
public class ForwardAuthorizeFilter(
|
||||||
InterfaceForwardQuery interfaceForwardQuery,
|
InterfaceForwardQuery interfaceForwardQuery,
|
||||||
ILogRepository logRepository,
|
ILogRepository logRepository,
|
||||||
IHttpClientInfoProvider httpClientInfoProvider)
|
IHttpClientInfoProvider httpClientInfoProvider,
|
||||||
|
IBasicRepository<InterfaceEntity> interfaceRepository)
|
||||||
: IAsyncActionFilter
|
: IAsyncActionFilter
|
||||||
{
|
{
|
||||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
@ -27,7 +29,7 @@ public class ForwardAuthorizeFilter(
|
|||||||
|
|
||||||
log.IsApp = true;
|
log.IsApp = true;
|
||||||
|
|
||||||
log.ClientIp = httpClientInfoProvider.ClientIpAddress;
|
log.ClientIP = httpClientInfoProvider.ClientIpAddress;
|
||||||
log.Address = httpContext.Request.GetDisplayUrl();
|
log.Address = httpContext.Request.GetDisplayUrl();
|
||||||
|
|
||||||
// body
|
// body
|
||||||
@ -41,7 +43,6 @@ public class ForwardAuthorizeFilter(
|
|||||||
var headers = httpContext.Request.Headers;
|
var headers = httpContext.Request.Headers;
|
||||||
log.Headers = JsonConvert.SerializeObject(headers);
|
log.Headers = JsonConvert.SerializeObject(headers);
|
||||||
|
|
||||||
// _segContext.Context.Span.AddLog(LogEvent.Message("开始应用授权"));
|
|
||||||
string? appKey = headers["appKey"], appSecret = headers["appSecret"];
|
string? appKey = headers["appKey"], appSecret = headers["appSecret"];
|
||||||
if (appKey.IsNullOrWhiteSpace() || appSecret.IsNullOrWhiteSpace())
|
if (appKey.IsNullOrWhiteSpace() || appSecret.IsNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
@ -57,6 +58,13 @@ public class ForwardAuthorizeFilter(
|
|||||||
|
|
||||||
logRepository.AppId = app.Id;
|
logRepository.AppId = app.Id;
|
||||||
|
|
||||||
|
var upStreamCode = httpContext.Request.Query["upStreamCode"].ToString();
|
||||||
|
var systemInterface = await interfaceRepository.GetFirstAsync(x => x.Code == upStreamCode,
|
||||||
|
x => new { x.Code, x.Name });
|
||||||
|
if (systemInterface == null) throw new BusinessException(message: "系统接口不存在");
|
||||||
|
logRepository.AppRequestLog.InterfaceCode = systemInterface.Code;
|
||||||
|
logRepository.AppRequestLog.InterfaceName = systemInterface.Name;
|
||||||
|
|
||||||
var actionContext = await next();
|
var actionContext = await next();
|
||||||
|
|
||||||
if (actionContext.Exception == null)
|
if (actionContext.Exception == null)
|
||||||
@ -72,7 +80,7 @@ public class ForwardAuthorizeFilter(
|
|||||||
log.Response = actionContext.Result?.ToString()?? string.Empty;
|
log.Response = actionContext.Result?.ToString()?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = logRepository.WriteAppLogAsync();
|
_ = logRepository.WriteAppLog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using InterfaceForward.Application.Contracts;
|
||||||
|
using InterfaceForward.Application.Contracts.ForwardCore;
|
||||||
|
using InterfaceForward.Application.Rabbit;
|
||||||
|
using InterfaceForward.Repositories.Log.Services;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Application.Filters;
|
||||||
|
|
||||||
|
public class ForwardExceptionFilter(
|
||||||
|
ILogRepository logRepository,
|
||||||
|
IOptions<InterfaceRelayOptions> options,
|
||||||
|
RabbitClient rabbitClient)
|
||||||
|
: IAsyncExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly InterfaceRelayOptions _options = options.Value;
|
||||||
|
|
||||||
|
public Task OnExceptionAsync(ExceptionContext context)
|
||||||
|
{
|
||||||
|
if (context.ExceptionHandled) return Task.CompletedTask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ServiceProviderRequestLog设计的意义是:
|
||||||
|
* 最大可能限度的保留请求服务商发生异常时附近的日志信息,以便于排查问题
|
||||||
|
*/
|
||||||
|
var originMessage = bool.TryParse(context.HttpContext.Request.Headers["isReturnMessage"].ToString(),
|
||||||
|
out var isReturnMessage)
|
||||||
|
? isReturnMessage ? logRepository.ServiceProviderRequestLog.Response : null
|
||||||
|
: null;
|
||||||
|
|
||||||
|
var res = new InterfaceRelayUnifyResultDto
|
||||||
|
{
|
||||||
|
Code = StatusCodes.Status400BadRequest.ToString(),
|
||||||
|
RequestId = logRepository.AppRequestLog.RequestId,
|
||||||
|
OriginalMessage = originMessage,
|
||||||
|
Attach = context.HttpContext.Request.Headers["attach"]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (context.Exception is ValidationException errors) //验证异常
|
||||||
|
{
|
||||||
|
res.Msg = errors.Message;
|
||||||
|
context.Result = new JsonResult(res);
|
||||||
|
}
|
||||||
|
else if (context.Exception is BusinessException business) //业务异常
|
||||||
|
{
|
||||||
|
res.Msg = business.Message;
|
||||||
|
context.Result = new JsonResult(res);
|
||||||
|
}
|
||||||
|
else //未处理异常
|
||||||
|
{
|
||||||
|
logRepository.SendFeiShu(context.Exception);
|
||||||
|
res.Code = StatusCodes.Status500InternalServerError.ToString();
|
||||||
|
res.Msg = "服务器发生未处理异常";
|
||||||
|
context.Result = new JsonResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NeedPush(context, out var subscribeName))
|
||||||
|
{
|
||||||
|
// todo:要改成http回调的方式?
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异常情况也要记录app日志
|
||||||
|
logRepository.AppRequestLog.Response = JsonConvert.SerializeObject(res);
|
||||||
|
_ = logRepository.WriteAppLog(context.Exception);
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool NeedPush(ExceptionContext context, out string subscribeName)
|
||||||
|
{
|
||||||
|
subscribeName = null;
|
||||||
|
string interfaceCode = context.HttpContext.Request.Query["upStreamCode"];
|
||||||
|
subscribeName = context.HttpContext.Request.Headers["failedSubscribeName"];
|
||||||
|
|
||||||
|
return _options.FailedNeedPush.Contains(interfaceCode) && !subscribeName.IsNullOrWhiteSpace();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,55 +0,0 @@
|
|||||||
using Fake.ExceptionHandling;
|
|
||||||
using InterfaceForward.Application.Contracts.ForwardCore;
|
|
||||||
using InterfaceForward.Domain.Shared.FeiShu;
|
|
||||||
using InterfaceForward.Repositories.Log.Services;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
namespace InterfaceForward.Application.Filters;
|
|
||||||
|
|
||||||
public class ForwardExceptionSubscriber : IExceptionSubscriber
|
|
||||||
{
|
|
||||||
public Task HandleAsync(ExceptionNotificationContext context)
|
|
||||||
{
|
|
||||||
var httpContext = context.ServiceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
|
|
||||||
var logRepository = context.ServiceProvider.GetRequiredService<ILogRepository>();
|
|
||||||
var feiShuNoticer = context.ServiceProvider.GetRequiredService<IFeiShuNoticer>();
|
|
||||||
|
|
||||||
// if (httpContext == null)
|
|
||||||
// {
|
|
||||||
// feiShuNoticer.NoticeAsync($"""
|
|
||||||
// 日志请求id:{ServiceProviderRequestLog.RequestId}
|
|
||||||
// 服务商--接口:{ServiceProviderRequestLog.Name}--{ServiceProviderRequestLog.InterfaceName}
|
|
||||||
// 异常原因:{Truncate(contextException.ToString())}
|
|
||||||
// 请求地址:{ServiceProviderRequestLog.Address}
|
|
||||||
// 原始报文:
|
|
||||||
// {Truncate(AppRequestLog.Content)}
|
|
||||||
// 请求报文:
|
|
||||||
// {Truncate(ServiceProviderRequestLog.Content)}
|
|
||||||
// 响应报文:
|
|
||||||
// {Truncate(ServiceProviderRequestLog.Response)}
|
|
||||||
// """)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
* ServiceProviderRequestLog设计的意义是:
|
|
||||||
* 最大可能限度的保留请求服务商发生异常时附近的日志信息,以便于排查问题
|
|
||||||
*/
|
|
||||||
var originMessage = bool.TryParse(httpContext.Request.Headers["isReturnMessage"].ToString(),
|
|
||||||
out var isReturnMessage)
|
|
||||||
? isReturnMessage ? logRepository.ServiceProviderRequestLog.Response : null
|
|
||||||
: null;
|
|
||||||
var res = new InterfaceRelayUnifyResultDto
|
|
||||||
{
|
|
||||||
RequestId = logRepository.AppRequestLog.RequestId,
|
|
||||||
OriginalMessage = originMessage,
|
|
||||||
Message = context.Exception.Message,
|
|
||||||
Attach = httpContext.Request.Headers["attach"]
|
|
||||||
};
|
|
||||||
logRepository.AppRequestLog.Response = JsonConvert.SerializeObject(res);
|
|
||||||
// 异常情况也要记录app日志
|
|
||||||
_ = logRepository.WriteAppLogAsync(context.Exception);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -249,7 +249,7 @@ public class DefaultForwardFlow : IForwardFlow
|
|||||||
public virtual void BeforeRequest(ForwardCoreContext context)
|
public virtual void BeforeRequest(ForwardCoreContext context)
|
||||||
{
|
{
|
||||||
var log = context.ServiceProviderRequestLog;
|
var log = context.ServiceProviderRequestLog;
|
||||||
log.ClientIp = NetUtil.GetLanIp();
|
log.ClientIP = NetUtil.GetLanIp();
|
||||||
log.Content = context.TargetInterfaceInput;
|
log.Content = context.TargetInterfaceInput;
|
||||||
|
|
||||||
context.ServiceProviderRequestLog.RequestTime = DateTime.Now;
|
context.ServiceProviderRequestLog.RequestTime = DateTime.Now;
|
||||||
|
|||||||
@ -3,20 +3,13 @@ using Fake.DependencyInjection;
|
|||||||
using InterfaceForward.Application.Rabbit;
|
using InterfaceForward.Application.Rabbit;
|
||||||
using InterfaceForward.Domain.Shared;
|
using InterfaceForward.Domain.Shared;
|
||||||
using InterfaceForward.Domain.Shared.Enum;
|
using InterfaceForward.Domain.Shared.Enum;
|
||||||
using Microsoft.IdentityModel.Logging;
|
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
namespace InterfaceForward.Application.HostServices;
|
namespace InterfaceForward.Application.HostServices;
|
||||||
|
|
||||||
public class AppSubscribeEventHandler : ITransientDependency
|
public class AppSubscribeEventHandler(RabbitClient rabbitClient) : ITransientDependency
|
||||||
{
|
{
|
||||||
public const string AppSubscribeEventSubscribe = "sjzy.interface.relay.app.subscribe";
|
public const string AppSubscribeEventSubscribe = "interface.relay.app.subscribe";
|
||||||
private readonly RabbitClient _rabbitClient;
|
|
||||||
|
|
||||||
public AppSubscribeEventHandler(RabbitClient rabbitClient)
|
|
||||||
{
|
|
||||||
_rabbitClient = rabbitClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task Handle(AppSubscribeEvent @event)
|
public Task Handle(AppSubscribeEvent @event)
|
||||||
{
|
{
|
||||||
@ -26,15 +19,15 @@ public class AppSubscribeEventHandler : ITransientDependency
|
|||||||
break;
|
break;
|
||||||
case OptionType.新增:
|
case OptionType.新增:
|
||||||
var res = DoAdd(@event);
|
var res = DoAdd(@event);
|
||||||
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res}", true);
|
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res}");
|
||||||
break;
|
break;
|
||||||
case OptionType.修改:
|
case OptionType.修改:
|
||||||
var res1 = DoUpdate(@event);
|
var res1 = DoUpdate(@event);
|
||||||
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res1}", true);
|
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res1}");
|
||||||
break;
|
break;
|
||||||
case OptionType.删除:
|
case OptionType.删除:
|
||||||
var res2 = DoDelete(@event);
|
var res2 = DoDelete(@event);
|
||||||
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res2}", true);
|
LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res2}");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
@ -47,9 +40,9 @@ public class AppSubscribeEventHandler : ITransientDependency
|
|||||||
{
|
{
|
||||||
var queueName =
|
var queueName =
|
||||||
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
||||||
_rabbitClient.UnSubscribe(queueName, GlobalConst.InterfaceRelayExchange, queueName, @event.IsDeleteQueue);
|
rabbitClient.UnSubscribe(queueName, GlobalConst.InterfaceRelayExchange, queueName, @event.IsDeleteQueue);
|
||||||
|
|
||||||
_rabbitClient.Subscribe(new ConsumeOptions
|
rabbitClient.Subscribe(new ConsumeOptions
|
||||||
{
|
{
|
||||||
Queue = queueName,
|
Queue = queueName,
|
||||||
FetchCount = @event.FetchCount, // 并发控制
|
FetchCount = @event.FetchCount, // 并发控制
|
||||||
@ -69,7 +62,7 @@ public class AppSubscribeEventHandler : ITransientDependency
|
|||||||
{
|
{
|
||||||
var queueName =
|
var queueName =
|
||||||
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
||||||
_rabbitClient.UnSubscribe(queueName, GlobalConst.InterfaceRelayExchange, queueName, @event.IsDeleteQueue);
|
rabbitClient.UnSubscribe(queueName, GlobalConst.InterfaceRelayExchange, queueName, @event.IsDeleteQueue);
|
||||||
return $"已成功{(@event.IsDeleteQueue ? "删除" : "解绑")}队列:{queueName},可以通过/AppSubscribe/GetList查询所有订阅";
|
return $"已成功{(@event.IsDeleteQueue ? "删除" : "解绑")}队列:{queueName},可以通过/AppSubscribe/GetList查询所有订阅";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +70,7 @@ public class AppSubscribeEventHandler : ITransientDependency
|
|||||||
{
|
{
|
||||||
var queueName =
|
var queueName =
|
||||||
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
$"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}";
|
||||||
_rabbitClient.Subscribe(new ConsumeOptions
|
rabbitClient.Subscribe(new ConsumeOptions
|
||||||
{
|
{
|
||||||
Queue = queueName,
|
Queue = queueName,
|
||||||
FetchCount = @event.FetchCount, // 并发控制
|
FetchCount = @event.FetchCount, // 并发控制
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
using Fake.Helpers;
|
using Fake.SyncEx;
|
||||||
using InterfaceForward.Application.Helpers;
|
using InterfaceForward.Application.Helpers;
|
||||||
using InterfaceForward.Application.Rabbit;
|
using InterfaceForward.Application.Rabbit;
|
||||||
using InterfaceForward.Domain.Shared;
|
using InterfaceForward.Domain.Shared;
|
||||||
using InterfaceForward.Repositories;
|
using InterfaceForward.Repositories;
|
||||||
|
using InterfaceForward.Repositories.App.Entitys;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.IdentityModel.Logging;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ namespace InterfaceForward.Application.HostServices;
|
|||||||
public class AppSubscribeHostService : IHostedService
|
public class AppSubscribeHostService : IHostedService
|
||||||
{
|
{
|
||||||
private readonly AppSubscribeEventHandler _appSubscribeEventHandler;
|
private readonly AppSubscribeEventHandler _appSubscribeEventHandler;
|
||||||
|
private readonly IBasicRepository<AppSubscribeConfigEntity> _appSubscribeConfigRepository;
|
||||||
private readonly RabbitClient _rabbitClient;
|
private readonly RabbitClient _rabbitClient;
|
||||||
|
|
||||||
public AppSubscribeHostService(IBasicRepository<AppSubscribeConfigEntity> appSubscribeConfigRepository,
|
public AppSubscribeHostService(IBasicRepository<AppSubscribeConfigEntity> appSubscribeConfigRepository,
|
||||||
@ -63,7 +64,7 @@ public class AppSubscribeHostService : IHostedService
|
|||||||
if (chan == AppSubscribeEventHandler.AppSubscribeEventSubscribe && msg is string str)
|
if (chan == AppSubscribeEventHandler.AppSubscribeEventSubscribe && msg is string str)
|
||||||
{
|
{
|
||||||
var @event = JsonConvert.DeserializeObject<AppSubscribeEvent>(str);
|
var @event = JsonConvert.DeserializeObject<AppSubscribeEvent>(str);
|
||||||
AsyncHelper.RunSync(() => _appSubscribeEventHandler.Handle(@event));
|
SyncContext.Run(() => _appSubscribeEventHandler.Handle(@event!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,9 +17,10 @@
|
|||||||
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
|
||||||
<PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.2.2.1"/>
|
<PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.2.2.1"/>
|
||||||
<PackageReference Include="Fake.AspNetCore" Version="8.0.1" />
|
<PackageReference Include="Fake.AspNetCore" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="Fake.EventBus.RabbitMQ" Version="8.0.1" />
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="Fake.ObjectMapping.AutoMapper" Version="8.0.1" />
|
<PackageReference Include="Fake.EventBus.RabbitMQ" Version="8.0.0-preview.3" />
|
||||||
|
<PackageReference Include="Fake.ObjectMapping.AutoMapper" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="FreeRedis" Version="1.2.15" />
|
<PackageReference Include="FreeRedis" Version="1.2.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,9 @@ public class BatchForwardEvent
|
|||||||
|
|
||||||
public int AppId { get; set; }
|
public int AppId { get; set; }
|
||||||
|
|
||||||
public string UpStreamCode { get; set; }
|
public string UpStreamCode { get; set; } = null!;
|
||||||
|
|
||||||
public string ServiceProviderCode { get; set; }
|
public string ServiceProviderCode { get; set; } = null!;
|
||||||
|
|
||||||
public string Attach { get; set; }
|
public string Attach { get; set; }
|
||||||
|
|
||||||
@ -16,5 +16,5 @@ public class BatchForwardEvent
|
|||||||
|
|
||||||
public bool IsReturnMessage { get; set; }
|
public bool IsReturnMessage { get; set; }
|
||||||
|
|
||||||
public string Data { get; set; }
|
public string Data { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@ -3,37 +3,35 @@ using Fake.DependencyInjection;
|
|||||||
using InterfaceForward.Application.Contracts.ForwardCore;
|
using InterfaceForward.Application.Contracts.ForwardCore;
|
||||||
using InterfaceForward.Application.Services;
|
using InterfaceForward.Application.Services;
|
||||||
using InterfaceForward.Domain.Shared;
|
using InterfaceForward.Domain.Shared;
|
||||||
using InterfaceForward.Domain.Shared.FeiShu;
|
|
||||||
using InterfaceForward.Repositories.Log.Services;
|
using InterfaceForward.Repositories.Log.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using SJZY.InterfaceRelay.Application.Contracts;
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
namespace InterfaceForward.Application.Rabbit;
|
namespace InterfaceForward.Application.Rabbit;
|
||||||
|
|
||||||
public class BatchForwardEventHandler(
|
public class BatchForwardEventHandler(
|
||||||
InterfaceForwardCommon forwardCommon,
|
InterfaceForwardCommon forwardCommon,
|
||||||
RabbitClient rabbitClient,
|
RabbitClient rabbitClient,
|
||||||
ILogRepository logRepository,
|
ILogRepository logRepository)
|
||||||
ILogger<BatchForwardEventHandler> logger,
|
|
||||||
IFeiShuNoticer feiShuNoticer)
|
|
||||||
: ITransientDependency, IRabbitHandler
|
: ITransientDependency, IRabbitHandler
|
||||||
{
|
{
|
||||||
public const string BatchForwardEventSubscribe = "sjzy.interface.relay.batch";
|
public const string BatchForwardEventSubscribe = "interface.relay.batch";
|
||||||
private readonly RabbitClient _rabbitClient = rabbitClient;
|
|
||||||
|
|
||||||
public bool Enable(ConsumeOptions options)
|
public bool Enable(ConsumeOptions options)
|
||||||
{
|
{
|
||||||
return options.Queue.StartsWith(BatchForwardEventSubscribe);
|
return options.Queue.StartsWith(BatchForwardEventSubscribe);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(IServiceProvider sp, BasicDeliverEventArgs args, ConsumeOptions options)
|
public async Task Handle(BasicDeliverEventArgs args)
|
||||||
{
|
{
|
||||||
var msg = Encoding.UTF8.GetString(args.Body.ToArray());
|
var msg = Encoding.UTF8.GetString(args.Body.ToArray());
|
||||||
logger.LogDebug($"rabbit on queue({options.Queue}) received msg");
|
|
||||||
|
|
||||||
var @event = System.Text.Json.JsonSerializer.Deserialize<BatchForwardEvent>(msg);
|
var @event = System.Text.Json.JsonSerializer.Deserialize<BatchForwardEvent>(msg);
|
||||||
|
if (@event == null)
|
||||||
|
{
|
||||||
|
throw new BusinessException("消息格式错误");
|
||||||
|
}
|
||||||
|
|
||||||
// important:恢复应用现场 全局贯彻
|
// important:恢复应用现场 全局贯彻
|
||||||
logRepository.AppId = @event.AppId;
|
logRepository.AppId = @event.AppId;
|
||||||
@ -71,7 +69,7 @@ public class BatchForwardEventHandler(
|
|||||||
? req
|
? req
|
||||||
: new JObject
|
: new JObject
|
||||||
{
|
{
|
||||||
[@event.UpStreamCode!] = req
|
[@event.UpStreamCode] = req
|
||||||
};
|
};
|
||||||
|
|
||||||
var res = contextList.Count == 1
|
var res = contextList.Count == 1
|
||||||
@ -85,12 +83,12 @@ public class BatchForwardEventHandler(
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
replayEvent.Message = ex.Message;
|
replayEvent.Message = ex.Message;
|
||||||
await feiShuNoticer.NoticeAsync(ex.ToString());
|
LogHelper.Error(ex.ToString(), false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
var data = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(replayEvent);
|
var data = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(replayEvent);
|
||||||
_rabbitClient.Publish(GlobalConst.InterfaceRelayExchange, @event.ResSubscribeName, data);
|
rabbitClient.Publish(GlobalConst.InterfaceRelayExchange, @event.ResSubscribeName, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
10
src/InterfaceForward.Application/Rabbit/IRabbitHandler.cs
Normal file
10
src/InterfaceForward.Application/Rabbit/IRabbitHandler.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Application.Rabbit;
|
||||||
|
|
||||||
|
public interface IRabbitHandler
|
||||||
|
{
|
||||||
|
bool Enable(ConsumeOptions options);
|
||||||
|
|
||||||
|
Task Handle(BasicDeliverEventArgs args);
|
||||||
|
}
|
||||||
@ -1,20 +1,23 @@
|
|||||||
using System.Text;
|
|
||||||
using Fake.RabbitMQ;
|
using Fake.RabbitMQ;
|
||||||
using InterfaceForward.Domain.Shared;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using RabbitMQ.Client.Events;
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
namespace InterfaceForward.Application.Rabbit;
|
namespace InterfaceForward.Application.Rabbit;
|
||||||
|
|
||||||
public class RabbitClient(IRabbitMqChannelPool channelPool)
|
public class RabbitClient(
|
||||||
|
IRabbitMqChannelPool channelPool,
|
||||||
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
|
ILogger<RabbitClient> logger)
|
||||||
{
|
{
|
||||||
public void Subscribe(ConsumeOptions consumeOptions)
|
public void Subscribe(ConsumeOptions consumeOptions)
|
||||||
{
|
{
|
||||||
using var channelAccessor = channelPool.Acquire(consumeOptions.Queue, configureChannel: channel =>
|
using var channelAccessor = channelPool.Acquire(consumeOptions.Queue);
|
||||||
{
|
|
||||||
channel.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true);
|
var channel = channelAccessor.Channel;
|
||||||
channel.QueueDeclare(consumeOptions.Queue, true);
|
|
||||||
channel.QueueBind(consumeOptions.Queue, GlobalConst.InterfaceRelayExchange, consumeOptions.Queue);
|
consumeOptions.Declaration.Invoke(channel);
|
||||||
|
|
||||||
if (consumeOptions.FetchCount > 0)
|
if (consumeOptions.FetchCount > 0)
|
||||||
{
|
{
|
||||||
@ -24,15 +27,42 @@ public class RabbitClient(IRabbitMqChannelPool channelPool)
|
|||||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
var consumer = new AsyncEventingBasicConsumer(channel);
|
||||||
consumer.Received += async (model, ea) =>
|
consumer.Received += async (model, ea) =>
|
||||||
{
|
{
|
||||||
var body = ea.Body.ToArray();
|
await using var scope = serviceScopeFactory.CreateAsyncScope();
|
||||||
var message = Encoding.UTF8.GetString(body);
|
foreach (var handler in scope.ServiceProvider.GetServices<IRabbitHandler>())
|
||||||
Console.WriteLine(" [x] Received {0}", message);
|
{
|
||||||
|
if (handler.Enable(consumeOptions))
|
||||||
|
{
|
||||||
|
await handler.Handle(ea);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
channel.BasicConsume(queue: consumeOptions.Queue,
|
channel.BasicConsume(queue: consumeOptions.Queue,
|
||||||
autoAck: false,
|
autoAck: false,
|
||||||
consumer: consumer);
|
consumer: consumer);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
public void Publish(string exchange, string routingKey, byte[] data, Action<IBasicProperties>? options = null)
|
||||||
|
{
|
||||||
|
using var channelAccessor = channelPool.Acquire(routingKey);
|
||||||
|
var props = channelAccessor.Channel.CreateBasicProperties();
|
||||||
|
options?.Invoke(props);
|
||||||
|
channelAccessor.Channel.BasicPublish(exchange, routingKey, props, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnSubscribe(string queueName, string exchange, string routingKey, bool deleteQueue = false)
|
||||||
|
{
|
||||||
|
logger.LogInformation(
|
||||||
|
$"UnSubscribe queue: {queueName} exchange: {exchange} routingKey: {routingKey} deleteQueue: {deleteQueue}");
|
||||||
|
using var channelAccessor = channelPool.Acquire(queueName);
|
||||||
|
if (deleteQueue)
|
||||||
|
{
|
||||||
|
var passive = channelAccessor.Channel.QueueDeclarePassive(queueName);
|
||||||
|
logger.LogInformation($"Queue {queueName} exists, deleting... {passive.MessageCount} messages in queue");
|
||||||
|
channelAccessor.Channel.QueueDelete(queueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
channelPool.Release(queueName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,5 +74,5 @@ public class ConsumeOptions
|
|||||||
|
|
||||||
public bool FailedRequeue { get; set; }
|
public bool FailedRequeue { get; set; }
|
||||||
|
|
||||||
public Action<IDeclaration>
|
public Action<IModel> Declaration { get; set; }
|
||||||
}
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
using InterfaceForward.Application.Contracts.Dtos.App;
|
||||||
|
using InterfaceForward.Application.Helpers;
|
||||||
|
using InterfaceForward.Application.HostServices;
|
||||||
|
using InterfaceForward.Domain.Shared.Enum;
|
||||||
|
using InterfaceForward.Repositories;
|
||||||
|
using InterfaceForward.Repositories.App.Entitys;
|
||||||
|
using InterfaceForward.Repositories.Interface.Entitys;
|
||||||
|
using InterfaceForward.Repositories.ServiceProvider.Entitys;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Application.Services.App;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用订阅
|
||||||
|
/// </summary>
|
||||||
|
[Route("AppSubscribe")]
|
||||||
|
[ApiExplorerSettings(GroupName = "应用服务")]
|
||||||
|
public class AppSubscribeService : ApplicationService
|
||||||
|
{
|
||||||
|
public const int DefaultFetchCount = 1;
|
||||||
|
public const bool DefaultFailedRequeue = false;
|
||||||
|
|
||||||
|
private readonly IBasicRepository<AppEntity> _appRepository;
|
||||||
|
private readonly IBasicRepository<AppSubscribeConfigEntity> _appSubscribeConfigRepository;
|
||||||
|
private readonly IBasicRepository<InterfaceEntity> _interfaceRepository;
|
||||||
|
private readonly IBasicRepository<ServiceProviderEntity> _serviceProviderRepository;
|
||||||
|
|
||||||
|
public AppSubscribeService(IBasicRepository<AppSubscribeConfigEntity> appSubscribeConfigRepository,
|
||||||
|
IBasicRepository<InterfaceEntity> interfaceRepository,
|
||||||
|
IBasicRepository<ServiceProviderEntity> serviceProviderRepository, IBasicRepository<AppEntity> appRepository)
|
||||||
|
{
|
||||||
|
_appSubscribeConfigRepository = appSubscribeConfigRepository;
|
||||||
|
_interfaceRepository = interfaceRepository;
|
||||||
|
_serviceProviderRepository = serviceProviderRepository;
|
||||||
|
_appRepository = appRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订阅列表
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("GetList")]
|
||||||
|
public async Task<List<AppSubscribeConfigEntity>> GetList(string? appKey)
|
||||||
|
{
|
||||||
|
return await _appSubscribeConfigRepository.GetListAsync(x =>
|
||||||
|
string.IsNullOrWhiteSpace(appKey) || x.AppKey == appKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建or更新
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">入参</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("Upsert")]
|
||||||
|
public async Task<string> Upsert(UpsertAppSubscribeConfigInput input)
|
||||||
|
{
|
||||||
|
if (input.FetchCount == 0)
|
||||||
|
{
|
||||||
|
input.FetchCount = DefaultFetchCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _appRepository.IsAnyAsync(x => x.AppKey == input.AppKey))
|
||||||
|
{
|
||||||
|
return "应用不存在";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _interfaceRepository.IsAnyAsync(x => x.IsUpStream == true && x.Code == input.SystemInterfaceCode))
|
||||||
|
{
|
||||||
|
return "系统接口不存在";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _serviceProviderRepository.IsAnyAsync(x => x.Code == input.ServiceProviderCode))
|
||||||
|
{
|
||||||
|
return "服务商不存在";
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = await _appSubscribeConfigRepository.GetFirstAsync(x =>
|
||||||
|
x.AppKey == input.AppKey && x.SystemInterfaceCode == input.SystemInterfaceCode &&
|
||||||
|
x.ServiceProviderCode == input.ServiceProviderCode);
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
{
|
||||||
|
if (config.FetchCount != input.FetchCount || config.FailedRequeue != input.FailedRequeue)
|
||||||
|
{
|
||||||
|
config.FetchCount = input.FetchCount;
|
||||||
|
config.FailedRequeue = input.FailedRequeue;
|
||||||
|
await _appSubscribeConfigRepository.UpdateAsync(config);
|
||||||
|
|
||||||
|
var @event = ObjectMapper.Map<UpsertAppSubscribeConfigInput, AppSubscribeEvent>(input);
|
||||||
|
@event.OptionType = OptionType.修改;
|
||||||
|
await RedisHelper.Client.PublishAsync(AppSubscribeEventHandler.AppSubscribeEventSubscribe,
|
||||||
|
@event.ToJson());
|
||||||
|
return "订阅已更新,关注飞书消息,等待节点状态同步";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "订阅已存在,且没有发生任何变化";
|
||||||
|
}
|
||||||
|
|
||||||
|
config = ObjectMapper.Map<UpsertAppSubscribeConfigInput, AppSubscribeConfigEntity>(input);
|
||||||
|
|
||||||
|
await _appSubscribeConfigRepository.InsertAsync(config);
|
||||||
|
|
||||||
|
var eventForAdd = ObjectMapper.Map<UpsertAppSubscribeConfigInput, AppSubscribeEvent>(input);
|
||||||
|
eventForAdd.OptionType = OptionType.新增;
|
||||||
|
await RedisHelper.Client.PublishAsync(AppSubscribeEventHandler.AppSubscribeEventSubscribe,
|
||||||
|
eventForAdd.ToJson());
|
||||||
|
return "新增订阅成功,关注飞书消息,等待节点状态同步";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">入参</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("Delete")]
|
||||||
|
public async Task<string> Delete(DeleteAppSubscribeConfigInput input)
|
||||||
|
{
|
||||||
|
var hasChange = await _appSubscribeConfigRepository.SoftDeleteAsync(x =>
|
||||||
|
x.AppKey == input.AppKey && x.SystemInterfaceCode == input.SystemInterfaceCode &&
|
||||||
|
x.ServiceProviderCode == input.ServiceProviderCode);
|
||||||
|
|
||||||
|
if (hasChange)
|
||||||
|
{
|
||||||
|
var chan = AppSubscribeEventHandler.AppSubscribeEventSubscribe;
|
||||||
|
var @event = ObjectMapper.Map<DeleteAppSubscribeConfigInput, AppSubscribeEvent>(input);
|
||||||
|
@event.OptionType = OptionType.删除;
|
||||||
|
await RedisHelper.Client.PublishAsync(chan, @event.ToJson());
|
||||||
|
return "成功删除应用订阅,关注飞书消息,等待节点状态同步";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "应用订阅不存在";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@ namespace InterfaceForward.Application.Services.App;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("App")]
|
[Route("App")]
|
||||||
[ApiExplorerSettings(GroupName = "应用服务")]
|
[ApiExplorerSettings(GroupName = "应用服务")]
|
||||||
public class AppsService : BaseService
|
public class AppsService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IAppRepository _appRepository;
|
private readonly IAppRepository _appRepository;
|
||||||
private readonly IAppScopeRepository _appScopeRepository;
|
private readonly IAppScopeRepository _appScopeRepository;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace InterfaceForward.Application.Services.App
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("Dictionary")]
|
[Route("Dictionary")]
|
||||||
[ApiExplorerSettings(GroupName = "应用服务")]
|
[ApiExplorerSettings(GroupName = "应用服务")]
|
||||||
public class DictionaryService : BaseService
|
public class DictionaryService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IDictionaryRepository _dictionaryRepository;
|
private readonly IDictionaryRepository _dictionaryRepository;
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace InterfaceForward.Application.Services.App
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("Log")]
|
[Route("Log")]
|
||||||
[ApiExplorerSettings(GroupName = "应用服务")]
|
[ApiExplorerSettings(GroupName = "应用服务")]
|
||||||
public class LogService : BaseService
|
public class LogService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly ILogRepository _logRepository;
|
private readonly ILogRepository _logRepository;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
using Fake.Application;
|
|
||||||
|
|
||||||
namespace InterfaceForward.Application.Services;
|
|
||||||
|
|
||||||
public abstract class BaseService : ApplicationService
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -13,7 +13,7 @@ namespace InterfaceForward.Application.Services.Interface;
|
|||||||
/// 接口返回配置
|
/// 接口返回配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "接口服务")]
|
[ApiExplorerSettings(GroupName = "接口服务")]
|
||||||
public class InterfaceReturnConfigService : BaseService
|
public class InterfaceReturnConfigService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IInterfaceReturnConfigRepository _interfaceReturnConfigRepository;
|
private readonly IInterfaceReturnConfigRepository _interfaceReturnConfigRepository;
|
||||||
private readonly IInterfaceRepository _interfaceRepository;
|
private readonly IInterfaceRepository _interfaceRepository;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace InterfaceForward.Application.Services.Interface;
|
|||||||
/// 服务商接口
|
/// 服务商接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "接口服务")]
|
[ApiExplorerSettings(GroupName = "接口服务")]
|
||||||
public class ServiceProviderInterfaceService : BaseService
|
public class ServiceProviderInterfaceService : ApplicationService
|
||||||
{
|
{
|
||||||
private ParameterService ParameterService => LazyServiceProvider.GetRequiredService<ParameterService>();
|
private ParameterService ParameterService => LazyServiceProvider.GetRequiredService<ParameterService>();
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace InterfaceForward.Application.Services.Interface;
|
|||||||
/// 系统接口
|
/// 系统接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "接口服务")]
|
[ApiExplorerSettings(GroupName = "接口服务")]
|
||||||
public class SystemInterfaceService : BaseService
|
public class SystemInterfaceService : ApplicationService
|
||||||
{
|
{
|
||||||
#region ctor
|
#region ctor
|
||||||
|
|
||||||
|
|||||||
@ -12,10 +12,10 @@ using InterfaceForward.Domain.Shared.Dtos;
|
|||||||
using InterfaceForward.Domain.Shared.Enum;
|
using InterfaceForward.Domain.Shared.Enum;
|
||||||
using InterfaceForward.Repositories;
|
using InterfaceForward.Repositories;
|
||||||
using InterfaceForward.Repositories.Log.Services;
|
using InterfaceForward.Repositories.Log.Services;
|
||||||
|
using InterfaceForward.Repositories.Log.ValueObjects;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using SJZY.InterfaceRelay.Repository.Log.ValueObjects;
|
|
||||||
|
|
||||||
namespace InterfaceForward.Application.Services;
|
namespace InterfaceForward.Application.Services;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -23,7 +23,7 @@ public class InterfaceMapPublishService(
|
|||||||
IInterfaceMapPublishRepository interfaceMapPublishRepository,
|
IInterfaceMapPublishRepository interfaceMapPublishRepository,
|
||||||
InterfaceForwardQuery interfaceForwardQuery,
|
InterfaceForwardQuery interfaceForwardQuery,
|
||||||
IInterfaceMapRepository interfaceMapRepository)
|
IInterfaceMapRepository interfaceMapRepository)
|
||||||
: ApplicationService
|
: Fake.Application.ApplicationService
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerSettings Settings = new()
|
private static readonly JsonSerializerSettings Settings = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.InterfaceMap;
|
|||||||
/// 接口映射服务
|
/// 接口映射服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "接口映射服务")]
|
[ApiExplorerSettings(GroupName = "接口映射服务")]
|
||||||
public partial class InterfaceMapService : ApplicationService
|
public partial class InterfaceMapService : Fake.Application.ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IBasicRepository<FixedParameterEntity> _fixedParameterRepository;
|
private readonly IBasicRepository<FixedParameterEntity> _fixedParameterRepository;
|
||||||
private readonly IBasicRepository<InterfaceMapDetailEntity> _interfaceMapDetailRepository;
|
private readonly IBasicRepository<InterfaceMapDetailEntity> _interfaceMapDetailRepository;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ namespace InterfaceForward.Application.Services.Parameter;
|
|||||||
/// 固定参数配置
|
/// 固定参数配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "参数服务")]
|
[ApiExplorerSettings(GroupName = "参数服务")]
|
||||||
public class FixedParameterService : BaseService
|
public class FixedParameterService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IFixedParameterRepository _fixedParameterRepository;
|
private readonly IFixedParameterRepository _fixedParameterRepository;
|
||||||
private readonly IServiceProviderRepository _serviceProviderRepository;
|
private readonly IServiceProviderRepository _serviceProviderRepository;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ namespace InterfaceForward.Application.Services.Parameter;
|
|||||||
/// 表单参数配置
|
/// 表单参数配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "参数服务")]
|
[ApiExplorerSettings(GroupName = "参数服务")]
|
||||||
public class FormParameterService : BaseService
|
public class FormParameterService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IBasicRepository<FormParameterEntity> _formParameterRepository;
|
private readonly IBasicRepository<FormParameterEntity> _formParameterRepository;
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace InterfaceForward.Application.Services.Parameter;
|
|||||||
/// 参数服务
|
/// 参数服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "参数服务")]
|
[ApiExplorerSettings(GroupName = "参数服务")]
|
||||||
public class ParameterService : BaseService
|
public class ParameterService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IInterfaceRepository _interfaceRepository;
|
private readonly IInterfaceRepository _interfaceRepository;
|
||||||
private readonly IParameterRepository _parameterRepository;
|
private readonly IParameterRepository _parameterRepository;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider;
|
|||||||
/// 服务商账户
|
/// 服务商账户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "服务商服务")]
|
[ApiExplorerSettings(GroupName = "服务商服务")]
|
||||||
public class ServiceProviderAccountService : BaseService
|
public class ServiceProviderAccountService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IServiceProviderAccountFieldRepository _serviceProviderAccountFieldRepository;
|
private readonly IServiceProviderAccountFieldRepository _serviceProviderAccountFieldRepository;
|
||||||
private readonly IServiceProviderAccountFieldValueRepository _serviceProviderAccountFieldValueRepository;
|
private readonly IServiceProviderAccountFieldValueRepository _serviceProviderAccountFieldValueRepository;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider;
|
|||||||
/// 服务商授权配置
|
/// 服务商授权配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "服务商服务")]
|
[ApiExplorerSettings(GroupName = "服务商服务")]
|
||||||
public class ServiceProviderAuthService : BaseService
|
public class ServiceProviderAuthService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IBasicRepository<InterfaceEntity> _interfaceRepository;
|
private readonly IBasicRepository<InterfaceEntity> _interfaceRepository;
|
||||||
private readonly IBasicRepository<ParameterEntity> _parameterRepository;
|
private readonly IBasicRepository<ParameterEntity> _parameterRepository;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider;
|
|||||||
/// 导入导出服务
|
/// 导入导出服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "服务商服务")]
|
[ApiExplorerSettings(GroupName = "服务商服务")]
|
||||||
public class ServiceProviderImportExportService : BaseService
|
public class ServiceProviderImportExportService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly ISugarDbContextProvider<InterfaceForwardDbContext> _sqlSugarClientProvider;
|
private readonly ISugarDbContextProvider<InterfaceForwardDbContext> _sqlSugarClientProvider;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider;
|
|||||||
/// 服务商服务
|
/// 服务商服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "服务商服务")]
|
[ApiExplorerSettings(GroupName = "服务商服务")]
|
||||||
public class ServiceProviderService : BaseService
|
public class ServiceProviderService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly IBasicRepository<InterfaceEntity> _interfaceRepository;
|
private readonly IBasicRepository<InterfaceEntity> _interfaceRepository;
|
||||||
private readonly IServiceProviderRepository _serviceProviderRepository;
|
private readonly IServiceProviderRepository _serviceProviderRepository;
|
||||||
|
|||||||
@ -1,11 +1,19 @@
|
|||||||
namespace InterfaceForward.Domain.Shared.Dtos;
|
namespace InterfaceForward.Domain.Shared.Dtos;
|
||||||
|
|
||||||
public class RequestLogDto(Guid requestId)
|
public class RequestLogDto
|
||||||
{
|
{
|
||||||
|
public const string Init = null;
|
||||||
|
|
||||||
|
public RequestLogDto(Guid requestId)
|
||||||
|
{
|
||||||
|
RequestId = requestId;
|
||||||
|
Response = Init;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 请求Id
|
/// 请求Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid RequestId { get; set; } = requestId;
|
public Guid RequestId { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 请求时间(务必设置)
|
/// 请求时间(务必设置)
|
||||||
@ -20,37 +28,37 @@ public class RequestLogDto(Guid requestId)
|
|||||||
///<summary>
|
///<summary>
|
||||||
/// 应用/服务商名称
|
/// 应用/服务商名称
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 发起请求IP
|
/// 发起请求IP
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? ClientIp { get; set; }
|
public string ClientIP { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 接口代码
|
/// 接口代码
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? InterfaceCode { get; set; }
|
public string InterfaceCode { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 请求接口名称
|
/// 请求接口名称
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? InterfaceName { get; set; }
|
public string InterfaceName { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 请求地址
|
/// 请求地址
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Address { get; set; }
|
public string Address { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 请求头
|
/// 请求头
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Headers { get; set; }
|
public string Headers { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 请求体
|
/// 请求体
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 响应耗时ms
|
/// 响应耗时ms
|
||||||
@ -60,12 +68,12 @@ public class RequestLogDto(Guid requestId)
|
|||||||
///<summary>
|
///<summary>
|
||||||
/// 响应结果
|
/// 响应结果
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Response { get; set; }
|
public string Response { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 响应结果映射后
|
/// 响应结果映射后
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? Response2 { get; set; }
|
public string Response2 { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 是否成功调用
|
/// 是否成功调用
|
||||||
@ -75,5 +83,5 @@ public class RequestLogDto(Guid requestId)
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异常
|
/// 异常
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Exception { get; set; }
|
public string Exception { get; set; }
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public static class RequestServiceProviderFailedCommon
|
public static class RequestServiceProviderFailedCommon
|
||||||
{
|
{
|
||||||
public const string RequestServiceProviderFailedSubscribeName = "SJZY.InterfaceRelay.RequestServiceProviderFailed";
|
public const string RequestServiceProviderFailedSubscribeName = "InterfaceForward.RequestServiceProviderFailed";
|
||||||
|
|
||||||
public static string RequestFailedCode = "4001";
|
public static string RequestFailedCode = "4001";
|
||||||
|
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace InterfaceForward.Domain.Shared.FeiShu;
|
|
||||||
|
|
||||||
public class FeiShuNoticer : IFeiShuNoticer
|
|
||||||
{
|
|
||||||
private readonly FeiShuNoticeOptions _options;
|
|
||||||
private readonly HttpClient _httpClient;
|
|
||||||
private readonly ILogger<FeiShuNoticer> _logger;
|
|
||||||
|
|
||||||
public FeiShuNoticer(IOptions<FeiShuNoticeOptions> options, HttpClient httpClient, ILogger<FeiShuNoticer> logger)
|
|
||||||
{
|
|
||||||
_options = options.Value;
|
|
||||||
_httpClient = httpClient;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task NoticeAsync(string content, string subTitle = "")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_options.Webhook.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
_logger.LogWarning("未配置飞书webhook");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var title = subTitle.IsNullOrWhiteSpace()
|
|
||||||
? _options.TitlePrefix
|
|
||||||
: _options.TitlePrefix + "_" + subTitle;
|
|
||||||
|
|
||||||
await HandleNoticeAsync(content, title);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// 这里失败不应该影响业务
|
|
||||||
_logger.LogWarning($"飞书通知失败,{e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async Task HandleNoticeAsync(string content, string title)
|
|
||||||
{
|
|
||||||
var message = new
|
|
||||||
{
|
|
||||||
msg_type = "post",
|
|
||||||
content = new
|
|
||||||
{
|
|
||||||
post = new
|
|
||||||
{
|
|
||||||
zh_cn = new
|
|
||||||
{
|
|
||||||
title,
|
|
||||||
content = new List<object>()
|
|
||||||
{
|
|
||||||
new List<object>()
|
|
||||||
{
|
|
||||||
new
|
|
||||||
{
|
|
||||||
tag = "text",
|
|
||||||
text = content + Environment.NewLine
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var httpContent = new StringContent(JsonSerializer.Serialize(message), Encoding.UTF8);
|
|
||||||
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
|
||||||
await _httpClient.PostAsync(_options.Webhook, httpContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
using Fake.DependencyInjection;
|
|
||||||
|
|
||||||
namespace InterfaceForward.Domain.Shared.FeiShu;
|
|
||||||
|
|
||||||
public interface IFeiShuNoticer: ITransientDependency
|
|
||||||
{
|
|
||||||
public Task NoticeAsync(string content, string subTitle = "");
|
|
||||||
}
|
|
||||||
@ -30,5 +30,5 @@ public static class GlobalConst
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ServiceProviderInterfaceQpsKeyPrefix = "InterfaceQPS";
|
public const string ServiceProviderInterfaceQpsKeyPrefix = "InterfaceQPS";
|
||||||
|
|
||||||
public const string InterfaceRelayExchange = "sjzy.interface.relay.direct";
|
public const string InterfaceRelayExchange = "interface.relay.direct";
|
||||||
}
|
}
|
||||||
98
src/InterfaceForward.Domain.Shared/Helpers/LogHelper.cs
Normal file
98
src/InterfaceForward.Domain.Shared/Helpers/LogHelper.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Fake.SyncEx;
|
||||||
|
using InterfaceForward.Domain.Shared.Options;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Domain.Shared.Helpers;
|
||||||
|
|
||||||
|
public static class LogHelper
|
||||||
|
{
|
||||||
|
private static FeiShuNoticeOptions _options = null!;
|
||||||
|
|
||||||
|
public static void Init(FeiShuNoticeOptions options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
public static void Info(string msg, bool isSend = false)
|
||||||
|
{
|
||||||
|
Log.Information(msg);
|
||||||
|
if (!isSend)
|
||||||
|
return;
|
||||||
|
SyncContext.Run(() => NoticeAsync(msg, isSend, "Info"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(string msg, bool isSend = false)
|
||||||
|
{
|
||||||
|
Log.Warning(msg);
|
||||||
|
if (!isSend)
|
||||||
|
return;
|
||||||
|
SyncContext.Run(() => NoticeAsync(msg, isSend, "Warn"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(string msg, bool isSend = true)
|
||||||
|
{
|
||||||
|
Log.Error(msg);
|
||||||
|
SyncContext.Run(() => NoticeAsync(msg, isSend, "Error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task NoticeAsync(string content, bool isSend, string subTitle = "")
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
// 调试模式下不发送通知
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
if (!isSend)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_options.Webhook.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
Log.Warning("未配置飞书webhook");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = subTitle.IsNullOrWhiteSpace()
|
||||||
|
? _options.TitlePrefix
|
||||||
|
: _options.TitlePrefix + "_" + subTitle;
|
||||||
|
|
||||||
|
await HandleNoticeAsync(content, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task HandleNoticeAsync(string content, string title)
|
||||||
|
{
|
||||||
|
var message = new
|
||||||
|
{
|
||||||
|
msg_type = "post",
|
||||||
|
content = new
|
||||||
|
{
|
||||||
|
post = new
|
||||||
|
{
|
||||||
|
zh_cn = new
|
||||||
|
{
|
||||||
|
title,
|
||||||
|
content = new List<object>()
|
||||||
|
{
|
||||||
|
new List<object>()
|
||||||
|
{
|
||||||
|
new
|
||||||
|
{
|
||||||
|
tag = "text",
|
||||||
|
text = content + Environment.NewLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using var httpClient = new HttpClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(_options.Timeout);
|
||||||
|
using var httpContent = new StringContent(JsonSerializer.Serialize(message), Encoding.UTF8);
|
||||||
|
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
await httpClient.PostAsync(_options.Webhook, httpContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.1" />
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
using Fake.Modularity;
|
using Fake.Modularity;
|
||||||
using InterfaceForward.Domain.Shared.FeiShu;
|
using InterfaceForward.Domain.Shared.Helpers;
|
||||||
|
using InterfaceForward.Domain.Shared.Options;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace InterfaceForward.Domain.Shared
|
namespace InterfaceForward.Domain.Shared
|
||||||
@ -8,8 +10,8 @@ namespace InterfaceForward.Domain.Shared
|
|||||||
{
|
{
|
||||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
{
|
{
|
||||||
var config = context.Services.GetConfiguration();
|
var configuration = context.Services.GetConfiguration();
|
||||||
context.Services.Configure<FeiShuNoticeOptions>(config.GetSection("FeiShuNotice"));
|
LogHelper.Init(configuration.GetSection("FeiShuNotice").Get<FeiShuNoticeOptions>()!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
namespace InterfaceForward.Domain.Shared.FeiShu;
|
namespace InterfaceForward.Domain.Shared.Options;
|
||||||
|
|
||||||
public class FeiShuNoticeOptions
|
public class FeiShuNoticeOptions
|
||||||
{
|
{
|
||||||
@ -11,4 +11,9 @@ public class FeiShuNoticeOptions
|
|||||||
/// 消息标题前缀
|
/// 消息标题前缀
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TitlePrefix { get; set; }
|
public string TitlePrefix { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 超时时间 秒
|
||||||
|
/// </summary>
|
||||||
|
public int Timeout { get; set; } = 20;
|
||||||
}
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
namespace InterfaceForward.Domain.Shared.Options
|
|
||||||
{
|
|
||||||
public class NoticeOptions
|
|
||||||
{
|
|
||||||
public string Webhook { get; set; }
|
|
||||||
|
|
||||||
public string Title { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
namespace InterfaceForward.Repositories.App.Entitys;
|
||||||
|
|
||||||
|
///<summary>
|
||||||
|
/// 应用mq订阅配置表
|
||||||
|
///</summary>
|
||||||
|
[SugarTable("t_app_subscribe_config")]
|
||||||
|
public class AppSubscribeConfigEntity : FullAuditedAggregateRoot<int>
|
||||||
|
{
|
||||||
|
///<summary>
|
||||||
|
/// 自增主键
|
||||||
|
///</summary>
|
||||||
|
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用key
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "AppKey")]
|
||||||
|
public string AppKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统接口code
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "SystemInterfaceCode")]
|
||||||
|
public string SystemInterfaceCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务商code
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "ServiceProviderCode")]
|
||||||
|
public string ServiceProviderCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// mq预取数量(服务并发度)
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "FetchCount")]
|
||||||
|
public ushort FetchCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 失败重回队列
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "FailedRequeue")]
|
||||||
|
public bool FailedRequeue { get; set; }
|
||||||
|
}
|
||||||
@ -7,7 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fake.SqlSugarCore" Version="8.0.0" />
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
|
<PackageReference Include="Fake.SqlSugarCore" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="NEST" Version="7.17.5" />
|
<PackageReference Include="NEST" Version="7.17.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public class LogIndex : IdBaseIndex
|
|||||||
///<summary>
|
///<summary>
|
||||||
/// 发起请求IP
|
/// 发起请求IP
|
||||||
///</summary>
|
///</summary>
|
||||||
public string? ClientIp { get; set; }
|
public string ClientIP { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 接口代码
|
/// 接口代码
|
||||||
@ -66,6 +66,11 @@ public class LogIndex : IdBaseIndex
|
|||||||
///</summary>
|
///</summary>
|
||||||
public string Response { get; set; }
|
public string Response { get; set; }
|
||||||
|
|
||||||
|
///<summary>
|
||||||
|
/// 响应结果映射后
|
||||||
|
///</summary>
|
||||||
|
public string Response2 { get; set; }
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
/// 是否成功调用
|
/// 是否成功调用
|
||||||
///</summary>
|
///</summary>
|
||||||
|
|||||||
@ -1,28 +1,30 @@
|
|||||||
using InterfaceForward.Domain.Shared.Dtos;
|
using InterfaceForward.Domain.Shared.Dtos;
|
||||||
using Nest;
|
|
||||||
using InterfaceForward.Repositories.Log.Entitys;
|
using InterfaceForward.Repositories.Log.Entitys;
|
||||||
using InterfaceForward.Repositories.Log.ValueObjects;
|
using InterfaceForward.Repositories.Log.ValueObjects;
|
||||||
using SJZY.InterfaceRelay.Repository.Log.ValueObjects;
|
using Nest;
|
||||||
|
|
||||||
namespace InterfaceForward.Repositories.Log.Services;
|
namespace InterfaceForward.Repositories.Log.Services
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志仓储
|
|
||||||
/// </summary>
|
|
||||||
public interface ILogRepository
|
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 日志仓储
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogRepository
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用id
|
/// 应用id
|
||||||
|
/// important:全局贯彻
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int AppId { get; set; }
|
int AppId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用日志
|
/// 应用日志
|
||||||
|
/// important:全局贯彻
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RequestLogDto AppRequestLog { get; set; }
|
public RequestLogDto AppRequestLog { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最后一条服务商日志
|
/// 最后一条服务商日志
|
||||||
|
/// important:全局贯彻
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RequestLogDto ServiceProviderRequestLog { get; set; }
|
public RequestLogDto ServiceProviderRequestLog { get; set; }
|
||||||
|
|
||||||
@ -31,7 +33,13 @@ public interface ILogRepository
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="exception">异常</param>
|
/// <param name="exception">异常</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task WriteAppLogAsync(Exception? exception = null);
|
Task WriteAppLog(Exception? exception = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发飞书
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="contextException"></param>
|
||||||
|
void SendFeiShu(Exception contextException);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加日志
|
/// 添加日志
|
||||||
@ -67,4 +75,5 @@ public interface ILogRepository
|
|||||||
/// <param name="requestId"></param>
|
/// <param name="requestId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<RequestLogSummary>> GetRequestLogsAsync(Guid requestId);
|
Task<List<RequestLogSummary>> GetRequestLogsAsync(Guid requestId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
using Nest;
|
using InterfaceForward.Domain.Shared.Dtos;
|
||||||
using InterfaceForward.Domain.Shared.Dtos;
|
|
||||||
using InterfaceForward.Domain.Shared.Enum;
|
using InterfaceForward.Domain.Shared.Enum;
|
||||||
using InterfaceForward.Domain.Shared.FeiShu;
|
using InterfaceForward.Domain.Shared.Helpers;
|
||||||
using InterfaceForward.Repositories.Log.Entitys;
|
using InterfaceForward.Repositories.Log.Entitys;
|
||||||
using InterfaceForward.Repositories.Log.ES;
|
using InterfaceForward.Repositories.Log.ES;
|
||||||
using InterfaceForward.Repositories.Log.ValueObjects;
|
using InterfaceForward.Repositories.Log.ValueObjects;
|
||||||
using SJZY.InterfaceRelay.Repository.Log.ValueObjects;
|
using Nest;
|
||||||
|
using LogHelper = InterfaceForward.Domain.Shared.Helpers.LogHelper;
|
||||||
|
|
||||||
namespace InterfaceForward.Repositories.Log.Services;
|
namespace InterfaceForward.Repositories.Log.Services;
|
||||||
|
|
||||||
@ -14,16 +14,11 @@ namespace InterfaceForward.Repositories.Log.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogRepository, IScopedDependency
|
public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogRepository, IScopedDependency
|
||||||
{
|
{
|
||||||
private readonly IFeiShuNoticer _feiShuNoticer;
|
public LogRepository(ConnectionFactory connection) : base(connection)
|
||||||
|
|
||||||
public LogRepository(ConnectionFactory connection, IFeiShuNoticer feiShuNoticer) : base(connection)
|
|
||||||
{
|
{
|
||||||
_feiShuNoticer = feiShuNoticer;
|
|
||||||
var guid = Guid.NewGuid();
|
var guid = Guid.NewGuid();
|
||||||
AppRequestLog = new RequestLogDto(guid)
|
AppRequestLog = new RequestLogDto(guid);
|
||||||
{
|
AppRequestLog.IsSuccess = true; // 只有接口通发生未处理异常才算应用失败
|
||||||
IsSuccess = true // 只有接口通发生未处理异常才算应用失败
|
|
||||||
};
|
|
||||||
ServiceProviderRequestLog = new RequestLogDto(guid);
|
ServiceProviderRequestLog = new RequestLogDto(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +26,7 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
public RequestLogDto AppRequestLog { get; set; }
|
public RequestLogDto AppRequestLog { get; set; }
|
||||||
public RequestLogDto ServiceProviderRequestLog { get; set; }
|
public RequestLogDto ServiceProviderRequestLog { get; set; }
|
||||||
|
|
||||||
public async Task WriteAppLogAsync(Exception? exception = null)
|
public async Task WriteAppLog(Exception? exception = null)
|
||||||
{
|
{
|
||||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||||
if (exception != null)
|
if (exception != null)
|
||||||
@ -45,6 +40,22 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
await AddLogAsync(AppRequestLog);
|
await AddLogAsync(AppRequestLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendFeiShu(Exception contextException)
|
||||||
|
{
|
||||||
|
LogHelper.Error($"""
|
||||||
|
日志请求id:{ServiceProviderRequestLog.RequestId}
|
||||||
|
服务商--接口:{ServiceProviderRequestLog.Name}--{ServiceProviderRequestLog.InterfaceName}
|
||||||
|
异常原因:{Truncate(contextException.ToString())}
|
||||||
|
请求地址:{ServiceProviderRequestLog.Address}
|
||||||
|
原始报文:
|
||||||
|
{Truncate(AppRequestLog.Content)}
|
||||||
|
请求报文:
|
||||||
|
{Truncate(ServiceProviderRequestLog.Content)}
|
||||||
|
响应报文:
|
||||||
|
{Truncate(ServiceProviderRequestLog.Response)}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task AddLogAsync(RequestLogDto requestLog)
|
public async Task AddLogAsync(RequestLogDto requestLog)
|
||||||
{
|
{
|
||||||
@ -56,7 +67,7 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
RequestTime = requestLog.RequestTime == default ? DateTime.Now : requestLog.RequestTime,
|
RequestTime = requestLog.RequestTime == default ? DateTime.Now : requestLog.RequestTime,
|
||||||
IsApp = requestLog.IsApp,
|
IsApp = requestLog.IsApp,
|
||||||
Name = requestLog.Name,
|
Name = requestLog.Name,
|
||||||
ClientIp = requestLog.ClientIp,
|
ClientIP = requestLog.ClientIP,
|
||||||
InterfaceCode = requestLog.InterfaceCode,
|
InterfaceCode = requestLog.InterfaceCode,
|
||||||
InterfaceName = requestLog.InterfaceName,
|
InterfaceName = requestLog.InterfaceName,
|
||||||
Address = requestLog.Address,
|
Address = requestLog.Address,
|
||||||
@ -64,31 +75,30 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
Content = requestLog.Content,
|
Content = requestLog.Content,
|
||||||
Cost = requestLog.Cost,
|
Cost = requestLog.Cost,
|
||||||
Response = requestLog.Response,
|
Response = requestLog.Response,
|
||||||
|
Response2 = requestLog.Response2,
|
||||||
IsSuccess = requestLog.IsSuccess,
|
IsSuccess = requestLog.IsSuccess,
|
||||||
Exception = requestLog.Exception
|
Exception = requestLog.Exception
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexResponse response = await Context.IndexAsync(idx,
|
try
|
||||||
request => request.Index($"sjzy_interface_forward-{DateTime.Now:yyyy.MM.dd}"));
|
|
||||||
if (!response.IsValid)
|
|
||||||
{
|
{
|
||||||
await _feiShuNoticer.NoticeAsync("数据添加失败,原因:" + response.DebugInformation);
|
//await Context.IndexDocumentAsync(idx);
|
||||||
|
IndexResponse response = await Context.IndexAsync(idx,
|
||||||
|
request => request.Index($"interface_forward-{DateTime.Now:yyyy.MM.dd}"));
|
||||||
|
if (!response.IsValid) LogHelper.Error("数据添加失败,原因:" + response.DebugInformation);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.Error($"日志插入ES失败:{ex.Message}。{idx.ToJson()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(List<LogIndex> list, long total)> GetListAsync(LogGetListInputValueObject input)
|
public async Task<(List<LogIndex> list, long total)> GetListAsync(LogGetListInputValueObject input)
|
||||||
{
|
{
|
||||||
var data = await Context.SearchAsync<LogIndex>(x => x
|
Func<QueryContainerDescriptor<LogIndex>, QueryContainer> query = input.RequestId.IsNullOrWhiteSpace()
|
||||||
.Source(s => s.Includes(i => i.Fields(
|
? q =>
|
||||||
f => f.Id, f => f.RequestId, f => f.RequestTime, f => f.IsApp,
|
|
||||||
f => f.Name, f => f.ClientIp, f => f.InterfaceName, f => f.InterfaceCode, f => f.Address,
|
|
||||||
f => f.Cost, f => f.IsSuccess)))
|
|
||||||
.Query(q =>
|
|
||||||
(input.Type != LogListInputTypeEnum.应用 ? null : q.Term(p => p.IsApp, true))
|
(input.Type != LogListInputTypeEnum.应用 ? null : q.Term(p => p.IsApp, true))
|
||||||
&& (input.Type != LogListInputTypeEnum.服务商 ? null : q.Term(p => p.IsApp, false))
|
&& (input.Type != LogListInputTypeEnum.服务商 ? null : q.Term(p => p.IsApp, false))
|
||||||
&& (input.RequestId.IsNullOrWhiteSpace()
|
|
||||||
? null
|
|
||||||
: q.Wildcard(w => w.RequestId.Suffix("keyword"), "*" + input.RequestId + "*"))
|
|
||||||
&& (input.InterfaceName.IsNullOrEmpty()
|
&& (input.InterfaceName.IsNullOrEmpty()
|
||||||
? null
|
? null
|
||||||
: q.Wildcard(w => w.InterfaceName.Suffix("keyword"), "*" + input.InterfaceName + "*"))
|
: q.Wildcard(w => w.InterfaceName.Suffix("keyword"), "*" + input.InterfaceName + "*"))
|
||||||
@ -124,7 +134,14 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
.Field(f => f.Cost)
|
.Field(f => f.Cost)
|
||||||
.LessThanOrEquals(input.CostEnd))
|
.LessThanOrEquals(input.CostEnd))
|
||||||
)
|
)
|
||||||
)
|
: q => q.Wildcard(w => w.RequestId.Suffix("keyword"), "*" + input.RequestId + "*");
|
||||||
|
|
||||||
|
var data = await Context.SearchAsync<LogIndex>(x => x
|
||||||
|
.Source(s => s.Includes(i => i.Fields(
|
||||||
|
f => f.Id, f => f.RequestId, f => f.RequestTime, f => f.IsApp,
|
||||||
|
f => f.Name, f => f.ClientIP, f => f.InterfaceName, f => f.InterfaceCode, f => f.Address,
|
||||||
|
f => f.Cost, f => f.IsSuccess)))
|
||||||
|
.Query(query)
|
||||||
.Sort(s => s.Field(f => f.RequestTime, SortOrder.Descending))
|
.Sort(s => s.Field(f => f.RequestTime, SortOrder.Descending))
|
||||||
.From((input.PageIndex - 1) * input.PageSize)
|
.From((input.PageIndex - 1) * input.PageSize)
|
||||||
.Size(input.PageSize)
|
.Size(input.PageSize)
|
||||||
@ -153,10 +170,9 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
// 按请求时间搜索
|
// 按请求时间搜索
|
||||||
&& q.DateRange(r => r
|
&& q.DateRange(r => r
|
||||||
.Field(f => f.RequestTime)
|
.Field(f => f.RequestTime)
|
||||||
.GreaterThanOrEquals(input.StartTime.ToString("yyyy-MM-dd")))
|
.GreaterThanOrEquals(input.StartTime.ToString("yyyy-MM-dd"))
|
||||||
&& q.DateRange(r => r
|
.LessThanOrEquals(input.EndTime.ToString("yyyy-MM-dd"))
|
||||||
.Field(f => f.RequestTime)
|
.TimeZone("+08:00"))
|
||||||
.LessThanOrEquals(input.EndTime.ToString("yyyy-MM-dd")))
|
|
||||||
)
|
)
|
||||||
// 分组 类似SQL的Group By
|
// 分组 类似SQL的Group By
|
||||||
.Aggregations(a => a
|
.Aggregations(a => a
|
||||||
@ -219,9 +235,9 @@ public class LogRepository : ElasticSearchContextAbstract<LogIndex>, ILogReposit
|
|||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string Truncate(string str, int maxLen = 500)
|
private static string? Truncate(string? str, int maxLen = 500)
|
||||||
{
|
{
|
||||||
if (str.IsNullOrWhiteSpace()) return str;
|
if (str.IsNullOrWhiteSpace()) return str;
|
||||||
return str.Length <= maxLen ? str : str.Left(maxLen) + "...";
|
return str!.Length <= maxLen ? str : str.Left(maxLen) + "...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
namespace SJZY.InterfaceRelay.Repository.Log.ValueObjects;
|
namespace InterfaceForward.Repositories.Log.ValueObjects;
|
||||||
|
|
||||||
public class RequestLogSummary
|
public class RequestLogSummary
|
||||||
{
|
{
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
||||||
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.1.23557.2"/>
|
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.1.23557.2"/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user