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