mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-07 00:27:44 +08:00
feat(StorageService, PictureController): refactor storage service methods to use unified ExecuteAsync pattern for file operations
This commit is contained in:
@@ -6,7 +6,6 @@ using Foxel.Models.Request.Picture;
|
|||||||
using Foxel.Models.Response.Picture;
|
using Foxel.Models.Response.Picture;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Foxel.Services.Configuration;
|
|
||||||
using Foxel.Services.Media;
|
using Foxel.Services.Media;
|
||||||
using Foxel.Services.Storage;
|
using Foxel.Services.Storage;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -16,7 +15,7 @@ namespace Foxel.Controllers;
|
|||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/picture")]
|
[Route("api/picture")]
|
||||||
public class PictureController(IPictureService pictureService, IConfigService configService, IStorageService storageService) : BaseApiController
|
public class PictureController(IPictureService pictureService, IStorageService storageService) : BaseApiController
|
||||||
{
|
{
|
||||||
[HttpGet("get_pictures")]
|
[HttpGet("get_pictures")]
|
||||||
public async Task<ActionResult<PaginatedResult<PictureResponse>>> GetPictures(
|
public async Task<ActionResult<PaginatedResult<PictureResponse>>> GetPictures(
|
||||||
@@ -280,7 +279,8 @@ public class PictureController(IPictureService pictureService, IConfigService co
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 使用 storageService 下载文件,这样会自动使用配置的代理
|
// 使用 storageService 下载文件,这样会自动使用配置的代理
|
||||||
string tempFilePath = await storageService.DownloadFileAsync(StorageType.Telegram, storagePath);
|
string tempFilePath = await storageService.ExecuteAsync(StorageType.Telegram,
|
||||||
|
provider => provider.DownloadFileAsync(storagePath));
|
||||||
|
|
||||||
// 获取文件内容类型
|
// 获取文件内容类型
|
||||||
string contentType = GetContentTypeFromPath(tempFilePath);
|
string contentType = GetContentTypeFromPath(tempFilePath);
|
||||||
@@ -327,7 +327,8 @@ public class PictureController(IPictureService pictureService, IConfigService co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 下载文件到临时位置
|
// 下载文件到临时位置
|
||||||
string filePath = await storageService.DownloadFileAsync(StorageType.WebDAV,path);
|
string filePath = await storageService.ExecuteAsync(StorageType.WebDAV,
|
||||||
|
provider => provider.DownloadFileAsync(path));
|
||||||
|
|
||||||
// 确定内容类型
|
// 确定内容类型
|
||||||
string contentType = GetContentTypeFromPath(path);
|
string contentType = GetContentTypeFromPath(path);
|
||||||
|
|||||||
@@ -225,7 +225,8 @@ public sealed class BackgroundTaskQueue : IBackgroundTaskQueue, IDisposable
|
|||||||
{
|
{
|
||||||
// 非本地存储需要先下载文件
|
// 非本地存储需要先下载文件
|
||||||
await UpdatePictureStatus(task.PictureId, ProcessingStatus.Processing, 15);
|
await UpdatePictureStatus(task.PictureId, ProcessingStatus.Processing, 15);
|
||||||
localFilePath = await storageService.DownloadFileAsync(picture.StorageType, picture.Path);
|
localFilePath = await storageService.ExecuteAsync(picture.StorageType,
|
||||||
|
provider => provider.DownloadFileAsync(picture.Path));
|
||||||
isTempFile = true;
|
isTempFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,11 +260,9 @@ public sealed class BackgroundTaskQueue : IBackgroundTaskQueue, IDisposable
|
|||||||
var thumbnailContentType = "image/webp";
|
var thumbnailContentType = "image/webp";
|
||||||
|
|
||||||
// 上传缩略图并获取存储路径或元数据
|
// 上传缩略图并获取存储路径或元数据
|
||||||
string thumbnailStoragePath = await storageService.SaveAsync(
|
string thumbnailStoragePath = await storageService.ExecuteAsync(
|
||||||
picture.StorageType,
|
picture.StorageType,
|
||||||
thumbnailFileStream,
|
provider => provider.SaveAsync(thumbnailFileStream, thumbnailFileName, thumbnailContentType));
|
||||||
thumbnailFileName,
|
|
||||||
thumbnailContentType);
|
|
||||||
|
|
||||||
// 将路径或元数据存储到ThumbnailPath
|
// 将路径或元数据存储到ThumbnailPath
|
||||||
picture.ThumbnailPath = thumbnailStoragePath;
|
picture.ThumbnailPath = thumbnailStoragePath;
|
||||||
|
|||||||
@@ -377,8 +377,10 @@ public class PictureService(
|
|||||||
{
|
{
|
||||||
Id = picture.Id,
|
Id = picture.Id,
|
||||||
Name = picture.Name,
|
Name = picture.Name,
|
||||||
Path = storageService.GetUrl(picture.StorageType, picture.Path),
|
Path = storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
ThumbnailPath = storageService.GetUrl(picture.StorageType, picture.ThumbnailPath),
|
Task.FromResult(provider.GetUrl(picture.Path ?? string.Empty))).Result,
|
||||||
|
ThumbnailPath = storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
|
Task.FromResult(provider.GetUrl(picture.ThumbnailPath ?? string.Empty))).Result,
|
||||||
Description = picture.Description,
|
Description = picture.Description,
|
||||||
CreatedAt = picture.CreatedAt,
|
CreatedAt = picture.CreatedAt,
|
||||||
Tags = picture.Tags != null ? picture.Tags.Select(t => t.Name).ToList() : new List<string>(),
|
Tags = picture.Tags != null ? picture.Tags.Select(t => t.Name).ToList() : new List<string>(),
|
||||||
@@ -551,7 +553,8 @@ public class PictureService(
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 使用存储服务保存文件
|
// 使用存储服务保存文件
|
||||||
string relativePath = await storageService.SaveAsync(storageType.Value, finalStream, finalFileName, finalContentType);
|
string relativePath = await storageService.ExecuteAsync(storageType.Value,
|
||||||
|
provider => provider.SaveAsync(finalStream, finalFileName, finalContentType));
|
||||||
|
|
||||||
// 创建基本的Picture对象,使用文件名作为标题和描述
|
// 创建基本的Picture对象,使用文件名作为标题和描述
|
||||||
string initialTitle = Path.GetFileNameWithoutExtension(originalFileName);
|
string initialTitle = Path.GetFileNameWithoutExtension(originalFileName);
|
||||||
@@ -617,8 +620,10 @@ public class PictureService(
|
|||||||
{
|
{
|
||||||
Id = picture.Id,
|
Id = picture.Id,
|
||||||
Name = picture.Name,
|
Name = picture.Name,
|
||||||
Path = storageService.GetUrl(picture.StorageType, relativePath),
|
Path = await storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
ThumbnailPath = isAnonymous ? storageService.GetUrl(picture.StorageType, relativePath) : null,
|
Task.FromResult(provider.GetUrl(relativePath))),
|
||||||
|
ThumbnailPath = isAnonymous ? await storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
|
Task.FromResult(provider.GetUrl(relativePath))) : null,
|
||||||
Description = picture.Description,
|
Description = picture.Description,
|
||||||
CreatedAt = picture.CreatedAt,
|
CreatedAt = picture.CreatedAt,
|
||||||
Tags = new List<string>(),
|
Tags = new List<string>(),
|
||||||
@@ -695,7 +700,7 @@ public class PictureService(
|
|||||||
new List<(int PictureId, string Path, string ThumbnailPath, int? UserId, StorageType StorageType)>();
|
new List<(int PictureId, string Path, string ThumbnailPath, int? UserId, StorageType StorageType)>();
|
||||||
foreach (var picture in picturesToDelete)
|
foreach (var picture in picturesToDelete)
|
||||||
{
|
{
|
||||||
filesToDelete.Add((picture.Id, picture.Path, picture.ThumbnailPath, picture.User?.Id, picture.StorageType));
|
filesToDelete.Add((picture.Id, picture.Path, picture.ThumbnailPath ?? string.Empty, picture.User?.Id, picture.StorageType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (picturesToDelete.Any())
|
if (picturesToDelete.Any())
|
||||||
@@ -713,12 +718,14 @@ public class PictureService(
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 使用存储服务删除文件
|
// 使用存储服务删除文件
|
||||||
await storageService.DeleteAsync(storageType, path);
|
await storageService.ExecuteAsync(storageType,
|
||||||
|
provider => provider.DeleteAsync(path));
|
||||||
|
|
||||||
// 删除缩略图
|
// 删除缩略图
|
||||||
if (!string.IsNullOrEmpty(thumbnailPath))
|
if (!string.IsNullOrEmpty(thumbnailPath))
|
||||||
{
|
{
|
||||||
await storageService.DeleteAsync(storageType, thumbnailPath);
|
await storageService.ExecuteAsync(storageType,
|
||||||
|
provider => provider.DeleteAsync(thumbnailPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -819,8 +826,10 @@ public class PictureService(
|
|||||||
{
|
{
|
||||||
Id = picture.Id,
|
Id = picture.Id,
|
||||||
Name = picture.Name,
|
Name = picture.Name,
|
||||||
Path = storageService.GetUrl(picture.StorageType, picture.Path),
|
Path = await storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
ThumbnailPath = storageService.GetUrl(picture.StorageType, picture.ThumbnailPath),
|
Task.FromResult(provider.GetUrl(picture.Path ?? string.Empty))),
|
||||||
|
ThumbnailPath = await storageService.ExecuteAsync(picture.StorageType, provider =>
|
||||||
|
Task.FromResult(provider.GetUrl(picture.ThumbnailPath ?? string.Empty))),
|
||||||
Description = picture.Description,
|
Description = picture.Description,
|
||||||
CreatedAt = picture.CreatedAt,
|
CreatedAt = picture.CreatedAt,
|
||||||
Tags = picture.Tags?.Select(t => t.Name).ToList() ?? new List<string>(),
|
Tags = picture.Tags?.Select(t => t.Name).ToList() ?? new List<string>(),
|
||||||
|
|||||||
@@ -8,42 +8,18 @@ namespace Foxel.Services.Storage;
|
|||||||
public interface IStorageService
|
public interface IStorageService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据存储类型获取对应的存储提供者
|
/// 在指定存储类型上执行操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <typeparam name="TResult">操作结果类型</typeparam>
|
||||||
/// <param name="storageType">存储类型</param>
|
/// <param name="storageType">存储类型</param>
|
||||||
/// <returns>存储提供者实例</returns>
|
/// <param name="operation">要执行的操作</param>
|
||||||
IStorageProvider GetProvider(StorageType storageType);
|
/// <returns>操作结果</returns>
|
||||||
|
Task<TResult> ExecuteAsync<TResult>(StorageType storageType, Func<IStorageProvider, Task<TResult>> operation);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用指定存储类型保存文件
|
/// 在指定存储类型上执行无返回值的操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="storageType">存储类型</param>
|
/// <param name="storageType">存储类型</param>
|
||||||
/// <param name="fileStream">文件流</param>
|
/// <param name="operation">要执行的操作</param>
|
||||||
/// <param name="fileName">文件名</param>
|
Task ExecuteAsync(StorageType storageType, Func<IStorageProvider, Task> operation);
|
||||||
/// <param name="contentType">内容类型</param>
|
|
||||||
/// <returns>存储路径</returns>
|
|
||||||
Task<string> SaveAsync(StorageType storageType, Stream fileStream, string fileName, string contentType);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用指定存储类型删除文件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="storageType">存储类型</param>
|
|
||||||
/// <param name="storagePath">存储路径</param>
|
|
||||||
Task DeleteAsync(StorageType storageType, string storagePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用指定存储类型获取文件URL
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="storageType">存储类型</param>
|
|
||||||
/// <param name="storagePath">存储路径</param>
|
|
||||||
/// <returns>文件URL</returns>
|
|
||||||
string GetUrl(StorageType storageType, string storagePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用指定存储类型下载文件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="storageType">存储类型</param>
|
|
||||||
/// <param name="storagePath">存储路径</param>
|
|
||||||
/// <returns>本地文件路径</returns>
|
|
||||||
Task<string> DownloadFileAsync(StorageType storageType, string storagePath);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class StorageService : IStorageService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定存储类型的提供者实例
|
/// 获取指定存储类型的提供者实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStorageProvider GetProvider(StorageType storageType)
|
private IStorageProvider GetProvider(StorageType storageType)
|
||||||
{
|
{
|
||||||
if (!_storageProviders.TryGetValue(storageType, out var providerType))
|
if (!_storageProviders.TryGetValue(storageType, out var providerType))
|
||||||
{
|
{
|
||||||
@@ -67,38 +67,20 @@ public class StorageService : IStorageService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用指定存储类型保存文件
|
/// 在指定存储类型上执行操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task<string> SaveAsync(StorageType storageType, Stream fileStream, string fileName, string contentType)
|
public async Task<TResult> ExecuteAsync<TResult>(StorageType storageType, Func<IStorageProvider, Task<TResult>> operation)
|
||||||
{
|
{
|
||||||
var provider = GetProvider(storageType);
|
var provider = GetProvider(storageType);
|
||||||
return provider.SaveAsync(fileStream, fileName, contentType);
|
return await operation(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用指定存储类型删除文件
|
/// 在指定存储类型上执行无返回值的操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task DeleteAsync(StorageType storageType, string storagePath)
|
public async Task ExecuteAsync(StorageType storageType, Func<IStorageProvider, Task> operation)
|
||||||
{
|
{
|
||||||
var provider = GetProvider(storageType);
|
var provider = GetProvider(storageType);
|
||||||
return provider.DeleteAsync(storagePath);
|
await operation(provider);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用指定存储类型获取文件URL
|
|
||||||
/// </summary>
|
|
||||||
public string GetUrl(StorageType storageType, string storagePath)
|
|
||||||
{
|
|
||||||
var provider = GetProvider(storageType);
|
|
||||||
return provider.GetUrl(storagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用指定存储类型下载文件
|
|
||||||
/// </summary>
|
|
||||||
public Task<string> DownloadFileAsync(StorageType storageType, string storagePath)
|
|
||||||
{
|
|
||||||
var provider = GetProvider(storageType);
|
|
||||||
return provider.DownloadFileAsync(storagePath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user