dramaling-vocab-learning/backend/DramaLing.Api/Services/Storage/LocalImageStorageService.cs

126 lines
4.0 KiB
C#

using DramaLing.Api.Models.Configuration;
using Microsoft.Extensions.Options;
namespace DramaLing.Api.Services.Storage;
public class LocalImageStorageService : IImageStorageService
{
private readonly string _basePath;
private readonly string _baseUrl;
private readonly ILogger<LocalImageStorageService> _logger;
public LocalImageStorageService(
IConfiguration configuration,
ILogger<LocalImageStorageService> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_basePath = configuration["ImageStorage:Local:BasePath"] ?? "wwwroot/images/examples";
_baseUrl = configuration["ImageStorage:Local:BaseUrl"] ?? "https://localhost:5008/images/examples";
// 確保目錄存在
var fullPath = Path.GetFullPath(_basePath);
if (!Directory.Exists(fullPath))
{
Directory.CreateDirectory(fullPath);
_logger.LogInformation("Created image storage directory: {Path}", fullPath);
}
}
public async Task<string> SaveImageAsync(Stream imageStream, string fileName)
{
try
{
var fullPath = Path.Combine(_basePath, fileName);
var directory = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using var fileStream = new FileStream(fullPath, FileMode.Create);
await imageStream.CopyToAsync(fileStream);
_logger.LogInformation("Image saved to {Path}", fullPath);
return fileName; // 回傳相對路徑
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to save image {FileName}", fileName);
throw;
}
}
public Task<string> GetImageUrlAsync(string imagePath)
{
var imageUrl = $"{_baseUrl.TrimEnd('/')}/{imagePath.TrimStart('/')}";
return Task.FromResult(imageUrl);
}
public Task<bool> DeleteImageAsync(string imagePath)
{
try
{
var fullPath = Path.Combine(_basePath, imagePath);
if (File.Exists(fullPath))
{
File.Delete(fullPath);
_logger.LogInformation("Image deleted: {Path}", fullPath);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to delete image {ImagePath}", imagePath);
return Task.FromResult(false);
}
}
public Task<bool> ImageExistsAsync(string imagePath)
{
var fullPath = Path.Combine(_basePath, imagePath);
return Task.FromResult(File.Exists(fullPath));
}
public Task<StorageInfo> GetStorageInfoAsync()
{
try
{
var fullPath = Path.GetFullPath(_basePath);
var directory = new DirectoryInfo(fullPath);
if (!directory.Exists)
{
return Task.FromResult(new StorageInfo
{
Provider = "Local",
Status = "Directory not found"
});
}
var files = directory.GetFiles("*", SearchOption.AllDirectories);
var totalSize = files.Sum(f => f.Length);
return Task.FromResult(new StorageInfo
{
Provider = "Local",
TotalSizeBytes = totalSize,
FileCount = files.Length,
Status = "Available"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get storage info");
return Task.FromResult(new StorageInfo
{
Provider = "Local",
Status = $"Error: {ex.Message}"
});
}
}
}