using System.Collections.Concurrent;
using CMSMicroservice.Protobuf.Protos.ImageResolver;
namespace FrontOffice.Main.Utilities;
///
/// سرویس مرکزی resolve تصاویر — تمام تصاویر دینامیک FrontOffice از این سرویس عبور میکنند.
/// مسیرهای نسبی از طریق gRPC به CMS ارسال شده و base64 data-URI دریافت میشود.
/// نتایج در حافظه کش میشوند تا از فراخوانی مجدد جلوگیری شود.
///
public class ImageCacheService
{
private readonly ImageResolverContract.ImageResolverContractClient _client;
private readonly ConcurrentDictionary _cache = new();
public ImageCacheService(ImageResolverContract.ImageResolverContractClient client)
{
_client = client;
}
///
/// تبدیل یک مسیر تصویر به base64 data-URI.
/// اگر مسیر خالی باشد → رشته خالی.
/// اگر قبلاً data-URI باشد → بدون تغییر.
/// اگر در کش باشد → از کش.
/// در غیر این صورت → فراخوانی gRPC.
///
public async Task ResolveAsync(string? path)
{
if (string.IsNullOrWhiteSpace(path))
return string.Empty;
// اگر قبلاً base64 هست (مثلاً از interceptor آمده)
if (path.StartsWith("data:", StringComparison.Ordinal))
return path;
// مسیرهای استاتیک (wwwroot) یا لینکهای خارجی نیاز به resolve ندارند
if (path.StartsWith('/') || path.StartsWith("http://", StringComparison.Ordinal)
|| path.StartsWith("https://", StringComparison.Ordinal))
return path;
// جستجو در کش
if (_cache.TryGetValue(path, out var cached))
return cached;
try
{
var response = await _client.ResolveImagesAsync(
new ResolveImagesRequest { Paths = { path } });
var result = response?.Images?.FirstOrDefault()?.DataUri ?? string.Empty;
_cache.TryAdd(path, result);
return result;
}
catch
{
// در صورت خطا، رشته خالی برگردان تا UI خراب نشود
return string.Empty;
}
}
///
/// تبدیل دستهای مسیرهای تصویر به base64 data-URI.
/// مسیرهای کششده و data-URIها بدون فراخوانی gRPC برگردانده میشوند.
///
public async Task> ResolveBatchAsync(IEnumerable paths)
{
var result = new Dictionary();
var toResolve = new List();
foreach (var path in paths)
{
if (string.IsNullOrWhiteSpace(path))
continue;
if (path.StartsWith("data:", StringComparison.Ordinal)
|| path.StartsWith('/')
|| path.StartsWith("http://", StringComparison.Ordinal)
|| path.StartsWith("https://", StringComparison.Ordinal))
{
result[path] = path;
}
else if (_cache.TryGetValue(path, out var cached))
{
result[path] = cached;
}
else
{
toResolve.Add(path);
}
}
if (toResolve.Count == 0)
return result;
try
{
var response = await _client.ResolveImagesAsync(
new ResolveImagesRequest { Paths = { toResolve } });
if (response?.Images != null)
{
foreach (var img in response.Images)
{
_cache.TryAdd(img.OriginalPath, img.DataUri);
result[img.OriginalPath] = img.DataUri;
}
}
}
catch
{
// در صورت خطا، مسیرهای resolve نشده خالی بمانند
}
return result;
}
///
/// پاکسازی تمام کش (مثلاً هنگام logout)
///
public void ClearCache() => _cache.Clear();
}