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}";
}
}