diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj
index b6e35c892..ba6d8dc63 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj
@@ -26,4 +26,8 @@
+
+
+
+
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreModule.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreModule.cs
index 9bd80e7b7..f4569ce83 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreModule.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreModule.cs
@@ -1,6 +1,7 @@
using LINGYUN.Abp.AI.Internal;
using LINGYUN.Abp.AI.Localization;
using LINGYUN.Abp.AI.Workspaces;
+using LINGYUN.Abp.Dynamic.Definitions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
@@ -18,7 +19,8 @@ namespace LINGYUN.Abp.AI;
typeof(AbpAIModule),
typeof(AbpGuidsModule),
typeof(AbpTimingModule),
- typeof(AbpLocalizationModule))]
+ typeof(AbpLocalizationModule),
+ typeof(AbpDynamicDefinitionsCoreModule))]
public class AbpAICoreModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
@@ -53,6 +55,11 @@ public class AbpAICoreModule : AbpModule
{
options.MapCodeNamespace(AbpAIErrorCodes.Namespace, typeof(AbpAIResource));
});
+
+ Configure(options =>
+ {
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ });
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs
index 3a4a78b8d..3b25830bd 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs
@@ -9,7 +9,6 @@ using Volo.Abp.Collections;
namespace LINGYUN.Abp.AI;
public class AbpAICoreOptions
{
- public DynamicWorkspaceStrategy DynamicWorkspaceStrategy { get; set; }
public ITypeList DefinitionProviders { get; }
public ITypeList ChatClientProviders { get; }
public ITypeList KernelProviders { get; }
@@ -21,7 +20,6 @@ public class AbpAICoreOptions
public AbpAICoreOptions()
{
- DynamicWorkspaceStrategy = DynamicWorkspaceStrategy.Merge;
DefinitionProviders = new TypeList();
ChatClientProviders = new TypeList();
KernelProviders = new TypeList();
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/DynamicWorkspaceStrategy.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/DynamicWorkspaceStrategy.cs
deleted file mode 100644
index 6aa754874..000000000
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/DynamicWorkspaceStrategy.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace LINGYUN.Abp.AI.Workspaces;
-///
-/// 动态工作区策略
-///
-public enum DynamicWorkspaceStrategy
-{
- ///
- /// 忽略动态工作区(静态优先)
- ///
- Ignore,
-
- ///
- /// 动态覆盖静态
- ///
- Covering,
-
- ///
- /// 合并策略
- ///
- Merge
-}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinition.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinition.cs
index 9b6d9c431..a59c636df 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinition.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinition.cs
@@ -147,8 +147,7 @@ public class WorkspaceDefinition : IHasSimpleStateCheckers
Name = name;
Provider = provider;
ModelName = modelName;
- _displayName = displayName;
- _displayName = displayName;
+ DisplayName = displayName;
Description = description;
SystemPrompt = systemPrompt;
Instructions = instructions;
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinitionManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinitionManager.cs
index 0a4ef9102..2d48aa041 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinitionManager.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/WorkspaceDefinitionManager.cs
@@ -1,231 +1,117 @@
-using Microsoft.Extensions.Options;
+using JetBrains.Annotations;
+using LINGYUN.Abp.Dynamic.Definitions;
+using Microsoft.Extensions.Options;
using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Workspaces;
-public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingletonDependency
+
+public class WorkspaceDefinitionManager :
+ DynamicDefinitionManager,
+ IWorkspaceDefinitionManager,
+ ITransientDependency
{
- protected readonly AbpAICoreOptions Options;
- protected readonly IStaticWorkspaceDefinitionStore StaticStore;
- protected readonly IDynamicWorkspaceDefinitionStore DynamicStore;
+ protected IStaticWorkspaceDefinitionStore StaticStore { get; }
+ protected IDynamicWorkspaceDefinitionStore DynamicStore { get; }
+ protected AbpAICoreOptions AIOptions { get; }
public WorkspaceDefinitionManager(
IStaticWorkspaceDefinitionStore staticStore,
IDynamicWorkspaceDefinitionStore dynamicStore,
- IOptions options)
+ IOptions options,
+ IOptions aIOptions)
+ : base(options)
{
StaticStore = staticStore;
DynamicStore = dynamicStore;
- Options = options.Value;
+ AIOptions = aIOptions.Value;
}
- public virtual async Task GetAsync(string name)
+ public async virtual Task> GetAllAsync()
{
- var workspace = await GetOrNullAsync(name);
- if (workspace == null)
- {
- throw new AbpException("Undefined Workspace: " + name);
- }
+ var staticDefinitions = await StaticStore.GetAllAsync();
+ var dynamicDefinitions = await DynamicStore.GetAllAsync();
- return workspace;
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
}
- public virtual async Task GetOrNullAsync(string name)
+ public async virtual Task GetAsync([NotNull] string name)
{
- Check.NotNull(name, nameof(name));
-
- var staticDefinition = await StaticStore.GetOrNullAsync(name);
- var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
-
- if (staticDefinition != null && dynamicDefinition != null)
- {
- return Options.DynamicWorkspaceStrategy switch
- {
- DynamicWorkspaceStrategy.Ignore => staticDefinition,
- DynamicWorkspaceStrategy.Covering => dynamicDefinition,
- DynamicWorkspaceStrategy.Merge => MergeWorkspace(staticDefinition, dynamicDefinition),
- _ => MergeWorkspace(staticDefinition, dynamicDefinition)
- };
- }
-
- return staticDefinition ?? dynamicDefinition;
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined Workspace: " + name);
}
- public virtual async Task> GetAllAsync()
+ public async virtual Task GetOrNullAsync([NotNull] string name)
{
- var staticWorkspaces = await StaticStore.GetAllAsync();
- var dynamicWorkspaces = await DynamicStore.GetAllAsync();
-
- // 根据策略处理工作区定义
- return Options.DynamicWorkspaceStrategy switch
- {
- DynamicWorkspaceStrategy.Ignore => await GetWorkspacesWithIgnoreStrategy(staticWorkspaces, dynamicWorkspaces),
- DynamicWorkspaceStrategy.Covering => await GetWorkspacesWithCoveringStrategy(staticWorkspaces, dynamicWorkspaces),
- DynamicWorkspaceStrategy.Merge => await GetWorkspacesWithMergeStrategy(staticWorkspaces, dynamicWorkspaces),
- _ => await GetWorkspacesWithMergeStrategy(staticWorkspaces, dynamicWorkspaces) // 默认使用合并策略
- };
- }
-
- #region 工作区定义策略
+ Check.NotNull(name, nameof(name));
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态工作区
- ///
- protected virtual Task> GetWorkspacesWithIgnoreStrategy(
- IReadOnlyList staticWorkspaces,
- IReadOnlyList dynamicWorkspaces)
- {
- var staticWorkspaceNames = staticWorkspaces
- .Select(p => p.Name)
- .ToImmutableHashSet();
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
- return Task.FromResult>(
- staticWorkspaces
- .Concat(dynamicWorkspaces.Where(d => !staticWorkspaceNames.Contains(d.Name)))
- .ToImmutableList()
- );
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
}
- ///
- /// 覆盖策略:动态完全覆盖静态工作区
- ///
- protected virtual Task> GetWorkspacesWithCoveringStrategy(
- IReadOnlyList staticWorkspaces,
- IReadOnlyList dynamicWorkspaces)
+ protected override string GetDefinitionKey(WorkspaceDefinition definition)
{
- var dynamicWorkspaceNames = dynamicWorkspaces
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- // 动态工作区完全覆盖静态工作区
- var result = dynamicWorkspaces
- .Concat(staticWorkspaces.Where(s => !dynamicWorkspaceNames.Contains(s.Name)))
- .ToImmutableList();
-
- return Task.FromResult>(result);
+ return definition.Name;
}
- ///
- /// 合并策略:合并静态和动态工作区,创建新实例
- ///
- protected virtual Task> GetWorkspacesWithMergeStrategy(
- IReadOnlyList staticWorkspaces,
- IReadOnlyList dynamicWorkspaces)
+ protected override Task AfterMergedDefinitionsAsync(Dictionary mergedDefinitions)
{
- var mergedWorkspaces = new Dictionary();
-
- // 先添加所有静态工作区
- foreach (var staticWorkspace in staticWorkspaces)
- {
- mergedWorkspaces[staticWorkspace.Name] = staticWorkspace;
- }
-
- // 合并动态工作区
- foreach (var dynamicWorkspace in dynamicWorkspaces)
+ foreach (var deletedWorkspaceName in AIOptions.DeletedWorkspaces)
{
- if (mergedWorkspaces.TryGetValue(dynamicWorkspace.Name, out var existingWorkspace))
- {
- // 工作区已存在,创建新的合并工作区
- var mergedWorkspace = MergeWorkspace(existingWorkspace, dynamicWorkspace);
- mergedWorkspaces[dynamicWorkspace.Name] = mergedWorkspace;
- }
- else
- {
- // 添加新的动态工作区
- mergedWorkspaces[dynamicWorkspace.Name] = dynamicWorkspace;
- }
+ mergedDefinitions.Remove(deletedWorkspaceName);
}
- // 处理被删除的工作区
- foreach (var deletedWorkspaceName in Options.DeletedWorkspaces)
- {
- if (mergedWorkspaces.ContainsKey(deletedWorkspaceName))
- {
- mergedWorkspaces.Remove(deletedWorkspaceName);
- }
- }
-
- return Task.FromResult>(mergedWorkspaces.Values.ToImmutableList());
+ return Task.CompletedTask;
}
- ///
- /// 合并两个工作区定义,返回新的 WorkspaceDefinition 实例
- ///
- protected virtual WorkspaceDefinition MergeWorkspace(
- WorkspaceDefinition staticWorkspace,
- WorkspaceDefinition dynamicWorkspace)
+ protected override Task MergeDefinitionAsync(WorkspaceDefinition targetDefinition, WorkspaceDefinition sourceDefinition)
{
- // 决定使用哪个提供者(优先使用动态的)
- var provider = !string.IsNullOrEmpty(dynamicWorkspace.Provider)
- ? dynamicWorkspace.Provider
- : staticWorkspace.Provider;
-
- // 决定使用哪个模型名称(优先使用动态的)
- var modelName = !string.IsNullOrEmpty(dynamicWorkspace.ModelName)
- ? dynamicWorkspace.ModelName
- : staticWorkspace.ModelName;
-
- // 决定使用哪个显示名称(优先使用动态的)
- var displayName = dynamicWorkspace.DisplayName ?? staticWorkspace.DisplayName;
-
- // 创建新的工作区实例(Name是只读的)
+ var provider = !string.IsNullOrEmpty(sourceDefinition.Provider)
+ ? sourceDefinition.Provider
+ : targetDefinition.Provider;
+ var modelName = !string.IsNullOrEmpty(sourceDefinition.ModelName)
+ ? sourceDefinition.ModelName
+ : targetDefinition.ModelName;
+ var displayName = sourceDefinition.DisplayName ?? targetDefinition.DisplayName;
var mergedWorkspace = new WorkspaceDefinition(
- staticWorkspace.Name, // 保持名称不变
+ targetDefinition.Name,
provider,
modelName,
displayName
- );
-
- // 设置描述(优先使用动态的)
- mergedWorkspace.Description = dynamicWorkspace.Description ?? staticWorkspace.Description;
+ )
+ {
+ Description = sourceDefinition.Description ?? targetDefinition.Description
+ };
- // 设置API密钥(优先使用动态的)
- if (!string.IsNullOrEmpty(dynamicWorkspace.ApiKey))
+ if (!string.IsNullOrEmpty(sourceDefinition.ApiKey))
{
- mergedWorkspace.WithApiKey(dynamicWorkspace.ApiKey!);
+ mergedWorkspace.WithApiKey(sourceDefinition.ApiKey!);
}
- else if (!string.IsNullOrEmpty(staticWorkspace.ApiKey))
+ else if (!string.IsNullOrEmpty(targetDefinition.ApiKey))
{
- mergedWorkspace.WithApiKey(staticWorkspace.ApiKey!);
+ mergedWorkspace.WithApiKey(targetDefinition.ApiKey!);
}
- // 设置API基础URL(优先使用动态的)
- if (!string.IsNullOrEmpty(dynamicWorkspace.ApiBaseUrl))
+ if (!string.IsNullOrEmpty(sourceDefinition.ApiBaseUrl))
{
- mergedWorkspace.WithApiBaseUrl(dynamicWorkspace.ApiBaseUrl!);
+ mergedWorkspace.WithApiBaseUrl(sourceDefinition.ApiBaseUrl!);
}
- else if (!string.IsNullOrEmpty(staticWorkspace.ApiBaseUrl))
+ else if (!string.IsNullOrEmpty(targetDefinition.ApiBaseUrl))
{
- mergedWorkspace.WithApiBaseUrl(staticWorkspace.ApiBaseUrl!);
+ mergedWorkspace.WithApiBaseUrl(targetDefinition.ApiBaseUrl!);
}
+ mergedWorkspace.SystemPrompt = sourceDefinition.SystemPrompt ?? targetDefinition.SystemPrompt;
+ mergedWorkspace.Instructions = sourceDefinition.Instructions ?? targetDefinition.Instructions;
+ mergedWorkspace.Temperature = sourceDefinition.Temperature ?? targetDefinition.Temperature;
+ mergedWorkspace.MaxOutputTokens = sourceDefinition.MaxOutputTokens ?? targetDefinition.MaxOutputTokens;
+ mergedWorkspace.FrequencyPenalty = sourceDefinition.FrequencyPenalty ?? targetDefinition.FrequencyPenalty;
+ mergedWorkspace.PresencePenalty = sourceDefinition.PresencePenalty ?? targetDefinition.PresencePenalty;
+ mergedWorkspace.IsEnabled = targetDefinition.IsEnabled || sourceDefinition.IsEnabled;
- // 设置系统提示词(优先使用动态的)
- mergedWorkspace.SystemPrompt = dynamicWorkspace.SystemPrompt ?? staticWorkspace.SystemPrompt;
-
- // 设置附加系统提示词(优先使用动态的)
- mergedWorkspace.Instructions = dynamicWorkspace.Instructions ?? staticWorkspace.Instructions;
-
- // 设置温度值(优先使用动态的)
- mergedWorkspace.Temperature = dynamicWorkspace.Temperature ?? staticWorkspace.Temperature;
-
- // 设置最大输出token数(优先使用动态的)
- mergedWorkspace.MaxOutputTokens = dynamicWorkspace.MaxOutputTokens ?? staticWorkspace.MaxOutputTokens;
-
- // 设置频率惩罚(优先使用动态的)
- mergedWorkspace.FrequencyPenalty = dynamicWorkspace.FrequencyPenalty ?? staticWorkspace.FrequencyPenalty;
-
- // 设置存在惩罚(优先使用动态的)
- mergedWorkspace.PresencePenalty = dynamicWorkspace.PresencePenalty ?? staticWorkspace.PresencePenalty;
-
- // 设置是否启用(只要有一方启用,结果就是启用)
- mergedWorkspace.IsEnabled = staticWorkspace.IsEnabled || dynamicWorkspace.IsEnabled;
-
- // 合并状态检查器
- foreach (var checker in staticWorkspace.StateCheckers)
+ foreach (var checker in targetDefinition.StateCheckers)
{
if (!mergedWorkspace.StateCheckers.Contains(checker))
{
@@ -233,7 +119,7 @@ public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingleto
}
}
- foreach (var checker in dynamicWorkspace.StateCheckers)
+ foreach (var checker in sourceDefinition.StateCheckers)
{
if (!mergedWorkspace.StateCheckers.Contains(checker))
{
@@ -241,8 +127,7 @@ public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingleto
}
}
- // 合并工具列表(去重)
- foreach (var tool in staticWorkspace.Tools)
+ foreach (var tool in targetDefinition.Tools)
{
if (!mergedWorkspace.Tools.Contains(tool))
{
@@ -250,7 +135,7 @@ public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingleto
}
}
- foreach (var tool in dynamicWorkspace.Tools)
+ foreach (var tool in sourceDefinition.Tools)
{
if (!mergedWorkspace.Tools.Contains(tool))
{
@@ -258,19 +143,16 @@ public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingleto
}
}
- // 合并属性(动态覆盖静态)
- foreach (var property in staticWorkspace.Properties)
+ foreach (var property in targetDefinition.Properties)
{
mergedWorkspace.Properties[property.Key] = property.Value;
}
- foreach (var property in dynamicWorkspace.Properties)
+ foreach (var property in sourceDefinition.Properties)
{
mergedWorkspace.Properties[property.Key] = property.Value;
}
- return mergedWorkspace;
+ return Task.FromResult(mergedWorkspace);
}
-
- #endregion
}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
index 630842b08..70179c0b7 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
@@ -1,188 +1,90 @@
-using Microsoft.Extensions.Options;
+using JetBrains.Annotations;
+using LINGYUN.Abp.Dynamic.Definitions;
+using Microsoft.Extensions.Options;
using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Tools;
-public class AIToolDefinitionManager : IAIToolDefinitionManager, ISingletonDependency
+public class AIToolDefinitionManager :
+ DynamicDefinitionManager,
+ IAIToolDefinitionManager,
+ ITransientDependency
{
- protected readonly AbpAIToolsOptions AIToolOptions;
- protected readonly IStaticAIToolDefinitionStore StaticStore;
- protected readonly IDynamicAIToolDefinitionStore DynamicStore;
+ protected IStaticAIToolDefinitionStore StaticStore { get; }
+ protected IDynamicAIToolDefinitionStore DynamicStore { get; }
+ protected AbpAIToolsOptions AIToolsOptions { get; }
public AIToolDefinitionManager(
IStaticAIToolDefinitionStore staticStore,
IDynamicAIToolDefinitionStore dynamicStore,
- IOptions aiToolOptions)
+ IOptions options,
+ IOptions aIToolsOptions)
+ : base(options)
{
StaticStore = staticStore;
DynamicStore = dynamicStore;
- AIToolOptions = aiToolOptions.Value;
+ AIToolsOptions = aIToolsOptions.Value;
}
- public virtual async Task GetAsync(string name)
+ public async virtual Task GetAsync([NotNull] string name)
{
- var workspace = await GetOrNullAsync(name);
- if (workspace == null)
- {
- throw new AbpException("Undefined AITool: " + name);
- }
-
- return workspace;
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined AITool: " + name);
}
- public virtual async Task GetOrNullAsync(string name)
+ public async virtual Task> GetAllAsync()
{
- Check.NotNull(name, nameof(name));
-
- var staticDefinition = await StaticStore.GetOrNullAsync(name);
- var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
-
- if (staticDefinition != null && dynamicDefinition != null)
- {
- return AIToolOptions.DynamicAItoolStrategy switch
- {
- DynamicAItoolStrategy.Ignore => staticDefinition,
- DynamicAItoolStrategy.Covering => dynamicDefinition,
- DynamicAItoolStrategy.Merge => MergeAITool(staticDefinition, dynamicDefinition),
- _ => MergeAITool(staticDefinition, dynamicDefinition)
- };
- }
+ var staticDefinitions = await StaticStore.GetAllAsync();
+ var dynamicDefinitions = await DynamicStore.GetAllAsync();
- return staticDefinition ?? dynamicDefinition;
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
}
- public virtual async Task> GetAllAsync()
+ public async virtual Task GetOrNullAsync([NotNull] string name)
{
- var staticAITools = await StaticStore.GetAllAsync();
- var dynamicAITools = await DynamicStore.GetAllAsync();
-
- // 根据策略处理AI工具定义
- return AIToolOptions.DynamicAItoolStrategy switch
- {
- DynamicAItoolStrategy.Ignore => await GetAIToolsWithIgnoreStrategy(staticAITools, dynamicAITools),
- DynamicAItoolStrategy.Covering => await GetAIToolsWithCoveringStrategy(staticAITools, dynamicAITools),
- DynamicAItoolStrategy.Merge => await GetAIToolsWithMergeStrategy(staticAITools, dynamicAITools),
- _ => await GetAIToolsWithMergeStrategy(staticAITools, dynamicAITools) // 默认使用合并策略
- };
- }
+ Check.NotNull(name, nameof(name));
- #region AI工具定义策略
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态AI工具
- ///
- protected virtual Task> GetAIToolsWithIgnoreStrategy(
- IReadOnlyList staticAITools,
- IReadOnlyList dynamicAITools)
- {
- var staticAIToolNames = staticAITools
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- return Task.FromResult>(
- staticAITools
- .Concat(dynamicAITools.Where(d => !staticAIToolNames.Contains(d.Name)))
- .ToImmutableList()
- );
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
}
- ///
- /// 覆盖策略:动态完全覆盖静态AI工具
- ///
- protected virtual Task> GetAIToolsWithCoveringStrategy(
- IReadOnlyList staticAITools,
- IReadOnlyList dynamicAITools)
+ protected override string GetDefinitionKey(AIToolDefinition definition)
{
- var dynamicAIToolNames = dynamicAITools
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- // 动态AI工具完全覆盖静态AI工具
- var result = dynamicAITools
- .Concat(staticAITools.Where(s => !dynamicAIToolNames.Contains(s.Name)))
- .ToImmutableList();
-
- return Task.FromResult>(result);
+ return definition.Name;
}
- ///
- /// 合并策略:合并静态和动态AI工具,创建新实例
- ///
- protected virtual Task> GetAIToolsWithMergeStrategy(
- IReadOnlyList staticAITools,
- IReadOnlyList dynamicAITools)
+ protected override Task AfterMergedDefinitionsAsync(Dictionary mergedDefinitions)
{
- var mergedAITools = new Dictionary();
-
- // 先添加所有静态AI工具
- foreach (var staticAITool in staticAITools)
- {
- mergedAITools[staticAITool.Name] = staticAITool;
- }
-
- // 合并动态AI工具
- foreach (var dynamicAITool in dynamicAITools)
- {
- if (mergedAITools.TryGetValue(dynamicAITool.Name, out var existingAITool))
- {
- // AI工具已存在,创建新的合并AI工具
- var mergedAITool = MergeAITool(existingAITool, dynamicAITool);
- mergedAITools[dynamicAITool.Name] = mergedAITool;
- }
- else
- {
- // 添加新的动态AI工具
- mergedAITools[dynamicAITool.Name] = dynamicAITool;
- }
- }
-
- // 处理被删除的AI工具
- foreach (var deletedToolName in AIToolOptions.DeletedAITools)
+ foreach (var deletedToolName in AIToolsOptions.DeletedAITools)
{
- if (mergedAITools.ContainsKey(deletedToolName))
- {
- mergedAITools.Remove(deletedToolName);
- }
+ mergedDefinitions.Remove(deletedToolName);
}
- return Task.FromResult>(mergedAITools.Values.ToImmutableList());
+ return Task.CompletedTask;
}
- ///
- /// 合并两个AI工具定义,返回新的 AIToolDefinition 实例
- ///
- protected virtual AIToolDefinition MergeAITool(
- AIToolDefinition staticAITool,
- AIToolDefinition dynamicAITool)
+ protected override Task MergeDefinitionAsync(AIToolDefinition targetDefinition, AIToolDefinition sourceDefinition)
{
- // 决定使用哪个提供者(优先使用动态的)
- var provider = !string.IsNullOrEmpty(dynamicAITool.Provider)
- ? dynamicAITool.Provider
- : staticAITool.Provider;
-
- // 决定使用哪个描述(优先使用动态的)
- var description = dynamicAITool.Description ?? staticAITool.Description;
+ var provider = !string.IsNullOrEmpty(sourceDefinition.Provider)
+ ? sourceDefinition.Provider
+ : targetDefinition.Provider;
+ var description = sourceDefinition.Description ?? targetDefinition.Description;
- // 创建新的AI工具实例(Name是只读的)
var mergedAITool = new AIToolDefinition(
- staticAITool.Name, // 保持名称不变
+ targetDefinition.Name,
provider,
description
- );
-
- // 设置是否启用(只要有一方启用,结果就是启用)
- mergedAITool.IsEnabled = staticAITool.IsEnabled || dynamicAITool.IsEnabled;
-
- // 设置是否为全局工具(只要有一方是全局,结果就是全局)
- mergedAITool.IsGlobal = staticAITool.IsGlobal || dynamicAITool.IsGlobal;
+ )
+ {
+ IsEnabled = targetDefinition.IsEnabled || sourceDefinition.IsEnabled,
+ IsGlobal = targetDefinition.IsGlobal || sourceDefinition.IsGlobal
+ };
- // 合并状态检查器
- foreach (var checker in staticAITool.StateCheckers)
+ foreach (var checker in targetDefinition.StateCheckers)
{
if (!mergedAITool.StateCheckers.Contains(checker))
{
@@ -190,7 +92,7 @@ public class AIToolDefinitionManager : IAIToolDefinitionManager, ISingletonDepen
}
}
- foreach (var checker in dynamicAITool.StateCheckers)
+ foreach (var checker in sourceDefinition.StateCheckers)
{
if (!mergedAITool.StateCheckers.Contains(checker))
{
@@ -198,19 +100,16 @@ public class AIToolDefinitionManager : IAIToolDefinitionManager, ISingletonDepen
}
}
- // 合并属性(动态覆盖静态)
- foreach (var property in staticAITool.Properties)
+ foreach (var property in targetDefinition.Properties)
{
mergedAITool.Properties[property.Key] = property.Value;
}
- foreach (var property in dynamicAITool.Properties)
+ foreach (var property in sourceDefinition.Properties)
{
mergedAITool.Properties[property.Key] = property.Value;
}
- return mergedAITool;
+ return Task.FromResult(mergedAITool);
}
-
- #endregion
-}
\ No newline at end of file
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
index 2da4d9526..7f702e323 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
@@ -1,7 +1,7 @@
using LINGYUN.Abp.AI.Localization;
+using LINGYUN.Abp.Dynamic.Definitions;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using Volo.Abp.Localization;
@@ -58,6 +58,11 @@ public class AbpAIToolsModule : AbpModule
.Get()
.AddVirtualJson("/LINGYUN/Abp/AI/Tools/Localization/Resources");
});
+
+ Configure(options =>
+ {
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ });
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
index e1bd082c1..fa552fa29 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
@@ -5,12 +5,10 @@ namespace LINGYUN.Abp.AI.Tools;
public class AbpAIToolsOptions
{
public ITypeList DefinitionProviders { get; }
- public DynamicAItoolStrategy DynamicAItoolStrategy { get; set; }
public ITypeList AIToolProviders { get; }
public HashSet DeletedAITools { get; }
public AbpAIToolsOptions()
{
- DynamicAItoolStrategy = DynamicAItoolStrategy.Merge;
DefinitionProviders = new TypeList();
AIToolProviders = new TypeList();
DeletedAITools = new HashSet();
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/DynamicAItoolStrategy.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/DynamicAItoolStrategy.cs
deleted file mode 100644
index 3435eb580..000000000
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/DynamicAItoolStrategy.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace LINGYUN.Abp.AI.Tools;
-///
-/// 动态工具策略
-///
-public enum DynamicAItoolStrategy : byte
-{
- ///
- /// 忽略
- ///
- Ignore = 0,
- ///
- /// 覆盖
- ///
- Covering =1,
- ///
- /// 合并
- ///
- Merge = 2
-}
diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj
index a9cf1bbb2..147ebdd44 100644
--- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj
+++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj
@@ -22,6 +22,7 @@
+
diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsCoreModule.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsCoreModule.cs
index 18ad47fe2..dc3d5484b 100644
--- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsCoreModule.cs
+++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsCoreModule.cs
@@ -1,4 +1,5 @@
-using LINGYUN.Abp.Notifications.Localization;
+using LINGYUN.Abp.Dynamic.Definitions;
+using LINGYUN.Abp.Notifications.Localization;
using LINGYUN.Abp.RealTime;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -12,6 +13,7 @@ using Volo.Abp.TextTemplating;
namespace LINGYUN.Abp.Notifications;
[DependsOn(
+ typeof(AbpDynamicDefinitionsCoreModule),
typeof(AbpTextTemplatingCoreModule),
typeof(AbpRealTimeModule),
typeof(AbpLocalizationModule),
@@ -36,6 +38,12 @@ public class AbpNotificationsCoreModule : AbpModule
{
preActions.Configure(options);
});
+
+ Configure(options =>
+ {
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ });
}
private void AutoAddDefinitionProviders(IServiceCollection services)
diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsOptions.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsOptions.cs
index d158f25c5..a88701015 100644
--- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsOptions.cs
+++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/AbpNotificationsOptions.cs
@@ -10,15 +10,12 @@ public class AbpNotificationsOptions
///
public ITypeList DefinitionProviders { get; }
- public DynamicNotificationStrategy DynamicNotificationStrategy { get; set; }
-
public HashSet DeletedNotifications { get; }
public HashSet DeletedNotificationGroups { get; }
public AbpNotificationsOptions()
{
- DynamicNotificationStrategy = DynamicNotificationStrategy.Merge;
DefinitionProviders = new TypeList();
DeletedNotifications = new HashSet();
diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/DynamicNotificationStrategy.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/DynamicNotificationStrategy.cs
deleted file mode 100644
index f473fed87..000000000
--- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/DynamicNotificationStrategy.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace LINGYUN.Abp.Notifications;
-///
-/// 动态通知策略
-///
-public enum DynamicNotificationStrategy : byte
-{
- ///
- /// 忽略
- ///
- Ignore = 0,
- ///
- /// 覆盖
- ///
- Covering =1,
- ///
- /// 合并
- ///
- Merge = 2
-}
diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs
index 0fa26ae5e..7d6b4a24d 100644
--- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs
+++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs
@@ -1,224 +1,93 @@
-using Microsoft.Extensions.Options;
+using JetBrains.Annotations;
+using LINGYUN.Abp.Dynamic.Definitions;
+using Microsoft.Extensions.Options;
using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Notifications;
-public class NotificationDefinitionManager : INotificationDefinitionManager, ITransientDependency
+public class NotificationDefinitionManager :
+ DynamicDefinitionManager,
+ INotificationDefinitionManager,
+ ITransientDependency
{
- private readonly AbpNotificationsOptions _notificationsOptions;
- private readonly IStaticNotificationDefinitionStore _staticStore;
- private readonly IDynamicNotificationDefinitionStore _dynamicStore;
+ protected IStaticNotificationDefinitionStore StaticStore { get; }
+ protected IDynamicNotificationDefinitionStore DynamicStore { get; }
public NotificationDefinitionManager(
IStaticNotificationDefinitionStore staticStore,
IDynamicNotificationDefinitionStore dynamicStore,
- IOptions notificationsOptions)
+ IOptions options) : base(options)
{
- _staticStore = staticStore;
- _dynamicStore = dynamicStore;
- _notificationsOptions = notificationsOptions.Value;
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
}
- public async virtual Task GetAsync(string name)
+ public async virtual Task GetAsync([NotNull] string name)
{
- var notification = await GetOrNullAsync(name);
- if (notification == null)
- {
- throw new AbpException("Undefined notification: " + name);
- }
-
- return notification;
- }
-
- public async virtual Task GetOrNullAsync(string name)
- {
- Check.NotNull(name, nameof(name));
-
- var staticDefinition = await _staticStore.GetOrNullAsync(name);
- var dynamicDefinition = await _dynamicStore.GetOrNullAsync(name);
-
- if (staticDefinition != null && dynamicDefinition != null)
- {
- return _notificationsOptions.DynamicNotificationStrategy switch
- {
- DynamicNotificationStrategy.Ignore => staticDefinition,
- DynamicNotificationStrategy.Covering => dynamicDefinition,
- DynamicNotificationStrategy.Merge => MergeNotification(staticDefinition, dynamicDefinition),
- _ => staticDefinition
- };
- }
-
- return staticDefinition ?? dynamicDefinition;
- }
-
- public async virtual Task> GetNotificationsAsync()
- {
- var staticNotifications = await _staticStore.GetNotificationsAsync();
- var dynamicNotifications = await _dynamicStore.GetNotificationsAsync();
-
- // 根据策略处理通知定义
- return _notificationsOptions.DynamicNotificationStrategy switch
- {
- DynamicNotificationStrategy.Ignore => await GetNotificationsWithIgnoreStrategy(staticNotifications, dynamicNotifications),
- DynamicNotificationStrategy.Covering => await GetNotificationsWithCoveringStrategy(staticNotifications, dynamicNotifications),
- DynamicNotificationStrategy.Merge => await GetNotificationsWithMergeStrategy(staticNotifications, dynamicNotifications),
- _ => await GetNotificationsWithIgnoreStrategy(staticNotifications, dynamicNotifications)
- };
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined notification: " + name);
}
public async virtual Task GetGroupOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
- var staticDefinition = await _staticStore.GetGroupOrNullAsync(name);
- var dynamicDefinition = await _dynamicStore.GetGroupOrNullAsync(name);
-
- if (staticDefinition != null && dynamicDefinition != null)
- {
- switch (_notificationsOptions.DynamicNotificationStrategy)
- {
- case DynamicNotificationStrategy.Ignore:
- return staticDefinition;
- case DynamicNotificationStrategy.Covering:
- return dynamicDefinition;
- case DynamicNotificationStrategy.Merge:
- MergeGroupNotifications(staticDefinition, dynamicDefinition);
- return staticDefinition;
- default:
- return staticDefinition;
- }
- }
+ var staticGroupDefinition = await StaticStore.GetGroupOrNullAsync(name);
+ var dynamicGroupDefinition = await DynamicStore.GetGroupOrNullAsync(name);
- return staticDefinition ?? dynamicDefinition;
+ return await GetGroupDefinitionAsync(staticGroupDefinition, dynamicGroupDefinition);
}
public async virtual Task> GetGroupsAsync()
{
- var staticGroups = await _staticStore.GetGroupsAsync();
- var dynamicGroups = await _dynamicStore.GetGroupsAsync();
+ var staticGroupDefinitions = await StaticStore.GetGroupsAsync();
+ var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync();
- // 根据策略处理分组定义
- return _notificationsOptions.DynamicNotificationStrategy switch
- {
- DynamicNotificationStrategy.Ignore => await GetGroupsWithIgnoreStrategy(staticGroups, dynamicGroups),
- DynamicNotificationStrategy.Covering => await GetGroupsWithCoveringStrategy(staticGroups, dynamicGroups),
- DynamicNotificationStrategy.Merge => await GetGroupsWithMergeStrategy(staticGroups, dynamicGroups),
- _ => await GetGroupsWithIgnoreStrategy(staticGroups, dynamicGroups)
- };
+ return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions);
}
- #region 通知定义策略
-
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态通知
- ///
- protected virtual Task> GetNotificationsWithIgnoreStrategy(
- IReadOnlyList staticNotifications,
- IReadOnlyList dynamicNotifications)
+ public async virtual Task> GetNotificationsAsync()
{
- var staticNotificationNames = staticNotifications
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- return Task.FromResult>(
- staticNotifications
- .Concat(dynamicNotifications.Where(d => !staticNotificationNames.Contains(d.Name)))
- .ToImmutableList()
- );
+ var staticDefinitions = await StaticStore.GetNotificationsAsync();
+ var dynamicDefinitions = await DynamicStore.GetNotificationsAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
}
- ///
- /// 覆盖策略:动态完全覆盖静态通知
- ///
- protected virtual Task> GetNotificationsWithCoveringStrategy(
- IReadOnlyList staticNotifications,
- IReadOnlyList dynamicNotifications)
+ public async virtual Task GetOrNullAsync(string name)
{
- var dynamicNotificationNames = dynamicNotifications
- .Select(p => p.Name)
- .ToImmutableHashSet();
+ Check.NotNull(name, nameof(name));
- // 动态通知完全覆盖静态通知
- var result = dynamicNotifications
- .Concat(staticNotifications.Where(s => !dynamicNotificationNames.Contains(s.Name)))
- .ToImmutableList();
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
- return Task.FromResult>(result);
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
}
- ///
- /// 合并策略:合并静态和动态通知,创建新实例
- ///
- protected virtual Task> GetNotificationsWithMergeStrategy(
- IReadOnlyList staticNotifications,
- IReadOnlyList dynamicNotifications)
+ protected override string GetDefinitionKey(NotificationDefinition definition)
{
- var mergedNotifications = new Dictionary();
-
- // 先添加所有静态通知
- foreach (var staticNotification in staticNotifications)
- {
- mergedNotifications[staticNotification.Name] = staticNotification;
- }
-
- // 合并动态通知
- foreach (var dynamicNotification in dynamicNotifications)
- {
- if (mergedNotifications.TryGetValue(dynamicNotification.Name, out var existingNotification))
- {
- // 通知已存在,创建新的合并通知
- var mergedNotification = MergeNotification(existingNotification, dynamicNotification);
- mergedNotifications[dynamicNotification.Name] = mergedNotification;
- }
- else
- {
- // 添加新的动态通知
- mergedNotifications[dynamicNotification.Name] = dynamicNotification;
- }
- }
-
- return Task.FromResult>(mergedNotifications.Values.ToImmutableList());
+ return definition.Name;
}
- ///
- /// 合并两个通知定义,返回新的 NotificationDefinition 实例
- ///
- protected virtual NotificationDefinition MergeNotification(
- NotificationDefinition staticNotification,
- NotificationDefinition dynamicNotification)
+ protected override Task MergeDefinitionAsync(NotificationDefinition targetDefinition, NotificationDefinition sourceDefinition)
{
- // 决定使用哪个显示名称(优先使用动态的)
- var displayName = dynamicNotification.DisplayName ?? staticNotification.DisplayName;
-
- // 决定使用哪个描述(优先使用动态的)
- var description = dynamicNotification.Description ?? staticNotification.Description;
-
- // 决定通知类型(优先使用动态的)
- var notificationType = dynamicNotification.NotificationType != NotificationType.Application
- ? dynamicNotification.NotificationType
- : staticNotification.NotificationType;
-
- // 决定存活类型(优先使用动态的)
- var lifetime = dynamicNotification.NotificationLifetime != NotificationLifetime.Persistent
- ? dynamicNotification.NotificationLifetime
- : staticNotification.NotificationLifetime;
-
- // 决定内容类型(优先使用动态的)
- var contentType = dynamicNotification.ContentType != NotificationContentType.Text
- ? dynamicNotification.ContentType
- : staticNotification.ContentType;
+ var displayName = sourceDefinition.DisplayName ?? targetDefinition.DisplayName;
+ var description = sourceDefinition.Description ?? targetDefinition.Description;
+ var notificationType = sourceDefinition.NotificationType != NotificationType.Application
+ ? sourceDefinition.NotificationType
+ : targetDefinition.NotificationType;
+ var lifetime = sourceDefinition.NotificationLifetime != NotificationLifetime.Persistent
+ ? sourceDefinition.NotificationLifetime
+ : targetDefinition.NotificationLifetime;
+ var contentType = sourceDefinition.ContentType != NotificationContentType.Text
+ ? sourceDefinition.ContentType
+ : targetDefinition.ContentType;
+ var allowSubscriptionToClients = sourceDefinition.AllowSubscriptionToClients || targetDefinition.AllowSubscriptionToClients;
- // 决定是否允许客户端订阅(优先使用动态的)
- var allowSubscriptionToClients = dynamicNotification.AllowSubscriptionToClients || staticNotification.AllowSubscriptionToClients;
-
- // 创建新的通知实例
var mergedNotification = new NotificationDefinition(
- staticNotification.Name, // 保持名称不变
+ targetDefinition.Name,
displayName,
description,
notificationType,
@@ -227,20 +96,17 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
allowSubscriptionToClients
);
- // 复制静态通知的属性
- foreach (var property in staticNotification.Properties)
+ foreach (var property in targetDefinition.Properties)
{
mergedNotification.Properties[property.Key] = property.Value;
}
- // 复制动态通知的属性(覆盖同名的静态属性)
- foreach (var property in dynamicNotification.Properties)
+ foreach (var property in sourceDefinition.Properties)
{
mergedNotification.Properties[property.Key] = property.Value;
}
- // 合并提供者
- foreach (var provider in staticNotification.Providers)
+ foreach (var provider in targetDefinition.Providers)
{
if (!mergedNotification.Providers.Contains(provider))
{
@@ -248,7 +114,7 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
}
}
- foreach (var provider in dynamicNotification.Providers)
+ foreach (var provider in sourceDefinition.Providers)
{
if (!mergedNotification.Providers.Contains(provider))
{
@@ -256,107 +122,32 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
}
}
- // 合并模板(优先使用动态的)
- if (dynamicNotification.Template != null)
+ if (sourceDefinition.Template != null)
{
- mergedNotification.WithTemplate(dynamicNotification.Template);
+ mergedNotification.WithTemplate(sourceDefinition.Template);
}
- else if (staticNotification.Template != null)
+ else if (targetDefinition.Template != null)
{
- mergedNotification.WithTemplate(staticNotification.Template);
+ mergedNotification.WithTemplate(targetDefinition.Template);
}
- return mergedNotification;
+ return Task.FromResult(mergedNotification);
}
- #endregion
-
- #region 分组定义策略
-
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态分组
- ///
- protected virtual Task> GetGroupsWithIgnoreStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
+ protected override string GetGroupDefinitionKey(NotificationGroupDefinition groupDefinition)
{
- var staticGroupNames = staticGroups
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- return Task.FromResult>(
- staticGroups
- .Concat(dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)))
- .ToImmutableList()
- );
- }
-
- ///
- /// 覆盖策略:动态完全覆盖静态分组
- ///
- protected virtual Task> GetGroupsWithCoveringStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
- {
- var dynamicGroupNames = dynamicGroups
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- var result = dynamicGroups
- .Concat(staticGroups.Where(s => !dynamicGroupNames.Contains(s.Name)))
- .ToImmutableList();
-
- return Task.FromResult>(result);
+ return groupDefinition.Name;
}
- ///
- /// 合并策略:合并静态和动态分组
- ///
- protected virtual Task> GetGroupsWithMergeStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
+ protected override Task MergeGroupDefinitionAsync(NotificationGroupDefinition targetGroupDefinition, NotificationGroupDefinition sourceGroupDefinition)
{
- var mergedGroups = new Dictionary();
-
- // 先添加所有静态分组
- foreach (var staticGroup in staticGroups)
- {
- mergedGroups[staticGroup.Name] = staticGroup;
- }
-
- // 合并动态分组
- foreach (var dynamicGroup in dynamicGroups)
- {
- if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup))
- {
- // 分组已存在,合并通知
- MergeGroupNotifications(existingGroup, dynamicGroup);
- }
- else
- {
- // 添加新的动态分组
- mergedGroups[dynamicGroup.Name] = dynamicGroup;
- }
- }
-
- return Task.FromResult>(
- mergedGroups.Values.ToImmutableList()
- );
- }
-
- ///
- /// 合并分组的通知列表
- ///
- private static void MergeGroupNotifications(NotificationGroupDefinition target, NotificationGroupDefinition source)
- {
- foreach (var sourceNotification in source.Notifications)
+ foreach (var sourceNotification in sourceGroupDefinition.Notifications)
{
- var existingNotification = target.GetNotificationOrNull(sourceNotification.Name);
+ var existingNotification = targetGroupDefinition.GetNotificationOrNull(sourceNotification.Name);
if (existingNotification == null)
{
- // 通知不存在,直接添加
- var newNotification = target.AddNotification(
+ var newNotification = targetGroupDefinition.AddNotification(
sourceNotification.Name,
sourceNotification.DisplayName,
sourceNotification.Description,
@@ -366,7 +157,6 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
sourceNotification.AllowSubscriptionToClients
);
- // 复制提供者
foreach (var provider in sourceNotification.Providers)
{
if (!newNotification.Providers.Contains(provider))
@@ -375,13 +165,11 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
}
}
- // 复制属性
foreach (var property in sourceNotification.Properties)
{
newNotification.Properties[property.Key] = property.Value;
}
- // 复制模板
if (sourceNotification.Template != null)
{
newNotification.WithTemplate(sourceNotification.Template);
@@ -389,13 +177,11 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
}
else
{
- // 通知已存在,合并属性
foreach (var property in sourceNotification.Properties)
{
existingNotification.Properties[property.Key] = property.Value;
}
- // 合并提供者
foreach (var provider in sourceNotification.Providers)
{
if (!existingNotification.Providers.Contains(provider))
@@ -404,30 +190,26 @@ public class NotificationDefinitionManager : INotificationDefinitionManager, ITr
}
}
- // 更新显示名称(如果源提供了)
if (sourceNotification.DisplayName != null)
{
existingNotification.DisplayName = sourceNotification.DisplayName;
}
- // 更新描述(如果源提供了)
if (sourceNotification.Description != null)
{
existingNotification.Description = sourceNotification.Description;
}
- // 更新模板(优先使用动态的)
if (sourceNotification.Template != null)
{
existingNotification.WithTemplate(sourceNotification.Template);
}
- // 更新允许客户端订阅
existingNotification.AllowSubscriptionToClients =
existingNotification.AllowSubscriptionToClients || sourceNotification.AllowSubscriptionToClients;
}
}
- }
- #endregion
-}
\ No newline at end of file
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN.Abp.Webhooks.Core.csproj b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN.Abp.Webhooks.Core.csproj
index e84bed9d0..35748da90 100644
--- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN.Abp.Webhooks.Core.csproj
+++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN.Abp.Webhooks.Core.csproj
@@ -17,4 +17,8 @@
+
+
+
+
diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksCoreModule.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksCoreModule.cs
index 75854f5a8..925829424 100644
--- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksCoreModule.cs
+++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksCoreModule.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.DependencyInjection;
+using LINGYUN.Abp.Dynamic.Definitions;
+using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using Volo.Abp.Features;
@@ -6,7 +7,9 @@ using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Webhooks;
-[DependsOn(typeof(AbpFeaturesModule))]
+[DependsOn(
+ typeof(AbpDynamicDefinitionsCoreModule),
+ typeof(AbpFeaturesModule))]
public class AbpWebhooksCoreModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
@@ -14,6 +17,15 @@ public class AbpWebhooksCoreModule : AbpModule
AutoAddDefinitionProviders(context.Services);
}
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ });
+ }
+
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List();
diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs
index 15435e52c..421e24331 100644
--- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs
+++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/AbpWebhooksOptions.cs
@@ -12,10 +12,6 @@ public class AbpWebhooksOptions
///
public TimeSpan TimeoutDuration { get; set; }
///
- /// 动态Webhook策略
- ///
- public DynamicWebhookStrategy DynamicWebhookStrategy { get; set; }
- ///
/// 默认最大发送次数
///
public int MaxSendAttemptCount { get; set; }
@@ -43,7 +39,6 @@ public class AbpWebhooksOptions
public string DefaultAgentIdentifier { get; set; }
public AbpWebhooksOptions()
{
- DynamicWebhookStrategy = DynamicWebhookStrategy.Merge;
TimeoutDuration = TimeSpan.FromSeconds(60);
MaxSendAttemptCount = 5;
MaxConsecutiveFailCountBeforeDeactivateSubscription = MaxSendAttemptCount * 3;
diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/DynamicWebhookStrategy.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/DynamicWebhookStrategy.cs
deleted file mode 100644
index 4e505be32..000000000
--- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/DynamicWebhookStrategy.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace LINGYUN.Abp.Webhooks;
-///
-/// 动态Webhook策略
-///
-public enum DynamicWebhookStrategy : byte
-{
- ///
- /// 忽略
- ///
- Ignore = 0,
- ///
- /// 覆盖
- ///
- Covering =1,
- ///
- /// 合并
- ///
- Merge = 2
-}
diff --git a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs
index ac6c4ab3f..14facda43 100644
--- a/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs
+++ b/aspnet-core/modules/webhooks/LINGYUN.Abp.Webhooks.Core/LINGYUN/Abp/Webhooks/WebhookDefinitionManager.cs
@@ -1,8 +1,8 @@
-using Microsoft.Extensions.DependencyInjection;
+using LINGYUN.Abp.Dynamic.Definitions;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
@@ -12,127 +12,76 @@ using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Webhooks;
-internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonDependency
+public class WebhookDefinitionManager :
+ DynamicDefinitionManager,
+ IWebhookDefinitionManager,
+ ITransientDependency
{
- private readonly AbpWebhooksOptions _webhooksOptions;
- private readonly IServiceProvider _serviceProvider;
- private readonly IStaticWebhookDefinitionStore _staticStore;
- private readonly IDynamicWebhookDefinitionStore _dynamicStore;
+ protected IServiceProvider ServiceProvider { get; }
+ protected IStaticWebhookDefinitionStore StaticStore { get; }
+ protected IDynamicWebhookDefinitionStore DynamicStore { get; }
public WebhookDefinitionManager(
IServiceProvider serviceProvider,
- IStaticWebhookDefinitionStore staticStore,
- IDynamicWebhookDefinitionStore dynamicStore,
- IOptions webhooksOptions)
+ IStaticWebhookDefinitionStore staticStore,
+ IDynamicWebhookDefinitionStore dynamicStore,
+ IOptions options)
+ : base(options)
{
- _serviceProvider = serviceProvider;
- _staticStore = staticStore;
- _dynamicStore = dynamicStore;
- _webhooksOptions = webhooksOptions.Value;
- }
-
- public async virtual Task GetOrNullAsync(string name)
- {
- Check.NotNull(name, nameof(name));
-
- var staticDefinition = await _staticStore.GetOrNullAsync(name);
- var dynamicDefinition = await _dynamicStore.GetOrNullAsync(name);
-
- if (staticDefinition != null && dynamicDefinition != null)
- {
- return _webhooksOptions.DynamicWebhookStrategy switch
- {
- DynamicWebhookStrategy.Ignore => staticDefinition,
- DynamicWebhookStrategy.Covering => dynamicDefinition,
- DynamicWebhookStrategy.Merge => MergeWebhook(staticDefinition, dynamicDefinition),
- _ => staticDefinition
- };
- }
-
- return staticDefinition ?? dynamicDefinition;
+ ServiceProvider = serviceProvider;
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
}
public async virtual Task GetAsync(string name)
{
- var webhook = await GetOrNullAsync(name);
- if (webhook == null)
- {
- throw new AbpException("Undefined webhook: " + name);
- }
-
- return webhook;
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined webhook: " + name);
}
- public async virtual Task> GetWebhooksAsync()
+ public async virtual Task GetGroupAsync(string name)
{
- var staticWebhooks = await _staticStore.GetWebhooksAsync();
- var dynamicWebhooks = await _dynamicStore.GetWebhooksAsync();
-
- // 根据策略处理Webhook定义
- return _webhooksOptions.DynamicWebhookStrategy switch
- {
- DynamicWebhookStrategy.Ignore => await GetWebhooksWithIgnoreStrategy(staticWebhooks, dynamicWebhooks),
- DynamicWebhookStrategy.Covering => await GetWebhooksWithCoveringStrategy(staticWebhooks, dynamicWebhooks),
- DynamicWebhookStrategy.Merge => await GetWebhooksWithMergeStrategy(staticWebhooks, dynamicWebhooks),
- _ => await GetWebhooksWithIgnoreStrategy(staticWebhooks, dynamicWebhooks)
- };
+ return await GetGroupOrNullAsync(name) ?? throw new AbpException("Undefined webhook group: " + name);
}
public async virtual Task GetGroupOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
- var staticDefinition = await _staticStore.GetGroupOrNullAsync(name);
- var dynamicDefinition = await _dynamicStore.GetGroupOrNullAsync(name);
+ var staticGroupDefinition = await StaticStore.GetGroupOrNullAsync(name);
+ var dynamicGroupDefinition = await DynamicStore.GetGroupOrNullAsync(name);
- if (staticDefinition != null && dynamicDefinition != null)
- {
- switch (_webhooksOptions.DynamicWebhookStrategy)
- {
- case DynamicWebhookStrategy.Ignore:
- return staticDefinition;
- case DynamicWebhookStrategy.Covering:
- return dynamicDefinition;
- case DynamicWebhookStrategy.Merge:
- MergeGroupWebhooks(staticDefinition, dynamicDefinition);
- return staticDefinition;
- default:
- return staticDefinition;
- }
- }
+ return await GetGroupDefinitionAsync(staticGroupDefinition, dynamicGroupDefinition);
+ }
+
+ public async virtual Task> GetGroupsAsync()
+ {
+ var staticGroupDefinitions = await StaticStore.GetGroupsAsync();
+ var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync();
- return staticDefinition ?? dynamicDefinition;
+ return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions);
}
- public async virtual Task GetGroupAsync(string name)
+ public async virtual Task GetOrNullAsync(string name)
{
- var webhookGroup = await GetGroupOrNullAsync(name);
- if (webhookGroup == null)
- {
- throw new AbpException("Undefined webhook group: " + name);
- }
+ Check.NotNull(name, nameof(name));
- return webhookGroup;
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
}
- public async virtual Task> GetGroupsAsync()
+ public async virtual Task> GetWebhooksAsync()
{
- var staticGroups = await _staticStore.GetGroupsAsync();
- var dynamicGroups = await _dynamicStore.GetGroupsAsync();
+ var staticDefinitions = await StaticStore.GetWebhooksAsync();
+ var dynamicDefinitions = await DynamicStore.GetWebhooksAsync();
- // 根据策略处理分组定义
- return _webhooksOptions.DynamicWebhookStrategy switch
- {
- DynamicWebhookStrategy.Ignore => await GetGroupsWithIgnoreStrategy(staticGroups, dynamicGroups),
- DynamicWebhookStrategy.Covering => await GetGroupsWithCoveringStrategy(staticGroups, dynamicGroups),
- DynamicWebhookStrategy.Merge => await GetGroupsWithMergeStrategy(staticGroups, dynamicGroups),
- _ => await GetGroupsWithIgnoreStrategy(staticGroups, dynamicGroups)
- };
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
}
- public async Task IsAvailableAsync(Guid? tenantId, string name)
+ public async virtual Task IsAvailableAsync(Guid? tenantId, string name)
{
- if (tenantId == null) // host allowed to subscribe all webhooks
+ if (tenantId == null)
{
return true;
}
@@ -149,8 +98,8 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
return true;
}
- var currentTenant = _serviceProvider.GetRequiredService();
- var featureChecker = _serviceProvider.GetRequiredService();
+ var currentTenant = ServiceProvider.GetRequiredService();
+ var featureChecker = ServiceProvider.GetRequiredService();
using (currentTenant.Change(tenantId))
{
if (!await featureChecker.IsEnabledAsync(true, webhookDefinition.RequiredFeatures.ToArray()))
@@ -162,111 +111,34 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
return true;
}
- #region Webhook定义策略
-
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态Webhook
- ///
- protected virtual Task> GetWebhooksWithIgnoreStrategy(
- IReadOnlyList staticWebhooks,
- IReadOnlyList dynamicWebhooks)
+ protected override string GetDefinitionKey(WebhookDefinition definition)
{
- var staticWebhookNames = staticWebhooks
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- return Task.FromResult>(
- staticWebhooks
- .Concat(dynamicWebhooks.Where(d => !staticWebhookNames.Contains(d.Name)))
- .ToImmutableList()
- );
+ return definition.Name;
}
- ///
- /// 覆盖策略:动态完全覆盖静态Webhook
- ///
- protected virtual Task> GetWebhooksWithCoveringStrategy(
- IReadOnlyList staticWebhooks,
- IReadOnlyList dynamicWebhooks)
+ protected override string GetGroupDefinitionKey(WebhookGroupDefinition groupDefinition)
{
- var dynamicWebhookNames = dynamicWebhooks
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- // 动态Webhook完全覆盖静态Webhook
- var result = dynamicWebhooks
- .Concat(staticWebhooks.Where(s => !dynamicWebhookNames.Contains(s.Name)))
- .ToImmutableList();
-
- return Task.FromResult>(result);
+ return groupDefinition.Name;
}
- ///
- /// 合并策略:合并静态和动态Webhook,创建新实例
- ///
- protected virtual Task> GetWebhooksWithMergeStrategy(
- IReadOnlyList staticWebhooks,
- IReadOnlyList dynamicWebhooks)
+ protected override Task MergeDefinitionAsync(WebhookDefinition targetDefinition, WebhookDefinition sourceDefinition)
{
- var mergedWebhooks = new Dictionary();
+ var displayName = sourceDefinition.DisplayName ?? targetDefinition.DisplayName;
+ var description = sourceDefinition.Description ?? targetDefinition.Description;
- // 先添加所有静态Webhook
- foreach (var staticWebhook in staticWebhooks)
- {
- mergedWebhooks[staticWebhook.Name] = staticWebhook;
- }
-
- // 合并动态Webhook
- foreach (var dynamicWebhook in dynamicWebhooks)
- {
- if (mergedWebhooks.TryGetValue(dynamicWebhook.Name, out var existingWebhook))
- {
- // Webhook已存在,创建新的合并Webhook
- var mergedWebhook = MergeWebhook(existingWebhook, dynamicWebhook);
- mergedWebhooks[dynamicWebhook.Name] = mergedWebhook;
- }
- else
- {
- // 添加新的动态Webhook
- mergedWebhooks[dynamicWebhook.Name] = dynamicWebhook;
- }
- }
-
- return Task.FromResult>(mergedWebhooks.Values.ToImmutableList());
- }
-
- ///
- /// 合并两个Webhook定义,返回新的 WebhookDefinition 实例
- ///
- protected virtual WebhookDefinition MergeWebhook(
- WebhookDefinition staticWebhook,
- WebhookDefinition dynamicWebhook)
- {
- // 决定使用哪个显示名称(优先使用动态的)
- var displayName = dynamicWebhook.DisplayName ?? staticWebhook.DisplayName;
-
- // 决定使用哪个描述(优先使用动态的)
- var description = dynamicWebhook.Description ?? staticWebhook.Description;
-
- // 创建新的Webhook实例(WebhookDefinition的Name是只读的)
var mergedWebhook = new WebhookDefinition(
- staticWebhook.Name, // 保持名称不变
+ targetDefinition.Name,
displayName,
description
- );
-
- // 设置分组名称(优先使用动态的)
- if (!string.IsNullOrEmpty(dynamicWebhook.GroupName))
- {
- mergedWebhook.GroupName = dynamicWebhook.GroupName;
- }
- else if (!string.IsNullOrEmpty(staticWebhook.GroupName))
+ )
{
- mergedWebhook.GroupName = staticWebhook.GroupName;
- }
+ GroupName =
+ !string.IsNullOrWhiteSpace(sourceDefinition.GroupName)
+ ? sourceDefinition.GroupName
+ : targetDefinition.GroupName
+ };
- // 合并必需的功能特性
- foreach (var feature in staticWebhook.RequiredFeatures)
+ foreach (var feature in targetDefinition.RequiredFeatures)
{
if (!mergedWebhook.RequiredFeatures.Contains(feature))
{
@@ -274,125 +146,42 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
}
}
- foreach (var feature in dynamicWebhook.RequiredFeatures)
+ foreach (var feature in sourceDefinition.RequiredFeatures)
{
if (!mergedWebhook.RequiredFeatures.Contains(feature))
{
mergedWebhook.RequiredFeatures.Add(feature);
}
}
-
- // 合并属性(动态覆盖静态)
- foreach (var property in staticWebhook.Properties)
+
+ foreach (var property in targetDefinition.Properties)
{
mergedWebhook.Properties[property.Key] = property.Value;
}
- foreach (var property in dynamicWebhook.Properties)
+ foreach (var property in sourceDefinition.Properties)
{
mergedWebhook.Properties[property.Key] = property.Value;
}
- return mergedWebhook;
- }
-
- #endregion
-
- #region 分组定义策略
-
- ///
- /// 忽略策略:静态优先,过滤掉同名的动态分组
- ///
- protected virtual Task> GetGroupsWithIgnoreStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
- {
- var staticGroupNames = staticGroups
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- return Task.FromResult>(
- staticGroups
- .Concat(dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)))
- .ToImmutableList()
- );
- }
-
- ///
- /// 覆盖策略:动态完全覆盖静态分组
- ///
- protected virtual Task> GetGroupsWithCoveringStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
- {
- var dynamicGroupNames = dynamicGroups
- .Select(p => p.Name)
- .ToImmutableHashSet();
-
- var result = dynamicGroups
- .Concat(staticGroups.Where(s => !dynamicGroupNames.Contains(s.Name)))
- .ToImmutableList();
-
- return Task.FromResult>(result);
- }
-
- ///
- /// 合并策略:合并静态和动态分组
- ///
- protected virtual Task> GetGroupsWithMergeStrategy(
- IReadOnlyList staticGroups,
- IReadOnlyList dynamicGroups)
- {
- var mergedGroups = new Dictionary();
-
- // 先添加所有静态分组
- foreach (var staticGroup in staticGroups)
- {
- mergedGroups[staticGroup.Name] = staticGroup;
- }
-
- // 合并动态分组
- foreach (var dynamicGroup in dynamicGroups)
- {
- if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup))
- {
- // 分组已存在,合并Webhook
- MergeGroupWebhooks(existingGroup, dynamicGroup);
- }
- else
- {
- // 添加新的动态分组
- mergedGroups[dynamicGroup.Name] = dynamicGroup;
- }
- }
-
- return Task.FromResult>(
- mergedGroups.Values.ToImmutableList()
- );
+ return Task.FromResult(mergedWebhook);
}
- ///
- /// 合并分组的Webhook列表
- ///
- private void MergeGroupWebhooks(WebhookGroupDefinition target, WebhookGroupDefinition source)
+ protected override Task MergeGroupDefinitionAsync(WebhookGroupDefinition targetGroupDefinition, WebhookGroupDefinition sourceGroupDefinition)
{
- foreach (var sourceWebhook in source.Webhooks)
+ foreach (var sourceWebhook in sourceGroupDefinition.Webhooks)
{
- var existingWebhook = target.GetWebhookOrNull(sourceWebhook.Name);
+ var existingWebhook = targetGroupDefinition.GetWebhookOrNull(sourceWebhook.Name);
if (existingWebhook == null)
{
- // Webhook不存在,直接添加
- var newWebhook = target.AddWebhook(
+ var newWebhook = targetGroupDefinition.AddWebhook(
sourceWebhook.Name,
sourceWebhook.DisplayName,
sourceWebhook.Description
);
+ newWebhook.GroupName = targetGroupDefinition.Name;
- // 设置分组名称
- newWebhook.GroupName = target.Name;
-
- // 复制必需的功能特性
foreach (var feature in sourceWebhook.RequiredFeatures)
{
if (!newWebhook.RequiredFeatures.Contains(feature))
@@ -401,7 +190,6 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
}
}
- // 复制属性
foreach (var property in sourceWebhook.Properties)
{
newWebhook.Properties[property.Key] = property.Value;
@@ -409,13 +197,11 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
}
else
{
- // Webhook已存在,合并属性
foreach (var property in sourceWebhook.Properties)
{
existingWebhook.Properties[property.Key] = property.Value;
}
- // 合并必需的功能特性
foreach (var feature in sourceWebhook.RequiredFeatures)
{
if (!existingWebhook.RequiredFeatures.Contains(feature))
@@ -424,23 +210,19 @@ internal class WebhookDefinitionManager : IWebhookDefinitionManager, ISingletonD
}
}
- // 更新显示名称(如果源提供了)
if (sourceWebhook.DisplayName != null)
{
existingWebhook.DisplayName = sourceWebhook.DisplayName;
}
- // 更新描述(如果源提供了)
if (sourceWebhook.Description != null)
{
existingWebhook.Description = sourceWebhook.Description;
}
- // 更新分组名称(确保保持一致)
- existingWebhook.GroupName = target.Name;
+ existingWebhook.GroupName = targetGroupDefinition.Name;
}
}
+ return Task.CompletedTask;
}
-
- #endregion
-}
\ No newline at end of file
+}