diff --git a/src/InterfaceForward.Api/InterfaceForward.Api.csproj b/src/InterfaceForward.Api/InterfaceForward.Api.csproj index 80f0b6e..3e0b2ad 100644 --- a/src/InterfaceForward.Api/InterfaceForward.Api.csproj +++ b/src/InterfaceForward.Api/InterfaceForward.Api.csproj @@ -16,9 +16,10 @@ - + + - + diff --git a/src/InterfaceForward.Api/appsettings.json b/src/InterfaceForward.Api/appsettings.json index f1a689d..2df4f10 100644 --- a/src/InterfaceForward.Api/appsettings.json +++ b/src/InterfaceForward.Api/appsettings.json @@ -32,7 +32,8 @@ }, "FeiShuNotice": { "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": { "Default": { diff --git a/src/InterfaceForward.AppHost/InterfaceForward.AppHost.csproj b/src/InterfaceForward.AppHost/InterfaceForward.AppHost.csproj index fc02db9..cb8a3c7 100644 --- a/src/InterfaceForward.AppHost/InterfaceForward.AppHost.csproj +++ b/src/InterfaceForward.AppHost/InterfaceForward.AppHost.csproj @@ -10,6 +10,8 @@ + + diff --git a/src/InterfaceForward.Application.Contracts/Dtos/App/DeleteAppSubscribeConfigInput.cs b/src/InterfaceForward.Application.Contracts/Dtos/App/DeleteAppSubscribeConfigInput.cs new file mode 100644 index 0000000..bc690b0 --- /dev/null +++ b/src/InterfaceForward.Application.Contracts/Dtos/App/DeleteAppSubscribeConfigInput.cs @@ -0,0 +1,24 @@ +namespace InterfaceForward.Application.Contracts.Dtos.App; + +public class DeleteAppSubscribeConfigInput +{ + /// + /// 应用key + /// + public string AppKey { get; set; } + + /// + /// 系统接口code + /// + public string SystemInterfaceCode { get; set; } + + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } + + /// + /// 【慎重!】删除队列(删除专用,一般false,即接口通只解除绑定,不删除队列) + /// + public bool IsDeleteQueue { get; set; } +} \ No newline at end of file diff --git a/src/InterfaceForward.Application.Contracts/Dtos/App/UpsertAppSubscribeConfigInput.cs b/src/InterfaceForward.Application.Contracts/Dtos/App/UpsertAppSubscribeConfigInput.cs new file mode 100644 index 0000000..e266917 --- /dev/null +++ b/src/InterfaceForward.Application.Contracts/Dtos/App/UpsertAppSubscribeConfigInput.cs @@ -0,0 +1,29 @@ +namespace InterfaceForward.Application.Contracts.Dtos.App; + +public class UpsertAppSubscribeConfigInput +{ + /// + /// 应用key + /// + public string AppKey { get; set; } + + /// + /// 系统接口code + /// + public string SystemInterfaceCode { get; set; } + + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } + + /// + /// 【慎重!】mq预取数量(服务并发度,给0就是默认1) + /// + public ushort FetchCount { get; set; } + + /// + /// 【慎重!】失败重回队列(一般false,即接口通不做重试,否则业务错误可能死循环) + /// + public bool FailedRequeue { get; set; } +} \ No newline at end of file diff --git a/src/InterfaceForward.Application.Contracts/ForwardCore/IInterfaceForwardService.cs b/src/InterfaceForward.Application.Contracts/ForwardCore/IInterfaceForwardService.cs index b5f1181..b2c2c66 100644 --- a/src/InterfaceForward.Application.Contracts/ForwardCore/IInterfaceForwardService.cs +++ b/src/InterfaceForward.Application.Contracts/ForwardCore/IInterfaceForwardService.cs @@ -13,14 +13,12 @@ public interface IInterfaceForwardService /// /// 系统接口code /// 服务商code - /// 主体id /// body /// 额外信息,原样返回 /// 是否返回原报文 /// 失败推送订阅名,不填就不推 /// Task ForwardWithSubscribeAsync(string upStreamCode, string serviceProviderCode, - int mainBodyId, object data, string? attach = null, bool isReturnMessage = false, string? failedSubscribeName = null); /// @@ -28,7 +26,6 @@ public interface IInterfaceForwardService /// /// 系统接口code /// 服务商code - /// 主体id /// 请求id /// body /// 额外信息,原样返回 @@ -36,6 +33,6 @@ public interface IInterfaceForwardService /// 失败推送订阅名,不填就不推 /// Task 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); } \ No newline at end of file diff --git a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceForwardOptions.cs b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceForwardOptions.cs index ffdc86e..9ce4d8c 100644 --- a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceForwardOptions.cs +++ b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceForwardOptions.cs @@ -1,4 +1,4 @@ -namespace SJZY.InterfaceRelay.Application.Contracts; +namespace InterfaceForward.Application.Contracts.ForwardCore; public class InterfaceForwardOptions { diff --git a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayForwardReplayEvent.cs b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayForwardReplayEvent.cs index 4ad88fa..74669aa 100644 --- a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayForwardReplayEvent.cs +++ b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayForwardReplayEvent.cs @@ -1,4 +1,4 @@ -namespace SJZY.InterfaceRelay.Application.Contracts; +namespace InterfaceForward.Application.Contracts.ForwardCore; public class InterfaceRelayForwardReplayEvent { diff --git a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayUnifyResultDto.cs b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayUnifyResultDto.cs index f548b5e..583dcab 100644 --- a/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayUnifyResultDto.cs +++ b/src/InterfaceForward.Application.Contracts/ForwardCore/InterfaceRelayUnifyResultDto.cs @@ -3,16 +3,15 @@ [Serializable] public class InterfaceRelayUnifyResultDto { + public string Code { get; set; } + + public string Msg { get; set; } + /// /// 请求Id /// public Guid RequestId { get; set; } - /// - /// 消息 - /// - public string? Message { get; set; } - /// /// 原报文 /// diff --git a/src/InterfaceForward.Application.Contracts/ForwardCore/RequestServiceProviderFailedEvent.cs b/src/InterfaceForward.Application.Contracts/ForwardCore/RequestServiceProviderFailedEvent.cs index b0c0c3d..2bf0234 100644 --- a/src/InterfaceForward.Application.Contracts/ForwardCore/RequestServiceProviderFailedEvent.cs +++ b/src/InterfaceForward.Application.Contracts/ForwardCore/RequestServiceProviderFailedEvent.cs @@ -1,4 +1,4 @@ -namespace SJZY.InterfaceRelay.Application.Contracts; +namespace InterfaceForward.Application.Contracts; public class RequestServiceProviderFailedEvent { diff --git a/src/InterfaceForward.Application.Contracts/InterfaceForward.Application.Contracts.csproj b/src/InterfaceForward.Application.Contracts/InterfaceForward.Application.Contracts.csproj index 4765b40..b134939 100644 --- a/src/InterfaceForward.Application.Contracts/InterfaceForward.Application.Contracts.csproj +++ b/src/InterfaceForward.Application.Contracts/InterfaceForward.Application.Contracts.csproj @@ -9,4 +9,8 @@ + + + + diff --git a/src/InterfaceForward.Application/Filters/ForwardAuthorizeFilter.cs b/src/InterfaceForward.Application/Filters/ForwardAuthorizeFilter.cs index 440705b..027f127 100644 --- a/src/InterfaceForward.Application/Filters/ForwardAuthorizeFilter.cs +++ b/src/InterfaceForward.Application/Filters/ForwardAuthorizeFilter.cs @@ -2,6 +2,7 @@ using Fake.Application; using Fake.AspNetCore.Http; using InterfaceForward.Repositories; +using InterfaceForward.Repositories.Interface.Entitys; using InterfaceForward.Repositories.Log.Services; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; @@ -13,7 +14,8 @@ namespace InterfaceForward.Application.Filters; public class ForwardAuthorizeFilter( InterfaceForwardQuery interfaceForwardQuery, ILogRepository logRepository, - IHttpClientInfoProvider httpClientInfoProvider) + IHttpClientInfoProvider httpClientInfoProvider, + IBasicRepository interfaceRepository) : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) @@ -27,7 +29,7 @@ public class ForwardAuthorizeFilter( log.IsApp = true; - log.ClientIp = httpClientInfoProvider.ClientIpAddress; + log.ClientIP = httpClientInfoProvider.ClientIpAddress; log.Address = httpContext.Request.GetDisplayUrl(); // body @@ -41,7 +43,6 @@ public class ForwardAuthorizeFilter( var headers = httpContext.Request.Headers; log.Headers = JsonConvert.SerializeObject(headers); - // _segContext.Context.Span.AddLog(LogEvent.Message("开始应用授权")); string? appKey = headers["appKey"], appSecret = headers["appSecret"]; if (appKey.IsNullOrWhiteSpace() || appSecret.IsNullOrWhiteSpace()) { @@ -56,6 +57,13 @@ public class ForwardAuthorizeFilter( throw new BusinessException(message: "应用已被禁用,请检查应用状态"); 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(); @@ -72,7 +80,7 @@ public class ForwardAuthorizeFilter( log.Response = actionContext.Result?.ToString()?? string.Empty; } - _ = logRepository.WriteAppLogAsync(); + _ = logRepository.WriteAppLog(); } } } \ No newline at end of file diff --git a/src/InterfaceForward.Application/Filters/ForwardExceptionFilter.cs b/src/InterfaceForward.Application/Filters/ForwardExceptionFilter.cs new file mode 100644 index 0000000..5e3adcf --- /dev/null +++ b/src/InterfaceForward.Application/Filters/ForwardExceptionFilter.cs @@ -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 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(); + } +} \ No newline at end of file diff --git a/src/InterfaceForward.Application/Filters/ForwardExceptionSubscriber.cs b/src/InterfaceForward.Application/Filters/ForwardExceptionSubscriber.cs deleted file mode 100644 index ed1093a..0000000 --- a/src/InterfaceForward.Application/Filters/ForwardExceptionSubscriber.cs +++ /dev/null @@ -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().HttpContext; - var logRepository = context.ServiceProvider.GetRequiredService(); - var feiShuNoticer = context.ServiceProvider.GetRequiredService(); - -// 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; - } -} \ No newline at end of file diff --git a/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs b/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs index ef4afb2..59cd8ae 100644 --- a/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs +++ b/src/InterfaceForward.Application/ForwardCore/DefaultForwardFlow.cs @@ -249,7 +249,7 @@ public class DefaultForwardFlow : IForwardFlow public virtual void BeforeRequest(ForwardCoreContext context) { var log = context.ServiceProviderRequestLog; - log.ClientIp = NetUtil.GetLanIp(); + log.ClientIP = NetUtil.GetLanIp(); log.Content = context.TargetInterfaceInput; context.ServiceProviderRequestLog.RequestTime = DateTime.Now; diff --git a/src/InterfaceForward.Application/HostServices/AppSubscribeEventHandler.cs b/src/InterfaceForward.Application/HostServices/AppSubscribeEventHandler.cs index f3934cb..88f32ee 100644 --- a/src/InterfaceForward.Application/HostServices/AppSubscribeEventHandler.cs +++ b/src/InterfaceForward.Application/HostServices/AppSubscribeEventHandler.cs @@ -3,20 +3,13 @@ using Fake.DependencyInjection; using InterfaceForward.Application.Rabbit; using InterfaceForward.Domain.Shared; using InterfaceForward.Domain.Shared.Enum; -using Microsoft.IdentityModel.Logging; using RabbitMQ.Client; namespace InterfaceForward.Application.HostServices; -public class AppSubscribeEventHandler : ITransientDependency +public class AppSubscribeEventHandler(RabbitClient rabbitClient) : ITransientDependency { - public const string AppSubscribeEventSubscribe = "sjzy.interface.relay.app.subscribe"; - private readonly RabbitClient _rabbitClient; - - public AppSubscribeEventHandler(RabbitClient rabbitClient) - { - _rabbitClient = rabbitClient; - } + public const string AppSubscribeEventSubscribe = "interface.relay.app.subscribe"; public Task Handle(AppSubscribeEvent @event) { @@ -26,15 +19,15 @@ public class AppSubscribeEventHandler : ITransientDependency break; case OptionType.新增: var res = DoAdd(@event); - LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res}", true); + LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res}"); break; case OptionType.修改: var res1 = DoUpdate(@event); - LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res1}", true); + LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res1}"); break; case OptionType.删除: var res2 = DoDelete(@event); - LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res2}", true); + LogHelper.Info($"{Dns.GetHostName()}\n{@event.ToJson()}\n{res2}"); break; default: throw new ArgumentOutOfRangeException(); @@ -47,9 +40,9 @@ public class AppSubscribeEventHandler : ITransientDependency { var queueName = $"{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, FetchCount = @event.FetchCount, // 并发控制 @@ -69,7 +62,7 @@ public class AppSubscribeEventHandler : ITransientDependency { var queueName = $"{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查询所有订阅"; } @@ -77,7 +70,7 @@ public class AppSubscribeEventHandler : ITransientDependency { var queueName = $"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{@event.AppKey}.{@event.SystemInterfaceCode}.{@event.ServiceProviderCode}"; - _rabbitClient.Subscribe(new ConsumeOptions + rabbitClient.Subscribe(new ConsumeOptions { Queue = queueName, FetchCount = @event.FetchCount, // 并发控制 diff --git a/src/InterfaceForward.Application/HostServices/AppSubscribeHostService.cs b/src/InterfaceForward.Application/HostServices/AppSubscribeHostService.cs index 6f71358..ed79018 100644 --- a/src/InterfaceForward.Application/HostServices/AppSubscribeHostService.cs +++ b/src/InterfaceForward.Application/HostServices/AppSubscribeHostService.cs @@ -1,10 +1,10 @@ -using Fake.Helpers; +using Fake.SyncEx; using InterfaceForward.Application.Helpers; using InterfaceForward.Application.Rabbit; using InterfaceForward.Domain.Shared; using InterfaceForward.Repositories; +using InterfaceForward.Repositories.App.Entitys; using Microsoft.Extensions.Hosting; -using Microsoft.IdentityModel.Logging; using Newtonsoft.Json; using RabbitMQ.Client; @@ -13,6 +13,7 @@ namespace InterfaceForward.Application.HostServices; public class AppSubscribeHostService : IHostedService { private readonly AppSubscribeEventHandler _appSubscribeEventHandler; + private readonly IBasicRepository _appSubscribeConfigRepository; private readonly RabbitClient _rabbitClient; public AppSubscribeHostService(IBasicRepository appSubscribeConfigRepository, @@ -63,7 +64,7 @@ public class AppSubscribeHostService : IHostedService if (chan == AppSubscribeEventHandler.AppSubscribeEventSubscribe && msg is string str) { var @event = JsonConvert.DeserializeObject(str); - AsyncHelper.RunSync(() => _appSubscribeEventHandler.Handle(@event)); + SyncContext.Run(() => _appSubscribeEventHandler.Handle(@event!)); } } } \ No newline at end of file diff --git a/src/InterfaceForward.Application/InterfaceForward.Application.csproj b/src/InterfaceForward.Application/InterfaceForward.Application.csproj index 3b0cd07..efd110c 100644 --- a/src/InterfaceForward.Application/InterfaceForward.Application.csproj +++ b/src/InterfaceForward.Application/InterfaceForward.Application.csproj @@ -17,9 +17,10 @@ - - - + + + + diff --git a/src/InterfaceForward.Application/Rabbit/BatchForwardEvent.cs b/src/InterfaceForward.Application/Rabbit/BatchForwardEvent.cs index 3516c0a..e676102 100644 --- a/src/InterfaceForward.Application/Rabbit/BatchForwardEvent.cs +++ b/src/InterfaceForward.Application/Rabbit/BatchForwardEvent.cs @@ -6,9 +6,9 @@ public class BatchForwardEvent 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; } @@ -16,5 +16,5 @@ public class BatchForwardEvent public bool IsReturnMessage { get; set; } - public string Data { get; set; } + public string Data { get; set; } = null!; } \ No newline at end of file diff --git a/src/InterfaceForward.Application/Rabbit/BatchForwardEventHandler.cs b/src/InterfaceForward.Application/Rabbit/BatchForwardEventHandler.cs index fed2d28..18feae4 100644 --- a/src/InterfaceForward.Application/Rabbit/BatchForwardEventHandler.cs +++ b/src/InterfaceForward.Application/Rabbit/BatchForwardEventHandler.cs @@ -3,37 +3,35 @@ using Fake.DependencyInjection; using InterfaceForward.Application.Contracts.ForwardCore; using InterfaceForward.Application.Services; using InterfaceForward.Domain.Shared; -using InterfaceForward.Domain.Shared.FeiShu; using InterfaceForward.Repositories.Log.Services; -using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using SJZY.InterfaceRelay.Application.Contracts; +using RabbitMQ.Client.Events; namespace InterfaceForward.Application.Rabbit; public class BatchForwardEventHandler( InterfaceForwardCommon forwardCommon, RabbitClient rabbitClient, - ILogRepository logRepository, - ILogger logger, - IFeiShuNoticer feiShuNoticer) + ILogRepository logRepository) : ITransientDependency, IRabbitHandler { - public const string BatchForwardEventSubscribe = "sjzy.interface.relay.batch"; - private readonly RabbitClient _rabbitClient = rabbitClient; + public const string BatchForwardEventSubscribe = "interface.relay.batch"; public bool Enable(ConsumeOptions options) { 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()); - logger.LogDebug($"rabbit on queue({options.Queue}) received msg"); var @event = System.Text.Json.JsonSerializer.Deserialize(msg); + if (@event == null) + { + throw new BusinessException("消息格式错误"); + } // important:恢复应用现场 全局贯彻 logRepository.AppId = @event.AppId; @@ -71,7 +69,7 @@ public class BatchForwardEventHandler( ? req : new JObject { - [@event.UpStreamCode!] = req + [@event.UpStreamCode] = req }; var res = contextList.Count == 1 @@ -85,12 +83,12 @@ public class BatchForwardEventHandler( catch (Exception ex) { replayEvent.Message = ex.Message; - await feiShuNoticer.NoticeAsync(ex.ToString()); + LogHelper.Error(ex.ToString(), false); } finally { var data = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(replayEvent); - _rabbitClient.Publish(GlobalConst.InterfaceRelayExchange, @event.ResSubscribeName, data); + rabbitClient.Publish(GlobalConst.InterfaceRelayExchange, @event.ResSubscribeName, data); } } } \ No newline at end of file diff --git a/src/InterfaceForward.Application/Rabbit/IRabbitHandler.cs b/src/InterfaceForward.Application/Rabbit/IRabbitHandler.cs new file mode 100644 index 0000000..a1c7c68 --- /dev/null +++ b/src/InterfaceForward.Application/Rabbit/IRabbitHandler.cs @@ -0,0 +1,10 @@ +using RabbitMQ.Client.Events; + +namespace InterfaceForward.Application.Rabbit; + +public interface IRabbitHandler +{ + bool Enable(ConsumeOptions options); + + Task Handle(BasicDeliverEventArgs args); +} \ No newline at end of file diff --git a/src/InterfaceForward.Application/Rabbit/RabbitClient.cs b/src/InterfaceForward.Application/Rabbit/RabbitClient.cs index 5128921..ba4bfb7 100644 --- a/src/InterfaceForward.Application/Rabbit/RabbitClient.cs +++ b/src/InterfaceForward.Application/Rabbit/RabbitClient.cs @@ -1,38 +1,68 @@ -using System.Text; using Fake.RabbitMQ; -using InterfaceForward.Domain.Shared; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using RabbitMQ.Client; using RabbitMQ.Client.Events; namespace InterfaceForward.Application.Rabbit; -public class RabbitClient(IRabbitMqChannelPool channelPool) +public class RabbitClient( + IRabbitMqChannelPool channelPool, + IServiceScopeFactory serviceScopeFactory, + ILogger logger) { public void Subscribe(ConsumeOptions consumeOptions) { - using var channelAccessor = channelPool.Acquire(consumeOptions.Queue, configureChannel: channel => - { - channel.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true); - channel.QueueDeclare(consumeOptions.Queue, true); - channel.QueueBind(consumeOptions.Queue, GlobalConst.InterfaceRelayExchange, consumeOptions.Queue); + using var channelAccessor = channelPool.Acquire(consumeOptions.Queue); - if (consumeOptions.FetchCount > 0) + var channel = channelAccessor.Channel; + + consumeOptions.Declaration.Invoke(channel); + + if (consumeOptions.FetchCount > 0) + { + channel.BasicQos(0, consumeOptions.FetchCount, false); + } + + var consumer = new AsyncEventingBasicConsumer(channel); + consumer.Received += async (model, ea) => + { + await using var scope = serviceScopeFactory.CreateAsyncScope(); + foreach (var handler in scope.ServiceProvider.GetServices()) { - channel.BasicQos(0, consumeOptions.FetchCount, false); - } - - var consumer = new AsyncEventingBasicConsumer(channel); - consumer.Received += async (model, ea) => + if (handler.Enable(consumeOptions)) { - var body = ea.Body.ToArray(); - var message = Encoding.UTF8.GetString(body); - Console.WriteLine(" [x] Received {0}", message); - }; - - channel.BasicConsume(queue: consumeOptions.Queue, - autoAck: false, - consumer: consumer); - }); + await handler.Handle(ea); + } + } + }; + + channel.BasicConsume(queue: consumeOptions.Queue, + autoAck: false, + consumer: consumer); + } + + public void Publish(string exchange, string routingKey, byte[] data, Action? 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); } } @@ -43,6 +73,6 @@ public class ConsumeOptions public ushort FetchCount { get; set; } public bool FailedRequeue { get; set; } - - public Action + + public Action Declaration { get; set; } } \ No newline at end of file diff --git a/src/InterfaceForward.Application/Services/App/AppSubscribeService.cs b/src/InterfaceForward.Application/Services/App/AppSubscribeService.cs new file mode 100644 index 0000000..c5660fb --- /dev/null +++ b/src/InterfaceForward.Application/Services/App/AppSubscribeService.cs @@ -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; + +/// +/// 应用订阅 +/// +[Route("AppSubscribe")] +[ApiExplorerSettings(GroupName = "应用服务")] +public class AppSubscribeService : ApplicationService +{ + public const int DefaultFetchCount = 1; + public const bool DefaultFailedRequeue = false; + + private readonly IBasicRepository _appRepository; + private readonly IBasicRepository _appSubscribeConfigRepository; + private readonly IBasicRepository _interfaceRepository; + private readonly IBasicRepository _serviceProviderRepository; + + public AppSubscribeService(IBasicRepository appSubscribeConfigRepository, + IBasicRepository interfaceRepository, + IBasicRepository serviceProviderRepository, IBasicRepository appRepository) + { + _appSubscribeConfigRepository = appSubscribeConfigRepository; + _interfaceRepository = interfaceRepository; + _serviceProviderRepository = serviceProviderRepository; + _appRepository = appRepository; + } + + /// + /// 订阅列表 + /// + /// + [HttpGet("GetList")] + public async Task> GetList(string? appKey) + { + return await _appSubscribeConfigRepository.GetListAsync(x => + string.IsNullOrWhiteSpace(appKey) || x.AppKey == appKey); + } + + /// + /// 创建or更新 + /// + /// 入参 + /// + [HttpPost("Upsert")] + public async Task 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(input); + @event.OptionType = OptionType.修改; + await RedisHelper.Client.PublishAsync(AppSubscribeEventHandler.AppSubscribeEventSubscribe, + @event.ToJson()); + return "订阅已更新,关注飞书消息,等待节点状态同步"; + } + + return "订阅已存在,且没有发生任何变化"; + } + + config = ObjectMapper.Map(input); + + await _appSubscribeConfigRepository.InsertAsync(config); + + var eventForAdd = ObjectMapper.Map(input); + eventForAdd.OptionType = OptionType.新增; + await RedisHelper.Client.PublishAsync(AppSubscribeEventHandler.AppSubscribeEventSubscribe, + eventForAdd.ToJson()); + return "新增订阅成功,关注飞书消息,等待节点状态同步"; + } + + /// + /// 删除 + /// + /// 入参 + /// + [HttpPost("Delete")] + public async Task 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(input); + @event.OptionType = OptionType.删除; + await RedisHelper.Client.PublishAsync(chan, @event.ToJson()); + return "成功删除应用订阅,关注飞书消息,等待节点状态同步"; + } + + return "应用订阅不存在"; + } +} \ No newline at end of file diff --git a/src/InterfaceForward.Application/Services/App/AppsService.cs b/src/InterfaceForward.Application/Services/App/AppsService.cs index 4af8fa6..f3b5332 100644 --- a/src/InterfaceForward.Application/Services/App/AppsService.cs +++ b/src/InterfaceForward.Application/Services/App/AppsService.cs @@ -20,7 +20,7 @@ namespace InterfaceForward.Application.Services.App; /// [Route("App")] [ApiExplorerSettings(GroupName = "应用服务")] -public class AppsService : BaseService +public class AppsService : ApplicationService { private readonly IAppRepository _appRepository; private readonly IAppScopeRepository _appScopeRepository; diff --git a/src/InterfaceForward.Application/Services/App/DictionaryService.cs b/src/InterfaceForward.Application/Services/App/DictionaryService.cs index a6437d9..cb3330a 100644 --- a/src/InterfaceForward.Application/Services/App/DictionaryService.cs +++ b/src/InterfaceForward.Application/Services/App/DictionaryService.cs @@ -8,7 +8,7 @@ namespace InterfaceForward.Application.Services.App /// [Route("Dictionary")] [ApiExplorerSettings(GroupName = "应用服务")] - public class DictionaryService : BaseService + public class DictionaryService : ApplicationService { private readonly IDictionaryRepository _dictionaryRepository; diff --git a/src/InterfaceForward.Application/Services/App/LogService.cs b/src/InterfaceForward.Application/Services/App/LogService.cs index e28001b..525f9e0 100644 --- a/src/InterfaceForward.Application/Services/App/LogService.cs +++ b/src/InterfaceForward.Application/Services/App/LogService.cs @@ -11,7 +11,7 @@ namespace InterfaceForward.Application.Services.App /// [Route("Log")] [ApiExplorerSettings(GroupName = "应用服务")] - public class LogService : BaseService + public class LogService : ApplicationService { private readonly ILogRepository _logRepository; diff --git a/src/InterfaceForward.Application/Services/BaseService.cs b/src/InterfaceForward.Application/Services/BaseService.cs deleted file mode 100644 index f6503a0..0000000 --- a/src/InterfaceForward.Application/Services/BaseService.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Fake.Application; - -namespace InterfaceForward.Application.Services; - -public abstract class BaseService : ApplicationService -{ -} \ No newline at end of file diff --git a/src/InterfaceForward.Application/Services/Interface/InterfaceReturnConfigService.cs b/src/InterfaceForward.Application/Services/Interface/InterfaceReturnConfigService.cs index 484511a..3ea9901 100644 --- a/src/InterfaceForward.Application/Services/Interface/InterfaceReturnConfigService.cs +++ b/src/InterfaceForward.Application/Services/Interface/InterfaceReturnConfigService.cs @@ -13,7 +13,7 @@ namespace InterfaceForward.Application.Services.Interface; /// 接口返回配置 /// [ApiExplorerSettings(GroupName = "接口服务")] -public class InterfaceReturnConfigService : BaseService +public class InterfaceReturnConfigService : ApplicationService { private readonly IInterfaceReturnConfigRepository _interfaceReturnConfigRepository; private readonly IInterfaceRepository _interfaceRepository; diff --git a/src/InterfaceForward.Application/Services/Interface/ServiceProviderInterfaceService.cs b/src/InterfaceForward.Application/Services/Interface/ServiceProviderInterfaceService.cs index e7a4a31..abfae06 100644 --- a/src/InterfaceForward.Application/Services/Interface/ServiceProviderInterfaceService.cs +++ b/src/InterfaceForward.Application/Services/Interface/ServiceProviderInterfaceService.cs @@ -18,7 +18,7 @@ namespace InterfaceForward.Application.Services.Interface; /// 服务商接口 /// [ApiExplorerSettings(GroupName = "接口服务")] -public class ServiceProviderInterfaceService : BaseService +public class ServiceProviderInterfaceService : ApplicationService { private ParameterService ParameterService => LazyServiceProvider.GetRequiredService(); diff --git a/src/InterfaceForward.Application/Services/Interface/SystemInterfaceService.cs b/src/InterfaceForward.Application/Services/Interface/SystemInterfaceService.cs index d06a7c5..3a95e12 100644 --- a/src/InterfaceForward.Application/Services/Interface/SystemInterfaceService.cs +++ b/src/InterfaceForward.Application/Services/Interface/SystemInterfaceService.cs @@ -17,7 +17,7 @@ namespace InterfaceForward.Application.Services.Interface; /// 系统接口 /// [ApiExplorerSettings(GroupName = "接口服务")] -public class SystemInterfaceService : BaseService +public class SystemInterfaceService : ApplicationService { #region ctor diff --git a/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs b/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs index 43de9bf..1eac2b6 100644 --- a/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs +++ b/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs @@ -12,10 +12,10 @@ using InterfaceForward.Domain.Shared.Dtos; using InterfaceForward.Domain.Shared.Enum; using InterfaceForward.Repositories; using InterfaceForward.Repositories.Log.Services; +using InterfaceForward.Repositories.Log.ValueObjects; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using SJZY.InterfaceRelay.Repository.Log.ValueObjects; namespace InterfaceForward.Application.Services; diff --git a/src/InterfaceForward.Application/Services/InterfaceForwardService.cs b/src/InterfaceForward.Application/Services/InterfaceForwardService.cs index 7635852..71b7f7a 100644 --- a/src/InterfaceForward.Application/Services/InterfaceForwardService.cs +++ b/src/InterfaceForward.Application/Services/InterfaceForwardService.cs @@ -6,8 +6,10 @@ using InterfaceForward.Application.Contracts; using InterfaceForward.Application.Contracts.ForwardCore; using InterfaceForward.Application.Filters; using InterfaceForward.Application.Rabbit; +using InterfaceForward.Application.Services.App; using InterfaceForward.Domain.Shared; using InterfaceForward.Repositories.Log.Services; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using RabbitMQ.Client; @@ -20,19 +22,21 @@ namespace InterfaceForward.Application.Services; [TypeFilter(typeof(ForwardAuthorizeFilter))] [AllowAnonymous] [Route("InterfaceForward")] -public class InterfaceForwardService : BaseService, IInterfaceForwardService +public class InterfaceForwardService : ApplicationService, IInterfaceForwardService { private readonly InterfaceForwardCommon _forwardCommon; private readonly ILogRepository _logRepository; private readonly RabbitClient _rabbitClient; + private readonly IHttpContextAccessor _httpContextAccessor; /// public InterfaceForwardService(ILogRepository logRepository, - InterfaceForwardCommon forwardCommon, RabbitClient rabbitClient) + InterfaceForwardCommon forwardCommon, RabbitClient rabbitClient,IHttpContextAccessor httpContextAccessor) { _logRepository = logRepository; _forwardCommon = forwardCommon; _rabbitClient = rabbitClient; + _httpContextAccessor = httpContextAccessor; } /// @@ -42,7 +46,7 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService [FromQuery] [Required] string serviceProviderCode, [FromBody] [Required] List data, [FromHeader] [Required] string resSubscribeName, - [FromHeader] string attach = null, + [FromHeader] string? attach = null, [FromHeader] bool isReturnMessage = false) { var contextList = await _forwardCommon.VerifyBusinessAndBuildForwardContexts(upStreamCode, @@ -59,7 +63,7 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService ResSubscribeName = resSubscribeName }; - var queueName = $"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{SJZYABPCore.HttpContext.Request + var queueName = $"{BatchForwardEventHandler.BatchForwardEventSubscribe}.{_httpContextAccessor.HttpContext!.Request .Headers["appKey"]}.{upStreamCode}.{serviceProviderCode}"; // tips:订阅需要持久化 @@ -101,7 +105,7 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService _rabbitClient.Publish(GlobalConst.InterfaceRelayExchange, queueName, eventBytes); } - return new InterfaceRelayUnifyResultDto(true, _logRepository.AppRequestLog.RequestId) + return new InterfaceRelayUnifyResultDto { RequestId = _logRepository.AppRequestLog.RequestId, OriginalMessage = null, @@ -109,7 +113,6 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService }; } - [CustomerResult] [HttpPost("ForwardWithSubscribe")] public async Task ForwardWithSubscribeAsync( [FromQuery] [Required] string upStreamCode, @@ -138,7 +141,7 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService ? await _forwardCommon.InternalForwardAsync(context) : await _forwardCommon.InternalForward2Async(contextList); - return new InterfaceRelayUnifyResultDto(true, res) + return new InterfaceRelayUnifyResultDto { RequestId = context.ServiceProviderRequestLog.RequestId, OriginalMessage = isReturnMessage ? context.ServiceProviderRequestLog.Response : null, @@ -182,7 +185,7 @@ public class InterfaceForwardService : BaseService, IInterfaceForwardService ? await _forwardCommon.InternalForwardAsync(context) : await _forwardCommon.InternalForward3Async(contextList, requestLogs); - return new InterfaceRelayUnifyResultDto(true, res) + return new InterfaceRelayUnifyResultDto { RequestId = context.ServiceProviderRequestLog.RequestId, OriginalMessage = isReturnMessage ? _logRepository.ServiceProviderRequestLog.Response : null, diff --git a/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapPublishService.cs b/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapPublishService.cs index 1314a9d..f6b43f6 100644 --- a/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapPublishService.cs +++ b/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapPublishService.cs @@ -23,7 +23,7 @@ public class InterfaceMapPublishService( IInterfaceMapPublishRepository interfaceMapPublishRepository, InterfaceForwardQuery interfaceForwardQuery, IInterfaceMapRepository interfaceMapRepository) - : ApplicationService + : Fake.Application.ApplicationService { private static readonly JsonSerializerSettings Settings = new() { diff --git a/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapService.cs b/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapService.cs index e8f237b..1950088 100644 --- a/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapService.cs +++ b/src/InterfaceForward.Application/Services/InterfaceMap/InterfaceMapService.cs @@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.InterfaceMap; /// 接口映射服务 /// [ApiExplorerSettings(GroupName = "接口映射服务")] -public partial class InterfaceMapService : ApplicationService +public partial class InterfaceMapService : Fake.Application.ApplicationService { private readonly IBasicRepository _fixedParameterRepository; private readonly IBasicRepository _interfaceMapDetailRepository; diff --git a/src/InterfaceForward.Application/Services/Parameter/FixedParameterService.cs b/src/InterfaceForward.Application/Services/Parameter/FixedParameterService.cs index 3b328f8..6dd062b 100644 --- a/src/InterfaceForward.Application/Services/Parameter/FixedParameterService.cs +++ b/src/InterfaceForward.Application/Services/Parameter/FixedParameterService.cs @@ -13,7 +13,7 @@ namespace InterfaceForward.Application.Services.Parameter; /// 固定参数配置 /// [ApiExplorerSettings(GroupName = "参数服务")] -public class FixedParameterService : BaseService +public class FixedParameterService : ApplicationService { private readonly IFixedParameterRepository _fixedParameterRepository; private readonly IServiceProviderRepository _serviceProviderRepository; diff --git a/src/InterfaceForward.Application/Services/Parameter/FormParameterService.cs b/src/InterfaceForward.Application/Services/Parameter/FormParameterService.cs index 28f7292..8d74b59 100644 --- a/src/InterfaceForward.Application/Services/Parameter/FormParameterService.cs +++ b/src/InterfaceForward.Application/Services/Parameter/FormParameterService.cs @@ -12,7 +12,7 @@ namespace InterfaceForward.Application.Services.Parameter; /// 表单参数配置 /// [ApiExplorerSettings(GroupName = "参数服务")] -public class FormParameterService : BaseService +public class FormParameterService : ApplicationService { private readonly IBasicRepository _formParameterRepository; diff --git a/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs b/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs index 4916a03..958dd2c 100644 --- a/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs +++ b/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs @@ -18,7 +18,7 @@ namespace InterfaceForward.Application.Services.Parameter; /// 参数服务 /// [ApiExplorerSettings(GroupName = "参数服务")] -public class ParameterService : BaseService +public class ParameterService : ApplicationService { private readonly IInterfaceRepository _interfaceRepository; private readonly IParameterRepository _parameterRepository; diff --git a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAccountService.cs b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAccountService.cs index b728a5c..93eca4a 100644 --- a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAccountService.cs +++ b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAccountService.cs @@ -14,7 +14,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider; /// 服务商账户 /// [ApiExplorerSettings(GroupName = "服务商服务")] -public class ServiceProviderAccountService : BaseService +public class ServiceProviderAccountService : ApplicationService { private readonly IServiceProviderAccountFieldRepository _serviceProviderAccountFieldRepository; private readonly IServiceProviderAccountFieldValueRepository _serviceProviderAccountFieldValueRepository; diff --git a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAuthService.cs b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAuthService.cs index 0b2a557..a4529bb 100644 --- a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAuthService.cs +++ b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderAuthService.cs @@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider; /// 服务商授权配置 /// [ApiExplorerSettings(GroupName = "服务商服务")] -public class ServiceProviderAuthService : BaseService +public class ServiceProviderAuthService : ApplicationService { private readonly IBasicRepository _interfaceRepository; private readonly IBasicRepository _parameterRepository; diff --git a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderImportExportService.cs b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderImportExportService.cs index afeaa24..a487b50 100644 --- a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderImportExportService.cs +++ b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderImportExportService.cs @@ -21,7 +21,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider; /// 导入导出服务 /// [ApiExplorerSettings(GroupName = "服务商服务")] -public class ServiceProviderImportExportService : BaseService +public class ServiceProviderImportExportService : ApplicationService { private readonly ISugarDbContextProvider _sqlSugarClientProvider; diff --git a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderService.cs b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderService.cs index 3382886..1b6b524 100644 --- a/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderService.cs +++ b/src/InterfaceForward.Application/Services/ServiceProvider/ServiceProviderService.cs @@ -15,7 +15,7 @@ namespace InterfaceForward.Application.Services.ServiceProvider; /// 服务商服务 /// [ApiExplorerSettings(GroupName = "服务商服务")] -public class ServiceProviderService : BaseService +public class ServiceProviderService : ApplicationService { private readonly IBasicRepository _interfaceRepository; private readonly IServiceProviderRepository _serviceProviderRepository; diff --git a/src/InterfaceForward.Domain.Shared/Dtos/RequestLogDto.cs b/src/InterfaceForward.Domain.Shared/Dtos/RequestLogDto.cs index 78916fd..9e83580 100644 --- a/src/InterfaceForward.Domain.Shared/Dtos/RequestLogDto.cs +++ b/src/InterfaceForward.Domain.Shared/Dtos/RequestLogDto.cs @@ -1,11 +1,19 @@ 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; + } + /// /// 请求Id /// - public Guid RequestId { get; set; } = requestId; + public Guid RequestId { get; set; } /// /// 请求时间(务必设置) @@ -20,37 +28,37 @@ public class RequestLogDto(Guid requestId) /// /// 应用/服务商名称 /// - public string? Name { get; set; } + public string Name { get; set; } /// /// 发起请求IP /// - public string? ClientIp { get; set; } + public string ClientIP { get; set; } /// /// 接口代码 /// - public string? InterfaceCode { get; set; } + public string InterfaceCode { get; set; } /// /// 请求接口名称 /// - public string? InterfaceName { get; set; } + public string InterfaceName { get; set; } /// /// 请求地址 /// - public string? Address { get; set; } + public string Address { get; set; } /// /// 请求头 /// - public string? Headers { get; set; } + public string Headers { get; set; } /// /// 请求体 /// - public string? Content { get; set; } + public string Content { get; set; } /// /// 响应耗时ms @@ -60,12 +68,12 @@ public class RequestLogDto(Guid requestId) /// /// 响应结果 /// - public string? Response { get; set; } - + public string Response { get; set; } + /// /// 响应结果映射后 /// - public string? Response2 { get; set; } + public string Response2 { get; set; } /// /// 是否成功调用 @@ -75,5 +83,5 @@ public class RequestLogDto(Guid requestId) /// /// 异常 /// - public string? Exception { get; set; } + public string Exception { get; set; } } \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/Dtos/RequestServiceProviderFailedCommon.cs b/src/InterfaceForward.Domain.Shared/Dtos/RequestServiceProviderFailedCommon.cs index 19edcca..afc415d 100644 --- a/src/InterfaceForward.Domain.Shared/Dtos/RequestServiceProviderFailedCommon.cs +++ b/src/InterfaceForward.Domain.Shared/Dtos/RequestServiceProviderFailedCommon.cs @@ -2,7 +2,7 @@ public static class RequestServiceProviderFailedCommon { - public const string RequestServiceProviderFailedSubscribeName = "SJZY.InterfaceRelay.RequestServiceProviderFailed"; + public const string RequestServiceProviderFailedSubscribeName = "InterfaceForward.RequestServiceProviderFailed"; public static string RequestFailedCode = "4001"; diff --git a/src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticer.cs b/src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticer.cs deleted file mode 100644 index 2d3cbd3..0000000 --- a/src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticer.cs +++ /dev/null @@ -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 _logger; - - public FeiShuNoticer(IOptions options, HttpClient httpClient, ILogger 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() - { - new List() - { - 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); - } -} \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/FeiShu/IFeiShuNoticer.cs b/src/InterfaceForward.Domain.Shared/FeiShu/IFeiShuNoticer.cs deleted file mode 100644 index f1d54d3..0000000 --- a/src/InterfaceForward.Domain.Shared/FeiShu/IFeiShuNoticer.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Fake.DependencyInjection; - -namespace InterfaceForward.Domain.Shared.FeiShu; - -public interface IFeiShuNoticer: ITransientDependency -{ - public Task NoticeAsync(string content, string subTitle = ""); -} \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/GlobalConst.cs b/src/InterfaceForward.Domain.Shared/GlobalConst.cs index fd0236c..17c3ac7 100644 --- a/src/InterfaceForward.Domain.Shared/GlobalConst.cs +++ b/src/InterfaceForward.Domain.Shared/GlobalConst.cs @@ -30,5 +30,5 @@ public static class GlobalConst /// public const string ServiceProviderInterfaceQpsKeyPrefix = "InterfaceQPS"; - public const string InterfaceRelayExchange = "sjzy.interface.relay.direct"; + public const string InterfaceRelayExchange = "interface.relay.direct"; } \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/Helpers/LogHelper.cs b/src/InterfaceForward.Domain.Shared/Helpers/LogHelper.cs new file mode 100644 index 0000000..4787f1f --- /dev/null +++ b/src/InterfaceForward.Domain.Shared/Helpers/LogHelper.cs @@ -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() + { + new List() + { + 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); + } +} \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/InterfaceForward.Domain.Shared.csproj b/src/InterfaceForward.Domain.Shared/InterfaceForward.Domain.Shared.csproj index eb79b9a..57b321e 100644 --- a/src/InterfaceForward.Domain.Shared/InterfaceForward.Domain.Shared.csproj +++ b/src/InterfaceForward.Domain.Shared/InterfaceForward.Domain.Shared.csproj @@ -11,6 +11,6 @@ - + diff --git a/src/InterfaceForward.Domain.Shared/InterfaceForwardDomainSharedModule.cs b/src/InterfaceForward.Domain.Shared/InterfaceForwardDomainSharedModule.cs index 4fe79d5..f4e18c5 100644 --- a/src/InterfaceForward.Domain.Shared/InterfaceForwardDomainSharedModule.cs +++ b/src/InterfaceForward.Domain.Shared/InterfaceForwardDomainSharedModule.cs @@ -1,5 +1,7 @@ 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; namespace InterfaceForward.Domain.Shared @@ -8,8 +10,8 @@ namespace InterfaceForward.Domain.Shared { public override void ConfigureServices(ServiceConfigurationContext context) { - var config = context.Services.GetConfiguration(); - context.Services.Configure(config.GetSection("FeiShuNotice")); + var configuration = context.Services.GetConfiguration(); + LogHelper.Init(configuration.GetSection("FeiShuNotice").Get()!); } } } \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticeOptions.cs b/src/InterfaceForward.Domain.Shared/Options/FeiShuNoticeOptions.cs similarity index 61% rename from src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticeOptions.cs rename to src/InterfaceForward.Domain.Shared/Options/FeiShuNoticeOptions.cs index a9a8e34..2c87952 100644 --- a/src/InterfaceForward.Domain.Shared/FeiShu/FeiShuNoticeOptions.cs +++ b/src/InterfaceForward.Domain.Shared/Options/FeiShuNoticeOptions.cs @@ -1,4 +1,4 @@ -namespace InterfaceForward.Domain.Shared.FeiShu; +namespace InterfaceForward.Domain.Shared.Options; public class FeiShuNoticeOptions { @@ -11,4 +11,9 @@ public class FeiShuNoticeOptions /// 消息标题前缀 /// public string TitlePrefix { get; set; } + + /// + /// 超时时间 秒 + /// + public int Timeout { get; set; } = 20; } \ No newline at end of file diff --git a/src/InterfaceForward.Domain.Shared/Options/NoticeOptions.cs b/src/InterfaceForward.Domain.Shared/Options/NoticeOptions.cs deleted file mode 100644 index 7e6fbb4..0000000 --- a/src/InterfaceForward.Domain.Shared/Options/NoticeOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace InterfaceForward.Domain.Shared.Options -{ - public class NoticeOptions - { - public string Webhook { get; set; } - - public string Title { get; set; } - } -} diff --git a/src/InterfaceForward.Repositories/App/Entitys/AppSubscribeConfigEntity.cs b/src/InterfaceForward.Repositories/App/Entitys/AppSubscribeConfigEntity.cs new file mode 100644 index 0000000..cacc267 --- /dev/null +++ b/src/InterfaceForward.Repositories/App/Entitys/AppSubscribeConfigEntity.cs @@ -0,0 +1,44 @@ +namespace InterfaceForward.Repositories.App.Entitys; + +/// +/// 应用mq订阅配置表 +/// +[SugarTable("t_app_subscribe_config")] +public class AppSubscribeConfigEntity : FullAuditedAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 应用key + /// + [SugarColumn(ColumnName = "AppKey")] + public string AppKey { get; set; } + + /// + /// 系统接口code + /// + [SugarColumn(ColumnName = "SystemInterfaceCode")] + public string SystemInterfaceCode { get; set; } + + /// + /// 服务商code + /// + [SugarColumn(ColumnName = "ServiceProviderCode")] + public string ServiceProviderCode { get; set; } + + /// + /// mq预取数量(服务并发度) + /// + [SugarColumn(ColumnName = "FetchCount")] + public ushort FetchCount { get; set; } + + /// + /// 失败重回队列 + /// + [SugarColumn(ColumnName = "FailedRequeue")] + public bool FailedRequeue { get; set; } +} \ No newline at end of file diff --git a/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj b/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj index 9494678..6204b73 100644 --- a/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj +++ b/src/InterfaceForward.Repositories/InterfaceForward.Repositories.csproj @@ -7,7 +7,8 @@ - + + diff --git a/src/InterfaceForward.Repositories/Log/Entitys/LogIndex.cs b/src/InterfaceForward.Repositories/Log/Entitys/LogIndex.cs index 69e280a..6c54ac9 100644 --- a/src/InterfaceForward.Repositories/Log/Entitys/LogIndex.cs +++ b/src/InterfaceForward.Repositories/Log/Entitys/LogIndex.cs @@ -29,8 +29,8 @@ public class LogIndex : IdBaseIndex /// /// 发起请求IP /// - public string? ClientIp { get; set; } - + public string ClientIP { get; set; } + /// /// 接口代码 /// @@ -66,11 +66,16 @@ public class LogIndex : IdBaseIndex /// public string Response { get; set; } + /// + /// 响应结果映射后 + /// + public string Response2 { get; set; } + /// /// 是否成功调用 /// public bool IsSuccess { get; set; } - + /// /// 异常 /// diff --git a/src/InterfaceForward.Repositories/Log/Services/ILogRepository.cs b/src/InterfaceForward.Repositories/Log/Services/ILogRepository.cs index d9897d5..8a428cc 100644 --- a/src/InterfaceForward.Repositories/Log/Services/ILogRepository.cs +++ b/src/InterfaceForward.Repositories/Log/Services/ILogRepository.cs @@ -1,70 +1,79 @@ using InterfaceForward.Domain.Shared.Dtos; -using Nest; using InterfaceForward.Repositories.Log.Entitys; using InterfaceForward.Repositories.Log.ValueObjects; -using SJZY.InterfaceRelay.Repository.Log.ValueObjects; +using Nest; -namespace InterfaceForward.Repositories.Log.Services; - -/// -/// 日志仓储 -/// -public interface ILogRepository +namespace InterfaceForward.Repositories.Log.Services { /// - /// 应用id + /// 日志仓储 /// - int AppId { get; set; } + public interface ILogRepository + { + /// + /// 应用id + /// important:全局贯彻 + /// + int AppId { get; set; } - /// - /// 应用日志 - /// - public RequestLogDto AppRequestLog { get; set; } + /// + /// 应用日志 + /// important:全局贯彻 + /// + public RequestLogDto AppRequestLog { get; set; } - /// - /// 最后一条服务商日志 - /// - public RequestLogDto ServiceProviderRequestLog { get; set; } + /// + /// 最后一条服务商日志 + /// important:全局贯彻 + /// + public RequestLogDto ServiceProviderRequestLog { get; set; } - /// - /// 写日志 - /// - /// 异常 - /// - Task WriteAppLogAsync(Exception? exception = null); + /// + /// 写日志 + /// + /// 异常 + /// + Task WriteAppLog(Exception? exception = null); - /// - /// 添加日志 - /// - /// - /// - Task AddLogAsync(RequestLogDto requestLog); + /// + /// 发飞书 + /// + /// + void SendFeiShu(Exception contextException); - /// - /// 日志列表 - /// - /// 入参 - /// - Task<(List list, long total)> GetListAsync(LogGetListInputValueObject input); + /// + /// 添加日志 + /// + /// + /// + Task AddLogAsync(RequestLogDto requestLog); - /// - /// 调用统计 - /// - /// 入参 - /// - Task> GetLogsStatisticsAsync(LogStatisticsInputValueObject input); + /// + /// 日志列表 + /// + /// 入参 + /// + Task<(List list, long total)> GetListAsync(LogGetListInputValueObject input); - /// - /// 根据ID获取单条 - /// - /// - /// - Task GetDetailsByIdAsync(string id); + /// + /// 调用统计 + /// + /// 入参 + /// + Task> GetLogsStatisticsAsync(LogStatisticsInputValueObject input); - /// - /// 根据给定请求id,获取请求日志 - /// - /// - /// - Task> GetRequestLogsAsync(Guid requestId); + /// + /// 根据ID获取单条 + /// + /// + /// + Task GetDetailsByIdAsync(string id); + + /// + /// 根据给定请求id,获取请求日志 + /// + /// + /// + Task> GetRequestLogsAsync(Guid requestId); + } } \ No newline at end of file diff --git a/src/InterfaceForward.Repositories/Log/Services/LogRepository.cs b/src/InterfaceForward.Repositories/Log/Services/LogRepository.cs index db45af4..4793c3a 100644 --- a/src/InterfaceForward.Repositories/Log/Services/LogRepository.cs +++ b/src/InterfaceForward.Repositories/Log/Services/LogRepository.cs @@ -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.FeiShu; +using InterfaceForward.Domain.Shared.Helpers; using InterfaceForward.Repositories.Log.Entitys; using InterfaceForward.Repositories.Log.ES; 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; @@ -14,16 +14,11 @@ namespace InterfaceForward.Repositories.Log.Services; /// public class LogRepository : ElasticSearchContextAbstract, ILogRepository, IScopedDependency { - private readonly IFeiShuNoticer _feiShuNoticer; - - public LogRepository(ConnectionFactory connection, IFeiShuNoticer feiShuNoticer) : base(connection) + public LogRepository(ConnectionFactory connection) : base(connection) { - _feiShuNoticer = feiShuNoticer; var guid = Guid.NewGuid(); - AppRequestLog = new RequestLogDto(guid) - { - IsSuccess = true // 只有接口通发生未处理异常才算应用失败 - }; + AppRequestLog = new RequestLogDto(guid); + AppRequestLog.IsSuccess = true; // 只有接口通发生未处理异常才算应用失败 ServiceProviderRequestLog = new RequestLogDto(guid); } @@ -31,7 +26,7 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit public RequestLogDto AppRequestLog { 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 if (exception != null) @@ -44,7 +39,23 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit 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) { @@ -56,7 +67,7 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit RequestTime = requestLog.RequestTime == default ? DateTime.Now : requestLog.RequestTime, IsApp = requestLog.IsApp, Name = requestLog.Name, - ClientIp = requestLog.ClientIp, + ClientIP = requestLog.ClientIP, InterfaceCode = requestLog.InterfaceCode, InterfaceName = requestLog.InterfaceName, Address = requestLog.Address, @@ -64,67 +75,73 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit Content = requestLog.Content, Cost = requestLog.Cost, Response = requestLog.Response, + Response2 = requestLog.Response2, IsSuccess = requestLog.IsSuccess, Exception = requestLog.Exception }; - IndexResponse response = await Context.IndexAsync(idx, - request => request.Index($"sjzy_interface_forward-{DateTime.Now:yyyy.MM.dd}")); - if (!response.IsValid) + try { - 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 list, long total)> GetListAsync(LogGetListInputValueObject input) { + Func, QueryContainer> query = input.RequestId.IsNullOrWhiteSpace() + ? q => + (input.Type != LogListInputTypeEnum.应用 ? null : q.Term(p => p.IsApp, true)) + && (input.Type != LogListInputTypeEnum.服务商 ? null : q.Term(p => p.IsApp, false)) + && (input.InterfaceName.IsNullOrEmpty() + ? null + : q.Wildcard(w => w.InterfaceName.Suffix("keyword"), "*" + input.InterfaceName + "*")) + && (input.Name.IsNullOrEmpty() + ? null + : q.Wildcard(w => w.Name.Suffix("keyword"), "*" + input.Name + "*")) + && (input.Content.IsNullOrEmpty() + ? null + : q.Wildcard(w => w.Content, "*" + input.Content?.ToLower() + "*")) + && (input.IsSuccess == null + ? null + : q.Term(w => w.IsSuccess, input.IsSuccess)) + && (input.Response.IsNullOrEmpty() + ? null + : q.Match(m => m.Field(f => f.Response).Query(input.Response))) + && ((input.RequestStartTime == null || input.RequestEndTime == null) + ? null + : q.DateRange(r => r + .Field(f => f.RequestTime) + .GreaterThanOrEquals(input.RequestStartTime) + .LessThanOrEquals(input.RequestEndTime) + .TimeZone("+08:00")) + ) + && (input.CostStart == null + ? null + : q.Range(t => t + .Field(f => f.Cost) + .GreaterThanOrEquals(input.CostStart)) + ) + && (input.CostEnd == null + ? null + : q.Range(t => t + .Field(f => f.Cost) + .LessThanOrEquals(input.CostEnd)) + ) + : q => q.Wildcard(w => w.RequestId.Suffix("keyword"), "*" + input.RequestId + "*"); + var data = await Context.SearchAsync(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.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, false)) - && (input.RequestId.IsNullOrWhiteSpace() - ? null - : q.Wildcard(w => w.RequestId.Suffix("keyword"), "*" + input.RequestId + "*")) - && (input.InterfaceName.IsNullOrEmpty() - ? null - : q.Wildcard(w => w.InterfaceName.Suffix("keyword"), "*" + input.InterfaceName + "*")) - && (input.Name.IsNullOrEmpty() - ? null - : q.Wildcard(w => w.Name.Suffix("keyword"), "*" + input.Name + "*")) - && (input.Content.IsNullOrEmpty() - ? null - : q.Wildcard(w => w.Content, "*" + input.Content?.ToLower() + "*")) - && (input.IsSuccess == null - ? null - : q.Term(w => w.IsSuccess, input.IsSuccess)) - && (input.Response.IsNullOrEmpty() - ? null - : q.Match(m => m.Field(f => f.Response).Query(input.Response))) - && ((input.RequestStartTime == null || input.RequestEndTime == null) - ? null - : q.DateRange(r => r - .Field(f => f.RequestTime) - .GreaterThanOrEquals(input.RequestStartTime) - .LessThanOrEquals(input.RequestEndTime) - .TimeZone("+08:00")) - ) - && (input.CostStart == null - ? null - : q.Range(t => t - .Field(f => f.Cost) - .GreaterThanOrEquals(input.CostStart)) - ) - && (input.CostEnd == null - ? null - : q.Range(t => t - .Field(f => f.Cost) - .LessThanOrEquals(input.CostEnd)) - ) - ) + .Query(query) .Sort(s => s.Field(f => f.RequestTime, SortOrder.Descending)) .From((input.PageIndex - 1) * input.PageSize) .Size(input.PageSize) @@ -153,10 +170,9 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit // 按请求时间搜索 && q.DateRange(r => r .Field(f => f.RequestTime) - .GreaterThanOrEquals(input.StartTime.ToString("yyyy-MM-dd"))) - && q.DateRange(r => r - .Field(f => f.RequestTime) - .LessThanOrEquals(input.EndTime.ToString("yyyy-MM-dd"))) + .GreaterThanOrEquals(input.StartTime.ToString("yyyy-MM-dd")) + .LessThanOrEquals(input.EndTime.ToString("yyyy-MM-dd")) + .TimeZone("+08:00")) ) // 分组 类似SQL的Group By .Aggregations(a => a @@ -218,10 +234,10 @@ public class LogRepository : ElasticSearchContextAbstract, ILogReposit IsApp = x.IsApp }).ToList(); } - - private static string Truncate(string str, int maxLen = 500) + + private static string? Truncate(string? str, int maxLen = 500) { if (str.IsNullOrWhiteSpace()) return str; - return str.Length <= maxLen ? str : str.Left(maxLen) + "..."; + return str!.Length <= maxLen ? str : str.Left(maxLen) + "..."; } } \ No newline at end of file diff --git a/src/InterfaceForward.Repositories/Log/ValueObjects/RequestLogSummary.cs b/src/InterfaceForward.Repositories/Log/ValueObjects/RequestLogSummary.cs index 48b6ca2..6830876 100644 --- a/src/InterfaceForward.Repositories/Log/ValueObjects/RequestLogSummary.cs +++ b/src/InterfaceForward.Repositories/Log/ValueObjects/RequestLogSummary.cs @@ -1,4 +1,4 @@ -namespace SJZY.InterfaceRelay.Repository.Log.ValueObjects; +namespace InterfaceForward.Repositories.Log.ValueObjects; public class RequestLogSummary { diff --git a/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj b/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj index 2da4ee2..3dbd78a 100644 --- a/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj +++ b/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj @@ -10,6 +10,7 @@ +