You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.1 KiB

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using CoreAgent.WebSocketTransport.Models;
namespace CoreAgent.WebSocketTransport.Middleware;
/// <summary>
/// 缓存中间件
/// 使用 IMemoryCache 缓存静态消息(如 CONFIG_ 消息),支持 TTL
/// </summary>
public class CacheMiddleware : IMessageMiddleware
{
private readonly IMemoryCache _cache;
private readonly ILogger<CacheMiddleware> _logger;
private readonly WebSocketConfig _config;
private static readonly string[] _cacheablePrefixes = { "CONFIG_", "SETTINGS_" };
public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, IOptions<WebSocketConfig> config)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_config = config?.Value ?? throw new ArgumentNullException(nameof(config));
}
/// <summary>
/// 处理发送消息,不进行缓存操作
/// </summary>
public Task<T?> ProcessSendAsync<T>(T message, CancellationToken cancellationToken = default)
{
// 发送消息不进行缓存,直接返回
return Task.FromResult<T?>(message);
}
/// <summary>
/// 处理接收消息,缓存符合条件的消息
/// </summary>
public Task<T?> ProcessReceiveAsync<T>(T message, CancellationToken cancellationToken = default)
{
if (message == null)
{
return Task.FromResult<T?>(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<T?>(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<T?>(message);
}
/// <summary>
/// 判断是否为可缓存消息
/// </summary>
private static bool IsCacheableMessage(string? message)
{
if (string.IsNullOrEmpty(message))
return false;
return _cacheablePrefixes.Any(prefix =>
message.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 生成缓存键
/// </summary>
private static string GenerateCacheKey(string? message)
{
return $"websocket_cache_{message?.GetHashCode() ?? 0}";
}
}