44
55namespace Supabase . Storage ;
66
7+ /// <summary>
8+ /// Provides thread-safe in-memory caching for resumable upload URLs with sliding expiration.
9+ /// </summary>
710public class UploadMemoryCache
811{
9- // Thread-safe in-memory cache for resumable upload URLs keyed by an identifier (e.g., file path or upload id).
10- // Uses simple sliding expiration.
1112 private static readonly ConcurrentDictionary < string , CacheEntry > _cache = new ( ) ;
1213
13- // Default sliding expiration for cached URLs.
1414 private static TimeSpan _defaultTtl = TimeSpan . FromMinutes ( 60 ) ;
1515
1616 private static long _version ; // helps with testing/observability if needed
@@ -36,13 +36,23 @@ public void Touch()
3636 public bool IsExpired ( ) => DateTimeOffset . UtcNow >= Expiration ;
3737 }
3838
39- // Sets the default time-to-live for future cache entries.
39+ /// <summary>
40+ /// Sets the default time-to-live duration for future cache entries.
41+ /// </summary>
42+ /// <param name="ttl">The time-to-live duration. If less than or equal to zero, defaults to 5 minutes.</param>
4043 public static void SetDefaultTtl ( TimeSpan ttl )
4144 {
4245 _defaultTtl = ttl <= TimeSpan . Zero ? TimeSpan . FromMinutes ( 5 ) : ttl ;
4346 }
4447
45- // Store or update the resumable upload URL for the provided key.
48+ // Store or upate the resumable upload URL for the provided key.
49+ /// <summary>
50+ /// Stores or updates a resumable upload URL in the cache for the specified key.
51+ /// </summary>
52+ /// <param name="key">The unique identifier for the cached URL.</param>
53+ /// <param name="url">The resumable upload URL to cache.</param>
54+ /// <param name="ttl">Optional time-to-live duration. If not specified, uses the default TTL.</param>
55+ /// <exception cref="ArgumentException">Thrown when key or url is null, empty, or whitespace.</exception>
4656 public static void Set ( string key , string url , TimeSpan ? ttl = null )
4757 {
4858 if ( string . IsNullOrWhiteSpace ( key ) )
@@ -61,32 +71,36 @@ public static void Set(string key, string url, TimeSpan? ttl = null)
6171 CleanupIfNeeded ( ) ;
6272 }
6373
64- // Try to get a cached URL. Refreshes sliding expiration on successful hit.
74+ /// <summary>
75+ /// Attempts to retrieve a cached URL by its key. Updates the sliding expiration on successful retrieval.
76+ /// </summary>
77+ /// <param name="key">The unique identifier for the cached URL.</param>
78+ /// <param name="url">When this method returns, contains the cached URL if found; otherwise, null.</param>
79+ /// <returns>True if the URL was found in the cache; otherwise, false.</returns>
6580 public static bool TryGet ( string key , out string ? url )
6681 {
6782 url = null ;
6883 if ( string . IsNullOrWhiteSpace ( key ) )
6984 return false ;
7085
71- if ( _cache . TryGetValue ( key , out var entry ) )
86+ if ( ! _cache . TryGetValue ( key , out var entry ) ) return false ;
87+ if ( entry . IsExpired ( ) )
7288 {
73- if ( entry . IsExpired ( ) )
74- {
75- // Evict expired entry
76- _cache . TryRemove ( key , out _ ) ;
77- return false ;
78- }
79-
80- // Sliding expiration
81- entry . Touch ( ) ;
82- url = entry . Url ;
83- return true ;
89+ _cache . TryRemove ( key , out _ ) ;
90+ return false ;
8491 }
8592
86- return false ;
93+ entry . Touch ( ) ;
94+ url = entry . Url ;
95+ return true ;
96+
8797 }
8898
89- // Remove a cached URL.
99+ /// <summary>
100+ /// Removes a cached URL by its key.
101+ /// </summary>
102+ /// <param name="key">The unique identifier for the cached URL to remove.</param>
103+ /// <returns>True if the URL was successfully removed; otherwise, false.</returns>
90104 public static bool Remove ( string key )
91105 {
92106 if ( string . IsNullOrWhiteSpace ( key ) )
@@ -98,20 +112,22 @@ public static bool Remove(string key)
98112 return removed ;
99113 }
100114
101- // Clear all cached URLs.
115+ /// <summary>
116+ /// Removes all cached URLs from the cache.
117+ /// </summary>
102118 public static void Clear ( )
103119 {
104120 _cache . Clear ( ) ;
105121 Interlocked . Increment ( ref _version ) ;
106122 }
107123
108- // Optionally expose count for diagnostics.
124+ /// <summary>
125+ /// Gets the current number of entries in the cache.
126+ /// </summary>
109127 public static int Count => _cache . Count ;
110128
111- // Simple opportunistic cleanup to remove expired entries.
112129 private static void CleanupIfNeeded ( )
113130 {
114- // Cheap scan for expired entries. No need for strict guarantees.
115131 foreach ( var kvp in _cache )
116132 {
117133 if ( kvp . Value . IsExpired ( ) )
0 commit comments