mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-13 05:31:07 +08:00
174 lines
8.1 KiB
C#
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);
|
|
}
|
|
} |