| | | 1 | | namespace Intentum.Core.Caching; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// In-memory implementation of <see cref="IIntentResultCache"/> for single-node or testing. |
| | | 5 | | /// For distributed scenarios use Redis (e.g. Intentum.AI.Caching.Redis or custom implementation). |
| | | 6 | | /// </summary> |
| | | 7 | | public sealed class MemoryIntentResultCache : IIntentResultCache |
| | | 8 | | { |
| | 0 | 9 | | private readonly Dictionary<string, (string Value, DateTimeOffset? ExpiresAt)> _store = new(); |
| | 0 | 10 | | private readonly object _lock = new(); |
| | | 11 | | |
| | | 12 | | /// <inheritdoc /> |
| | | 13 | | public Task<(bool Found, string? Value)> TryGetAsync(string key, CancellationToken cancellationToken = default) |
| | 0 | 14 | | { |
| | 0 | 15 | | lock (_lock) |
| | 0 | 16 | | { |
| | 0 | 17 | | if (!_store.TryGetValue(key, out var entry)) |
| | 0 | 18 | | return Task.FromResult<(bool Found, string? Value)>((false, null)); |
| | 0 | 19 | | if (entry.ExpiresAt.HasValue && DateTimeOffset.UtcNow >= entry.ExpiresAt.Value) |
| | 0 | 20 | | { |
| | 0 | 21 | | _store.Remove(key); |
| | 0 | 22 | | return Task.FromResult<(bool Found, string? Value)>((false, null)); |
| | | 23 | | } |
| | 0 | 24 | | return Task.FromResult<(bool Found, string? Value)>((true, entry.Value)); |
| | | 25 | | } |
| | 0 | 26 | | } |
| | | 27 | | |
| | | 28 | | /// <inheritdoc /> |
| | | 29 | | public Task SetAsync(string key, string value, TimeSpan? ttl = null, CancellationToken cancellationToken = default) |
| | 0 | 30 | | { |
| | 0 | 31 | | var expiresAt = ttl.HasValue ? DateTimeOffset.UtcNow + ttl.Value : (DateTimeOffset?)null; |
| | 0 | 32 | | lock (_lock) |
| | 0 | 33 | | _store[key] = (value, expiresAt); |
| | 0 | 34 | | return Task.CompletedTask; |
| | 0 | 35 | | } |
| | | 36 | | } |