using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using CoreAgent.WebSocketTransport.Models; namespace CoreAgent.WebSocketTransport.Middleware; /// /// 缓存中间件 /// 使用 IMemoryCache 缓存静态消息(如 CONFIG_ 消息),支持 TTL /// public class CacheMiddleware : IMessageMiddleware { private readonly IMemoryCache _cache; private readonly ILogger _logger; private readonly WebSocketConfig _config; private static readonly string[] _cacheablePrefixes = { "CONFIG_", "SETTINGS_" }; public CacheMiddleware(IMemoryCache cache, ILogger logger, IOptions config) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _config = config?.Value ?? throw new ArgumentNullException(nameof(config)); } /// /// 处理发送消息,不进行缓存操作 /// public Task ProcessSendAsync(T message, CancellationToken cancellationToken = default) { // 发送消息不进行缓存,直接返回 return Task.FromResult(message); } /// /// 处理接收消息,缓存符合条件的消息 /// public Task ProcessReceiveAsync(T message, CancellationToken cancellationToken = default) { if (message == null) { return Task.FromResult(default); } var messageStr = message.ToString(); // 检查是否为可缓存消息 if (IsCacheableMessage(messageStr)) { var cacheKey = GenerateCacheKey(messageStr); // 尝试从缓存获取 if (_cache.TryGetValue(cacheKey, out T? cachedMessage)) { _logger.LogDebug("缓存命中: {CacheKey}", cacheKey); return Task.FromResult(cachedMessage); } // 缓存消息 var cacheOptions = new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(_config.CacheTtlMinutes), SlidingExpiration = TimeSpan.FromMinutes(_config.CacheTtlMinutes / 2) }; _cache.Set(cacheKey, message, cacheOptions); _logger.LogDebug("消息已缓存: {CacheKey}, TTL: {TtlMinutes}分钟", cacheKey, _config.CacheTtlMinutes); } return Task.FromResult(message); } /// /// 判断是否为可缓存消息 /// private static bool IsCacheableMessage(string? message) { if (string.IsNullOrEmpty(message)) return false; return _cacheablePrefixes.Any(prefix => message.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); } /// /// 生成缓存键 /// private static string GenerateCacheKey(string? message) { return $"websocket_cache_{message?.GetHashCode() ?? 0}"; } }