Files
better-genshin-impact/BetterGenshinImpact/Service/GearTask/Execution/GearTaskEventBus.cs
辉鸭蛋 7f7a34e9ba feat(gear-task): 引入事件驱动的任务执行与历史记录系统
- 新增 IGearTaskEventBus 接口及默认实现,用于解耦执行器与记录器、UI 投影等消费者
- 新增 IGearTaskResumable 接口,支持任务节点内部恢复(如 Pathing 任务可恢复至特定路径点)
- 重构任务执行流程,使用 GearTaskExecutionRunner 替代旧的 GearTaskExecutionManager
- 实现基于磁盘 JSON 的历史记录存储(IGearTaskHistoryStore),支持执行记录的保存、加载与清理
- 为 PathingGearTask 添加恢复能力,通过 PathingGearTaskResumeState 记录断点状态
- 在 PathExecutor 中集成运行时事件通知,支持路径点进入、完成、传送等事件的发布
- 统一执行事件模型(GearTaskExecutionEvent),包含任务定义、节点路径、时间戳等元数据
- 服务注册更新,使用新的执行器、事件总线、历史记录器等组件
2026-05-11 01:57:29 +08:00

98 lines
2.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace BetterGenshinImpact.Service.GearTask.Execution;
/// <summary>
/// 默认事件总线实现。
/// 当前采用进程内同步分发,借由消费者内部自行决定是否异步缓冲。
/// </summary>
public sealed class GearTaskEventBus : IGearTaskEventBus
{
private readonly ILogger<GearTaskEventBus> _logger;
private readonly object _gate = new();
private readonly List<IGearTaskEventConsumer> _consumers = [];
public GearTaskEventBus(ILogger<GearTaskEventBus> logger)
{
_logger = logger;
}
public ValueTask PublishAsync(GearTaskExecutionEvent evt, CancellationToken ct = default)
{
IGearTaskEventConsumer[] snapshot;
lock (_gate)
{
// 先拷贝快照,避免消费者在回调期间订阅或退订影响当前广播。
snapshot = _consumers.ToArray();
}
return PublishCoreAsync(snapshot, evt, ct);
}
public IDisposable Subscribe(IGearTaskEventConsumer consumer)
{
lock (_gate)
{
_consumers.Add(consumer);
}
return new Subscription(this, consumer);
}
private async ValueTask PublishCoreAsync(IEnumerable<IGearTaskEventConsumer> consumers, GearTaskExecutionEvent evt, CancellationToken ct)
{
foreach (var consumer in consumers)
{
try
{
await consumer.ConsumeAsync(evt, ct);
}
catch (Exception ex)
{
_logger.LogError(ex,
"GearTask 事件消费者处理失败已隔离该异常。Consumer: {ConsumerType}, Event: {EventType}, RecordId: {RecordId}",
consumer.GetType().Name,
evt.GetType().Name,
evt.RecordId);
}
}
}
private void Unsubscribe(IGearTaskEventConsumer consumer)
{
lock (_gate)
{
_consumers.Remove(consumer);
}
}
private sealed class Subscription : IDisposable
{
private readonly GearTaskEventBus _bus;
private readonly IGearTaskEventConsumer _consumer;
private bool _disposed;
public Subscription(GearTaskEventBus bus, IGearTaskEventConsumer consumer)
{
_bus = bus;
_consumer = consumer;
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
_bus.Unsubscribe(_consumer);
}
}
}