112 lines
3.5 KiB
C#
112 lines
3.5 KiB
C#
using back.Options;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace back.persistance.blob;
|
|
|
|
public class FileSystemImageStorageService(
|
|
IOptions<Databases> systemOptions,
|
|
IOptionsMonitor<DatabaseConfig> options,
|
|
IMemoryCache memoryCache
|
|
) : IBlobStorageService
|
|
{
|
|
private readonly string RootPath = systemOptions.Value.BaseDirectory ?? "data";
|
|
private readonly DatabaseConfig config = options.Get(DatabaseConfig.BlobStorage);
|
|
private readonly IMemoryCache cache = memoryCache;
|
|
|
|
private string GetFullPath(string fileName)
|
|
{
|
|
// Ensure the directory exists
|
|
var path = Path.Join(RootPath, config.SystemContainer, fileName);
|
|
var directory = Path.GetDirectoryName(path);
|
|
if (directory != null && !Directory.Exists(directory))
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
public async Task Delete(string fileName)
|
|
{
|
|
try
|
|
{
|
|
var path = GetFullPath(fileName);
|
|
if (cache.TryGetValue(path, out Stream? cachedStream))
|
|
{
|
|
cachedStream?.Dispose(); // Dispose the cached stream if it exists
|
|
cache.Remove(path); // Remove from cache
|
|
}
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new InvalidOperationException($"Error deleting file {fileName}: {ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
public async Task<Stream?> GetStream(string fileName)
|
|
{
|
|
var path = GetFullPath(fileName);
|
|
if (File.Exists(path))
|
|
{
|
|
if (cache.TryGetValue(path, out Stream? cachedStream))
|
|
{
|
|
return cachedStream;
|
|
}
|
|
// open the file stream for multiple reads and cache it for performance
|
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
|
|
cache.CreateEntry(path)
|
|
.SetValue(fileStream)
|
|
.SetSlidingExpiration(TimeSpan.FromMinutes(30)); // Cache for 30 minutes
|
|
|
|
return fileStream;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public async Task<byte[]?> GetBytes(string fileName)
|
|
{
|
|
var stream = await GetStream(fileName);
|
|
if (stream != null)
|
|
{
|
|
using var memoryStream = new MemoryStream();
|
|
await stream.CopyToAsync(memoryStream);
|
|
return memoryStream.ToArray();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public async Task Save(Stream blobStream, string fileName)
|
|
{
|
|
var path = GetFullPath(fileName);
|
|
if (cache.TryGetValue(path, out Stream? _) || File.Exists(path))
|
|
{
|
|
throw new InvalidOperationException($"File {fileName} already exists. Use Update for updating file info.");
|
|
}
|
|
using var fileStream = new FileStream(path, options: new FileStreamOptions {
|
|
Access = FileAccess.Write,
|
|
BufferSize = 4096,
|
|
Mode = FileMode.OpenOrCreate,
|
|
Share = FileShare.Read,
|
|
});
|
|
blobStream.Seek(0, SeekOrigin.Begin);
|
|
await blobStream.CopyToAsync(fileStream);
|
|
blobStream.Seek(0, SeekOrigin.Begin);
|
|
}
|
|
|
|
public async Task Update(Stream blobStream, string fileName)
|
|
{
|
|
var path = GetFullPath(fileName);
|
|
if (File.Exists(path))
|
|
{
|
|
await Delete(fileName);
|
|
}
|
|
await Save(blobStream, fileName);
|
|
}
|
|
}
|
|
|