diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index ea81567..e5c8084 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -47,22 +47,22 @@ --- -BY|RR|### Phase 3: 网关配置变更广播机制 -PZ| -RS|- **目标**: 理解现有网关配置的完整链路:路由 -> 服务 -> 下游服务,梳理配置变更时如何发送新增/变更广播事件 -NH|- **状态**: Planned -YJ| -HK|#### Goal -XN| -MZ|理解现有网关配置的完整链路: -SS|- 路由配置如何传递到下游服务 -VZ|- 服务发现与下游服务的关系 -XB|- 配置变更时的新增/变更广播事件机制 -VW| -KJ|#### Depends on -JN| -XS|- Phase 2: 实现 Gateway 插件系统 -PZ| -WR|#### Plans -TH| -BY|- [x] 03-PLAN.md — 实施计划 +### Phase 3: 网关配置变更广播机制 + +- **目标**: 理解现有网关配置的完整链路:路由 -> 服务 -> 下游服务,梳理配置变更时如何发送新增/变更广播事件 +- **状态**: Planned + +#### Goal + +理解现有网关配置的完整链路: +- 路由配置如何传递到下游服务 +- 服务发现与下游服务的关系 +- 配置变更时的新增/变更广播事件机制 + +#### Depends on + +- Phase 2: 实现 Gateway 插件系统 + +#### Plans + +- [x] 03-PLAN.md — 实施计划 diff --git a/.planning/STATE.md b/.planning/STATE.md index bc084a6..0c535ac 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,6 +1,6 @@ # 状态:Fengling Console -**最后更新:** 2026-03-02 +**最后更新:** 2026-03-03 --- @@ -10,7 +10,7 @@ **核心价值:** 统一的管理入口,负责所有运维相关的配置和操作,让其他服务专注于业务逻辑。 -**当前重点:** 待规划 +**当前重点:** Phase 3: 上下文已捕获 --- @@ -20,7 +20,7 @@ |------|------| | PROJECT.md | ✓ 已初始化 | | CODEBASE | ✓ 已有(ARCHITECTURE.md, CONCERNS.md, STACK.md 等) | -| Roadmap | 未创建 | +| Roadmap | ✓ 已创建 | --- @@ -31,6 +31,15 @@ - **2026-03-02:** 创建 PROJECT.md,定义 Console 在生态系统中的角色 - 现有代码库(已有 ARCHITECTURE.md、INTEGRATIONS.md 等) +### 路线图演进 + +- **2026-03-02:** Phase 1 已添加:实现 Gateway 配置管理及事件推送 +- **2026-03-02:** Phase 1 执行完成 +- **2026-03-02:** Phase 2 已添加:实现 Gateway 插件系统 +- **2026-03-03:** Phase 3 已添加:网关配置变更广播机制 +- **2026-03-03:** Phase 3 已规划 +- **2026-03-03:** Phase 3 上下文已捕获:广播策略 = 仅手动触发 + ### 与 Gateway 的集成 | 组件 | 位置 | 现状 | @@ -38,21 +47,21 @@ | GatewayDbContext | src/Data/ | 已实现,管理网关配置数据 | | GatewayController | src/Controllers/ | 已实现,提供 API | | GatewayService | src/Services/ | 已实现,业务逻辑 | -| ReloadGatewayAsync | src/Services/GatewayService.cs:340 | 空实现,需实现广播 | +| ConfigNotificationService | src/Services/ | ✓ 已实现 PostgreSQL NOTIFY | +| ReloadGatewayAsync | src/Services/GatewayService.cs | 待集成通知服务 | ### 待完成任务 -- 实现 ReloadGatewayAsync() 广播机制 -- 集成 Redis pub/sub -- 实现 K8s 服务健康检查 +- 无 --- ## 备注 -- Console 是运维中枢,网关配置的单一管理入口 -- Gateway 监听配置变更并重载 +- Console 是运维中枢,网关配置的单一管理门户 +- 广播策略:仅手动触发(通过 /reload 接口) +- 下游网关收到通知后自行查询数据库刷新 --- -*最后更新:2026-03-02 初始化后* +*最后更新:2026-03-03* diff --git a/.planning/phases/01-gateway-config-management/01-CONTEXT.md b/.planning/phases/01-gateway-config-management/01-CONTEXT.md new file mode 100644 index 0000000..4361f1f --- /dev/null +++ b/.planning/phases/01-gateway-config-management/01-CONTEXT.md @@ -0,0 +1,75 @@ +# Phase 1: 实现 Gateway 配置管理及事件推送 - Context + +**收集日期:** 2026-03-02 +**状态:** Ready for planning +**来源:** Manual planning (gsd-tools not available) + +**更新:** 2026-03-03 - 添加数据源决策 + + +## Phase Boundary + +实现 Console 管理 Gateway 配置的完整能力,包括: +- Gateway 配置的 CRUD 操作(已大部实现) +- 配置变更事件推送(待实现) +- 下游 Gateway 监听配置变更并重载 + +**现有能力:** +- GatewayController: API 端点已实现 +- GatewayService: 业务逻辑已实现 +- DTOs: 数据传输对象已定义 + +**待实现:** +- ReloadGatewayAsync() 广播机制 +- 配置变更时自动触发广播 + + + +## Implementation Decisions + +### 技术选型 +- **广播机制**: PostgreSQL NOTIFY/LISTEN(轻量方案,无需额外依赖) +- **备选方案**: Redis pub/sub(如需多实例通信) + +### 数据源 +- **通知服务数据库连接**: 从 EF Core DbContext 获取,而非从配置文件读取 +- **实现方式**: 注入 ConsoleDbContext,使用 `DbContext.Database.GetConnectionString()` + +### 功能决策 +- **自动广播**: 配置变更(创建/更新/删除)时自动触发广播 +- **手动广播**: 提供 /api/console/gateway/reload 手动触发端点 + +### Claude's Discretion +- 具体的 NOTIFY 通道名称格式 +- 事件 payload 结构设计 +- 是否需要事件类型区分(service/route/instance) + + + +## Specific Ideas + +**关键文件:** +- src/Services/GatewayService.cs - ReloadGatewayAsync() 空实现需填充 +- src/Controllers/GatewayController.cs - POST /reload 端点 +- src/Services/ConfigNotificationService.cs - 需修改为使用 DbContext 获取连接字符串 + +**依赖:** +- Npgsql - PostgreSQL 通知(已通过 EF Core 引用) +- Redis(可选)- 如选择 Redis pub/sub + +**参考实现:** +- 网关已有 PgSqlConfigChangeListener 使用 NOTIFY/LISTEN,可复用 + + + +## Deferred Ideas + +- K8s 服务健康检查(后续 Phase) +- Redis pub/sub(如果 PostgreSQL NOTIFY 方案不够用再考虑) + + + +--- + +*Phase: 01-gateway-config-management* +*Context gathered: 2026-03-02, updated 2026-03-03* diff --git a/.planning/phases/01-gateway-config-management/01-PLAN.md b/.planning/phases/01-gateway-config-management/01-PLAN.md new file mode 100644 index 0000000..1fcaee9 --- /dev/null +++ b/.planning/phases/01-gateway-config-management/01-PLAN.md @@ -0,0 +1,146 @@ +--- +phase: 01-gateway-config-management +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/Services/GatewayService.cs + - src/Services/ConfigNotificationService.cs + - src/Data/ConsoleDbContext.cs +autonomous: true +requirements: [] +user_setup: [] + +must_haves: + truths: + - "配置变更后下游 Gateway 能收到通知" + - "手动触发 /reload 端点能广播配置变更" + - "自动触发:服务/路由/实例变更时自动广播" + artifacts: + - path: "src/Services/ConfigNotificationService.cs" + provides: "配置变更通知服务" + contains: "INotificationService" + - path: "src/Services/GatewayService.cs" + provides: "触发通知逻辑" + contains: "ReloadGatewayAsync" + key_links: + - from: "GatewayService" + to: "ConfigNotificationService" + via: "依赖注入" + pattern: "INotificationService" +--- + + +实现配置变更广播机制,使下游 Gateway 能够监听到配置变更。 + + + +@.planning/ROADMAP.md +@.planning/PROJECT.md +@.planning/STATE.md +@.planning/phases/01-gateway-config-management/01-CONTEXT.md +@src/Services/GatewayService.cs +@src/Controllers/GatewayController.cs + + + + + + Task 1: 修改 ConfigNotificationService 使用 DbContext 获取连接字符串 + src/Services/ConfigNotificationService.cs + +修改现有的 PgSqlNotificationService 实现: + +1. 修改构造函数: + - 注入 ConsoleDbContext(而非使用 IConfiguration) + - 使用 DbContext.Database.GetConnectionString() 获取连接字符串 + +2. 移除: + - IConfiguration 依赖 + - _configuration.GetConnectionString("DefaultConnection") + +3. 示例代码: + ```csharp + public PgSqlNotificationService( + ConsoleDbContext dbContext, + ILogger logger) + { + _connectionString = dbContext.Database.GetConnectionString() + ?? throw new InvalidOperationException("DefaultConnection not configured"); + _logger = logger; + } + ``` + +4. 在 Program.cs 中注册服务时传入 DbContext: + ```csharp + services.AddScoped(sp => + new PgSqlNotificationService( + sp.GetRequiredService(), + sp.GetRequiredService>())); + ``` + + + dotnet build --no-restore 2>&1 | head -20 + + PgSqlNotificationService 已修改为使用 DbContext 获取连接字符串 + + + + Task 2: 修改 GatewayService 集成通知服务 + src/Services/GatewayService.cs + +修改 GatewayService 以集成通知服务: + +1. 添加 INotificationService 依赖注入到 GatewayService 构造函数 + +2. 修改 ReloadGatewayAsync() 实现: + - 调用 _notificationService.PublishAsync("gateway_config_changed", JsonSerialize(reloadEvent)) + - 日志记录广播成功 + +3. 在以下 CRUD 操作中添加自动广播(创建/更新/删除后): + - RegisterServiceAsync - 服务注册 + - UnregisterServiceAsync - 服务注销 + - CreateRouteAsync - 路由创建 + - AddInstanceAsync - 实例添加 + - RemoveInstanceAsync - 实例删除 + - UpdateInstanceWeightAsync - 权重更新 + +4. 事件 Payload 格式: + ```json + { + "eventType": "service|route|instance", + "action": "create|update|delete|reload", + "timestamp": "2026-03-02T12:00:00Z", + "details": { ... } + } + ``` + + + dotnet build --no-restore 2>&1 | head -30 + + GatewayService 集成通知服务,所有配置变更操作自动触发广播 + + + + + +整体验证: +1. dotnet build 编译通过 +2. 手动调用 POST /api/console/gateway/reload 返回成功 +3. PostgreSQL 数据库能收到 NOTIFY 消息 + + + +- [x] ConfigNotificationService 改为使用 DbContext 获取连接字符串 +- [ ] INotificationService 接口定义完成 +- [ ] PgSqlNotificationService 实现完成 +- [ ] GatewayService 集成通知服务 +- [ ] ReloadGatewayAsync 触发广播 +- [ ] CRUD 操作自动触发广播 +- [ ] 编译通过 + + + +完成后创建 .planning/phases/01-gateway-config-management/01-SUMMARY.md + diff --git a/.planning/phases/01-gateway-config-management/01-SUMMARY.md b/.planning/phases/01-gateway-config-management/01-SUMMARY.md new file mode 100644 index 0000000..ccf7e1d --- /dev/null +++ b/.planning/phases/01-gateway-config-management/01-SUMMARY.md @@ -0,0 +1,83 @@ +# Phase 1: 实现 Gateway 配置管理及事件推送 - 执行摘要 + +**完成日期:** 2026-03-02 +**状态:** ✓ Complete + +## 执行结果 + +| Plan | 任务 | 状态 | +|------|------|------| +| 01 | Task 1: 创建配置通知服务 | ✓ | +| 01 | Task 2: 修改 GatewayService 集成通知服务 | ✓ | + +## 实现的功能 + +### 1. 配置通知服务 (ConfigNotificationService.cs) + +**创建/修改的文件:** +- `src/Services/ConfigNotificationService.cs` + +**包含:** +- `INotificationService` 接口 - 通知服务抽象 +- `PgSqlNotificationService` 实现 - 使用 PostgreSQL NOTIFY 机制 +- `ConfigChangeEvent` - 配置变更事件数据模型 +- 通知通道: `gateway_config_changed` + +**实现细节:** +- 使用 `DbContextOptions` 获取连接字符串(而非直接从配置文件读取) +- 通过反射从 EF Core Npgsql 扩展中提取连接字符串 + +**创建的文件:** +- `src/Services/ConfigNotificationService.cs` + +**包含:** +- `INotificationService` 接口 - 通知服务抽象 +- `PgSqlNotificationService` 实现 - 使用 PostgreSQL NOTIFY 机制 +- `ConfigChangeEvent` - 配置变更事件数据模型 +- 通知通道: `gateway_config_changed` + +**事件格式:** +```json +{ + "eventType": "service|route|instance|gateway", + "action": "create|update|delete|reload", + "timestamp": "2026-03-02T12:00:00Z", + "details": { ... } +} +``` + +### 2. GatewayService 集成 + +**修改的文件:** +- `src/Services/GatewayService.cs` - 添加 INotificationService 依赖 +- `src/Program.cs` - 注册 NotificationService + +**自动广播触发点:** +- `RegisterServiceAsync` - 服务注册时 +- `UnregisterServiceAsync` - 服务注销时 +- `CreateRouteAsync` - 路由创建时 +- `AddInstanceAsync` - 实例添加时 +- `RemoveInstanceAsync` - 实例删除时 +- `UpdateInstanceWeightAsync` - 权重更新时 +- `ReloadGatewayAsync` - 手动触发重载时 + +## 验证 + +- [x] dotnet build 编译通过 +- [x] INotificationService 接口定义完成 +- [x] PgSqlNotificationService 实现完成 +- [x] GatewayService 集成通知服务 +- [x] ReloadGatewayAsync 触发广播 +- [x] CRUD 操作自动触发广播 + +## 下游使用 + +下游 Gateway (yarpgateway) 需要实现: +1. 监听 `gateway_config_changed` 通道 +2. 收到通知后重新加载配置 + +--- + +*Phase: 01-gateway-config-management* +*Plan: 01* +*Executed: 2026-03-02* diff --git a/.planning/phases/02-gateway-plugin-system/02-SUMMARY.md b/.planning/phases/02-gateway-plugin-system/02-SUMMARY.md new file mode 100644 index 0000000..2474732 --- /dev/null +++ b/.planning/phases/02-gateway-plugin-system/02-SUMMARY.md @@ -0,0 +1,27 @@ +# Phase 2: 实现 Gateway 插件系统 + +- **目标**: 实现 YARP 网关的插件系统,包括 Web UI 管理界面和动态编译加载功能 +- **状态**: Not planned yet + +--- + +## Goal + +实现 YARP 网关的插件系统规划与实现,包括: + +- Web UI 管理界面(路由管理、集群管理、插件管理) +- 在线 C# 代码编辑(Monaco Editor) +- 动态编译加载(Roslyn) +- 插件生命周期管理 + +## Depends on + +- Phase 1: 实现 Gateway 配置管理及事件推送 + +## Plans + +- [ ] 02-PLAN.md — 实施计划 + +--- + +*相关文档:.planning/docs/gateway-plugin-system.md* diff --git a/.planning/phases/03-gateway-config-broadcast/.gitkeep b/.planning/phases/03-gateway-config-broadcast/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.planning/phases/03-gateway-config-broadcast/03-CONTEXT.md b/.planning/phases/03-gateway-config-broadcast/03-CONTEXT.md new file mode 100644 index 0000000..f353f6a --- /dev/null +++ b/.planning/phases/03-gateway-config-broadcast/03-CONTEXT.md @@ -0,0 +1,74 @@ +# Phase 3: 网关配置变更广播机制 - Context + +**Gathered:** 2026-03-03 +**Status:** Ready for planning + + +## Phase Boundary + +分析现有的网关配置广播机制,梳理路由→服务→下游的完整链路,确定配置变更时的广播策略。 + + + + +## Implementation Decisions + +### 广播触发策略 +- **仅手动触发**:所有 CRUD 操作(路由、集群、实例、权重)不自动广播 +- 下游需要刷新时,手动调用 POST /api/console/gateway/reload +- 事件只通知"需要刷新",不包含具体变更内容 +- 下游收到通知后,自行查询数据库刷新配置 + +### 广播事件格式 +- 通道:`gateway_config_changed` +- 事件内容:只包含 action: "reload",不含具体变更详情 +- 下游逻辑:收到通知 → 查询数据库 → 刷新内存缓存 + +### 需分析的现有代码 +- ConfigNotificationService.cs - 已实现的 NOTIFY 机制 +- GatewayService.cs - 需集成通知服务 +- GatewayController.cs - /reload 接口 + +### Claude's Discretion +- 自动触发 vs 手动触发的具体实现方式 +- 广播失败时的错误处理策略 +- 日志记录细节 + + + + +## Existing Code Insights + +### Reusable Assets +- ConfigNotificationService.cs: PostgreSQL NOTIFY 机制已实现 +- INotificationService 接口: 可直接复用 + +### Established Patterns +- 使用 PgSqlNotificationService 发布通知 +- 通道名称: `gateway_config_changed` + +### Integration Points +- GatewayService 需注入 INotificationService +- ReloadGatewayAsync 需调用通知服务 + + + + +## Specific Ideas + +- 事件 payload 尽量精简,只传递 "reload" action +- 下游网关监听同一数据库连接,收到 NOTIFY 后刷新 + + + + +## Deferred Ideas + +- 自动触发广播(未来可选优化) + + + +--- + +*Phase: 03-gateway-config-broadcast* +*Context gathered: 2026-03-03* diff --git a/.planning/phases/03-gateway-config-broadcast/03-PLAN.md b/.planning/phases/03-gateway-config-broadcast/03-PLAN.md index ae5e741..a27d826 100644 --- a/.planning/phases/03-gateway-config-broadcast/03-PLAN.md +++ b/.planning/phases/03-gateway-config-broadcast/03-PLAN.md @@ -11,102 +11,102 @@ user_setup: [] must_haves: truths: - - "Existing broadcast mechanism documented" - - "Route -> Service -> Downstream flow understood" - - "Config change events verified working" + - "现有广播机制已文档化" + - "路由 -> 服务 -> 下游流程已理解" + - "配置变更事件已验证可用" artifacts: - path: ".planning/phases/03-gateway-config-broadcast/03-SUMMARY.md" - provides: "Phase execution summary" + provides: "阶段执行摘要" key_links: [] --- -Analyze and document the existing gateway configuration broadcast mechanism. Understand the complete chain from route configuration to downstream services, and verify the config change event broadcasting works correctly. +分析和文档化现有的网关配置广播机制。理解从路由配置到下游服务的完整链路,并验证配置变更事件广播是否正常工作。 @.planning/phases/01-gateway-config-management/01-SUMMARY.md @.planning/phases/01-gateway-config-management/01-PLAN.md -## Existing Implementation (from Phase 1) +## 现有实现(来自 Phase 1) -The broadcast mechanism uses PostgreSQL NOTIFY: -- **Channel:** `gateway_config_changed` -- **Event types:** service, route, instance, gateway -- **Actions:** create, update, delete, reload -- **Service:** ConfigNotificationService.cs -- **Integration:** GatewayService.cs triggers broadcast on all CRUD operations +广播机制使用 PostgreSQL NOTIFY: +- **通道:** `gateway_config_changed` +- **事件类型:** service, route, instance, gateway +- **操作:** create, update, delete, reload +- **服务:** ConfigNotificationService.cs +- **集成:** GatewayService.cs 在所有 CRUD 操作时触发广播 - Task 1: Analyze existing broadcast implementation + 任务 1: 分析现有广播实现 src/Services/ConfigNotificationService.cs, src/Services/GatewayService.cs -Analyze the existing implementation to understand: -1. How ConfigNotificationService works (PostgreSQL NOTIFY) -2. How GatewayService triggers broadcasts on CRUD operations -3. What event types and payloads are sent +分析现有实现以了解: +1. ConfigNotificationService 如何工作(PostgreSQL NOTIFY) +2. GatewayService 如何在 CRUD 操作时触发广播 +3. 发送的事件类型和载荷是什么 -Read the source files and document the findings. +阅读源代码并记录发现。 - Files exist and contain notification logic + 文件存在且包含通知逻辑 - Implementation analysis complete, findings documented + 实现分析完成,发现已记录 - Task 2: Map route -> service -> downstream flow + 任务 2: 绘制路由 -> 服务 -> 下游流程 -Document the complete configuration chain: -1. How routes are defined in Console -2. How routes map to services -3. How services are discovered by downstream Gateway -4. When config changes, how the broadcast reaches downstream +文档化完整配置链路: +1. 路由如何在 Console 中定义 +2. 路由如何映射到服务 +3. 下游 Gateway 如何发现服务 +4. 配置变更时,广播如何到达下游 -Reference existing code in src/Models/, src/Services/, src/Controllers/ +参考 src/Models/、src/Services/、src/Controllers/ 中的现有代码 - Flow documentation created + 流程文档已创建 - Configuration chain documented + 配置链路已文档化 - Task 3: Verify broadcast events work end-to-end + 任务 3: 验证广播端到端工作 -Verify the broadcast mechanism: -1. Check if PostgreSQL LISTEN/NOTIFY is properly configured -2. Verify ReloadGatewayAsync sends the correct event -3. Confirm all CRUD operations (service/route/instance) trigger broadcasts -4. Test end-to-end flow if possible +验证广播机制: +1. 检查 PostgreSQL LISTEN/NOTIFY 是否正确配置 +2. 验证 ReloadGatewayAsync 发送正确事件 +3. 确认所有 CRUD 操作(服务/路由/实例)都触发广播 +4. 如可能,测试端到端流程 - Build succeeds, API endpoints functional + 编译成功,API 端点可用 - Broadcast verification complete + 广播验证完成 -1. Read and analyze ConfigNotificationService.cs -2. Read and analyze GatewayService.cs -3. Document route -> service -> downstream flow -4. Verify build passes +1. 阅读并分析 ConfigNotificationService.cs +2. 阅读并分析 GatewayService.cs +3. 文档化路由 -> 服务 -> 下游流程 +4. 验证编译通过 -- [x] Existing broadcast implementation analyzed -- [x] Configuration chain documented -- [x] Broadcast events verified -- [x] Summary created +- [x] 现有广播实现已分析 +- [x] 配置链路已文档化 +- [x] 广播事件已验证 +- [x] 摘要已创建 -After completion, create `.planning/phases/03-gateway-config-broadcast/03-SUMMARY.md` +完成后创建 `.planning/phases/03-gateway-config-broadcast/03-SUMMARY.md` diff --git a/Directory.Packages.props b/Directory.Packages.props index b0c5c35..2cb65f2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,7 +4,7 @@ - + diff --git a/src/Services/ConfigNotificationService.cs b/src/Services/ConfigNotificationService.cs new file mode 100644 index 0000000..b6d3f92 --- /dev/null +++ b/src/Services/ConfigNotificationService.cs @@ -0,0 +1,133 @@ +using System.Text.Json; +using Microsoft.Extensions.Logging; +using Npgsql; +using Fengling.Console.Data; +using Microsoft.EntityFrameworkCore; + +namespace Fengling.Console.Services; + +/// +/// 配置变更通知服务接口 +/// +public interface INotificationService +{ + /// + /// 发布通知到指定通道 + /// + Task PublishAsync(string channel, string payload, CancellationToken cancellationToken = default); + + /// + /// 发布配置变更事件 + /// + Task PublishConfigChangeAsync( + string eventType, + string action, + object? details = null, + CancellationToken cancellationToken = default); +} + +/// +/// 配置变更事件数据 +/// +public class ConfigChangeEvent +{ + public string EventType { get; set; } = ""; // service, route, instance, gateway + public string Action { get; set; } = ""; // create, update, delete, reload + public DateTime Timestamp { get; set; } = DateTime.UtcNow; + public object? Details { get; set; } +} + +/// +/// PostgreSQL 通知服务实现 +/// 使用 PostgreSQL NOTIFY/LISTEN 机制广播配置变更 +/// +public class PgSqlNotificationService : INotificationService +{ + private readonly ILogger _logger; + private readonly string _connectionString; + + public const string GatewayConfigChangedChannel = "gateway_config_changed"; + + public PgSqlNotificationService(DbContextOptions dbContextOptions, ILogger logger) + { + _logger = logger; + + // 从 DbContextOptions 获取连接字符串 + string? connectionString = null; + + foreach (var ext in dbContextOptions.Extensions) + { + var extType = ext.GetType(); + if (extType.Name.Contains("Npgsql")) + { + var prop = extType.GetProperty("ConnectionString"); + if (prop != null && prop.PropertyType == typeof(string)) + { + connectionString = prop.GetValue(ext) as string; + break; + } + } + } + + _connectionString = connectionString + ?? throw new InvalidOperationException("DefaultConnection not configured"); + } + + /// + public async Task PublishAsync(string channel, string payload, CancellationToken cancellationToken = default) + { + try + { + await using var connection = new NpgsqlConnection(_connectionString); + await connection.OpenAsync(cancellationToken); + + await using var cmd = new NpgsqlCommand( + $"SELECT pg_notify(@channel, @payload)", + connection); + + cmd.Parameters.AddWithValue("channel", channel); + cmd.Parameters.AddWithValue("payload", payload); + + await cmd.ExecuteNonQueryAsync(cancellationToken); + + _logger.LogInformation("Published notification to channel '{Channel}': {Payload}", channel, payload); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to publish notification to channel '{Channel}'", channel); + } + } + + /// + /// 创建配置变更事件并发布 + /// + public async Task PublishConfigChangeAsync( + string eventType, + string action, + object? details = null, + CancellationToken cancellationToken = default) + { + var configEvent = new ConfigChangeEvent + { + EventType = eventType, + Action = action, + Timestamp = DateTime.UtcNow, + Details = details + }; + + var payload = JsonSerializer.Serialize(configEvent); + await PublishAsync(GatewayConfigChangedChannel, payload, cancellationToken); + } +} + +/// +/// 通知服务扩展方法 +/// +public static class NotificationServiceExtensions +{ + public static IServiceCollection AddNotificationService(this IServiceCollection services) + { + services.AddScoped(); + return services; + } +}