mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-31 05:00:33 +08:00
feat(storage): implement storage management API and enhance storage mode handling
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System.Reflection;
|
||||
using Foxel.Services.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.EntityFrameworkCore; // For IDbContextFactory
|
||||
using System.Text.Json; // For JsonSerializer
|
||||
using Foxel.Services.Storage.Providers; // For specific config classes
|
||||
|
||||
namespace Foxel.Services.Storage;
|
||||
|
||||
@@ -12,11 +14,16 @@ 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)
|
||||
public StorageService(
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<StorageService> logger,
|
||||
IDbContextFactory<MyDbContext> contextFactory)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_contextFactory = contextFactory;
|
||||
RegisterStorageProviders();
|
||||
}
|
||||
|
||||
@@ -27,14 +34,14 @@ public class StorageService : IStorageService
|
||||
{
|
||||
// 获取当前应用程序域中所有程序集
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 扫描每个程序集中的所有类型
|
||||
var types = assembly.GetTypes()
|
||||
.Where(type => type is { IsClass: true, IsAbstract: false } &&
|
||||
.Where(type => type is { IsClass: true, IsAbstract: false } &&
|
||||
type.GetInterfaces().Contains(typeof(IStorageProvider)) &&
|
||||
type.GetCustomAttribute<StorageProviderAttribute>() != null);
|
||||
|
||||
@@ -45,45 +52,123 @@ public class StorageService : IStorageService
|
||||
{
|
||||
// 注册存储提供者类型与对应的存储类型
|
||||
_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(StorageType storageType)
|
||||
private IStorageProvider GetProvider(int storageModeId)
|
||||
{
|
||||
if (!_storageProviders.TryGetValue(storageType, out var providerType))
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
var storageMode = context.StorageModes
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(sm => sm.Id == storageModeId);
|
||||
|
||||
if (storageMode == null)
|
||||
{
|
||||
throw new ArgumentException($"未找到存储类型 {storageType} 的提供者");
|
||||
_logger.LogError("ID 为 {StorageModeId} 的 StorageMode 未找到。", storageModeId);
|
||||
throw new ArgumentException($"ID 为 {storageModeId} 的 StorageMode 未找到。");
|
||||
}
|
||||
|
||||
return (IStorageProvider)_serviceProvider.GetRequiredService(providerType);
|
||||
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>(StorageType storageType, Func<IStorageProvider, Task<TResult>> operation)
|
||||
public async Task<TResult> ExecuteAsync<TResult>(int storageModeId, Func<IStorageProvider, Task<TResult>> operation)
|
||||
{
|
||||
var provider = GetProvider(storageType);
|
||||
var provider = GetProvider(storageModeId);
|
||||
return await operation(provider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在指定存储类型上执行无返回值的操作
|
||||
/// 在指定存储模式上执行无返回值的操作
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(StorageType storageType, Func<IStorageProvider, Task> operation)
|
||||
public async Task ExecuteAsync(int storageModeId, Func<IStorageProvider, Task> operation)
|
||||
{
|
||||
var provider = GetProvider(storageType);
|
||||
var provider = GetProvider(storageModeId);
|
||||
await operation(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user