Files
Foxel/Services/Storage/StorageService.cs

174 lines
8.1 KiB
C#

using System.Reflection;
using Foxel.Services.Attributes;
using Microsoft.EntityFrameworkCore; // For IDbContextFactory
using System.Text.Json; // For JsonSerializer
using Foxel.Services.Storage.Providers; // For specific config classes
namespace Foxel.Services.Storage;
/// <summary>
/// 统一的存储服务实现
/// </summary>
public class StorageService : IStorageService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<StorageService> _logger;
private readonly Dictionary<StorageType, Type> _storageProviders = new();
private readonly IDbContextFactory<MyDbContext> _contextFactory;
public StorageService(
IServiceProvider serviceProvider,
ILogger<StorageService> logger,
IDbContextFactory<MyDbContext> contextFactory)
{
_serviceProvider = serviceProvider;
_logger = logger;
_contextFactory = contextFactory;
RegisterStorageProviders();
}
/// <summary>
/// 使用反射扫描和注册所有标记了StorageProviderAttribute的存储提供者
/// </summary>
private void RegisterStorageProviders()
{
// 获取当前应用程序域中所有程序集
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
try
{
// 扫描每个程序集中的所有类型
var types = assembly.GetTypes()
.Where(type => type is { IsClass: true, IsAbstract: false } &&
type.GetInterfaces().Contains(typeof(IStorageProvider)) &&
type.GetCustomAttribute<StorageProviderAttribute>() != null);
foreach (var type in types)
{
var attribute = type.GetCustomAttribute<StorageProviderAttribute>();
if (attribute != null)
{
// 注册存储提供者类型与对应的存储类型
_storageProviders[attribute.StorageType] = type;
_logger.LogInformation("已注册存储提供者: {StorageType} -> {ProviderType}", attribute.StorageType, type.FullName);
}
}
}
catch (ReflectionTypeLoadException ex) // 更具体地捕获加载类型时的异常
{
_logger.LogWarning(ex, "扫描程序集 {AssemblyName} 时发生类型加载错误。详细信息: {LoaderExceptions}", assembly.FullName,
string.Join(", ", ex.LoaderExceptions.Select(e => e?.Message ?? "N/A")));
}
catch (Exception ex)
{
_logger.LogWarning(ex, "扫描程序集 {AssemblyName} 时发生错误", assembly.FullName);
// 继续扫描其他程序集
}
}
if (!_storageProviders.Any())
{
_logger.LogWarning("未能注册任何存储提供者。请检查提供者是否正确标记了 [StorageProvider] 特性并且位于扫描的程序集中。");
}
}
/// <summary>
/// 根据 StorageModeId 获取并配置提供者实例
/// </summary>
private IStorageProvider GetProvider(int storageModeId)
{
using var context = _contextFactory.CreateDbContext();
var storageMode = context.StorageModes
.AsNoTracking()
.FirstOrDefault(sm => sm.Id == storageModeId);
if (storageMode == null)
{
_logger.LogError("ID 为 {StorageModeId} 的 StorageMode 未找到。", storageModeId);
throw new ArgumentException($"ID 为 {storageModeId} 的 StorageMode 未找到。");
}
if (!storageMode.IsEnabled)
{
_logger.LogWarning("StorageMode {StorageModeId} ({StorageModeName}) 未启用。", storageModeId, storageMode.Name);
throw new InvalidOperationException($"StorageMode '{storageMode.Name}' (ID: {storageModeId}) 未启用。");
}
if (!_storageProviders.TryGetValue(storageMode.StorageType, out var providerType))
{
_logger.LogError("未找到 StorageType {StorageType} (来自 StorageMode {StorageModeId}) 的已注册提供者。", storageMode.StorageType, storageModeId);
throw new ArgumentException($"未找到 StorageType {storageMode.StorageType} 的提供者。");
}
object specificConfig = DeserializeProviderConfig(storageMode.StorageType, storageMode.ConfigurationJson, storageMode.Name);
try
{
return (IStorageProvider)ActivatorUtilities.CreateInstance(_serviceProvider, providerType, specificConfig);
}
catch (Exception ex)
{
_logger.LogError(ex, "为 StorageMode {StorageModeName} (ID: {StorageModeId}, Type: {StorageType}) 创建提供者 {ProviderType} 的实例失败。",
storageMode.Name, storageModeId, storageMode.StorageType, providerType.FullName);
throw new InvalidOperationException($"创建存储提供者 '{providerType.Name}' 失败: {ex.Message}", ex);
}
}
private object DeserializeProviderConfig(StorageType storageType, string? jsonConfig, string storageModeName)
{
if (string.IsNullOrWhiteSpace(jsonConfig))
{
_logger.LogError("StorageMode '{StorageModeName}' (Type: {StorageType}) 的 ConfigurationJson 为空或空白。", storageModeName, storageType);
throw new InvalidOperationException($"StorageMode '{storageModeName}' (Type: {storageType}) 的配置 (ConfigurationJson) 为空。");
}
try
{
switch (storageType)
{
case StorageType.Local:
return JsonSerializer.Deserialize<LocalStorageConfig>(jsonConfig)
?? throw new JsonException($"无法反序列化 LocalStorageConfig。JSON: {jsonConfig}");
case StorageType.Telegram:
return JsonSerializer.Deserialize<TelegramStorageConfig>(jsonConfig)
?? throw new JsonException($"无法反序列化 TelegramStorageConfig。JSON: {jsonConfig}");
case StorageType.S3:
return JsonSerializer.Deserialize<S3StorageConfig>(jsonConfig)
?? throw new JsonException($"无法反序列化 S3StorageConfig。JSON: {jsonConfig}");
case StorageType.Cos:
return JsonSerializer.Deserialize<CosStorageConfig>(jsonConfig)
?? throw new JsonException($"无法反序列化 CosStorageConfig。JSON: {jsonConfig}");
case StorageType.WebDAV:
return JsonSerializer.Deserialize<WebDavStorageConfig>(jsonConfig)
?? throw new JsonException($"无法反序列化 WebDavStorageConfig。JSON: {jsonConfig}");
default:
_logger.LogError("不支持的存储类型配置反序列化: {StorageType} (来自 StorageMode '{StorageModeName}')", storageType, storageModeName);
throw new NotSupportedException($"不支持 StorageType {storageType} 的配置反序列化。");
}
}
catch (JsonException ex)
{
_logger.LogError(ex, "反序列化 StorageMode '{StorageModeName}' (Type: {StorageType}) 的配置失败。JSON: {JsonConfig}", storageModeName, storageType, jsonConfig);
throw new InvalidOperationException($"StorageMode '{storageModeName}' (Type: {storageType}) 的配置格式无效。", ex);
}
}
/// <summary>
/// 在指定存储模式上执行操作
/// </summary>
public async Task<TResult> ExecuteAsync<TResult>(int storageModeId, Func<IStorageProvider, Task<TResult>> operation)
{
var provider = GetProvider(storageModeId);
return await operation(provider);
}
/// <summary>
/// 在指定存储模式上执行无返回值的操作
/// </summary>
public async Task ExecuteAsync(int storageModeId, Func<IStorageProvider, Task> operation)
{
var provider = GetProvider(storageModeId);
await operation(provider);
}
}