126 lines
4.0 KiB
C#
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:5000/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}"
|
|
});
|
|
}
|
|
}
|
|
} |