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