mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-15 12:27:47 +08:00
feat(storage): refactor storage service and provider interface, support dynamic registration of storage providers
This commit is contained in:
@@ -2,10 +2,10 @@ using Foxel.Services.Interface;
|
||||
using COSXML;
|
||||
using COSXML.Auth;
|
||||
using COSXML.Model.Object;
|
||||
using COSXML.Model.Bucket;
|
||||
using COSXML.Transfer;
|
||||
using COSXML.CosException;
|
||||
using COSXML.Model.Tag;
|
||||
using Foxel.Services.Attributes;
|
||||
|
||||
namespace Foxel.Services.StorageProvider;
|
||||
|
||||
@@ -20,7 +20,7 @@ public class CustomQCloudCredentialProvider : DefaultSessionQCloudCredentialProv
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
public sealed override void Refresh()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -29,8 +29,8 @@ public class CustomQCloudCredentialProvider : DefaultSessionQCloudCredentialProv
|
||||
string tmpToken = _configService["Storage:CosStorageToken"];
|
||||
long tmpStartTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
long tmpExpiredTime = tmpStartTime + 7200;
|
||||
SetQCloudCredential(tmpSecretId, tmpSecretKey,
|
||||
String.Format("{0};{1}", tmpStartTime, tmpExpiredTime), tmpToken);
|
||||
SetQCloudCredential(tmpSecretId, tmpSecretKey,
|
||||
$"{tmpStartTime};{tmpExpiredTime}", tmpToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -39,11 +39,9 @@ public class CustomQCloudCredentialProvider : DefaultSessionQCloudCredentialProv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StorageProvider(StorageType.Cos)]
|
||||
public class CosStorageProvider : IStorageProvider
|
||||
{
|
||||
private readonly string _secretId;
|
||||
private readonly string _secretKey;
|
||||
private readonly string _bucketName;
|
||||
private readonly string _region;
|
||||
private readonly string _cdnUrl;
|
||||
@@ -55,14 +53,12 @@ public class CosStorageProvider : IStorageProvider
|
||||
public CosStorageProvider(IConfigService configService)
|
||||
{
|
||||
_configService = configService;
|
||||
_secretId = configService["Storage:CosStorageSecretId"];
|
||||
_secretKey = configService["Storage:CosStorageSecretKey"];
|
||||
_bucketName = configService["Storage:CosStorageBucketName"];
|
||||
_region = configService["Storage:CosStorageRegion"];
|
||||
_cdnUrl = configService["Storage:CosStorageCdnUrl"] ?? string.Empty;
|
||||
_cdnUrl = configService["Storage:CosStorageCdnUrl"];
|
||||
|
||||
// 检查桶是否为公开读取(从配置获取)
|
||||
bool.TryParse(configService["Storage:CosStoragePublicRead"] ?? "false", out _isPublicRead);
|
||||
bool.TryParse(configService["Storage:CosStoragePublicRead"], out _isPublicRead);
|
||||
|
||||
// 在构造函数中初始化客户端,作为单例使用
|
||||
_cosXmlClient = CreateClient();
|
||||
@@ -96,7 +92,7 @@ public class CosStorageProvider : IStorageProvider
|
||||
string tempPath = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
using (var fileStream2 = new FileStream(tempPath, FileMode.Create))
|
||||
await using (var fileStream2 = new FileStream(tempPath, FileMode.Create))
|
||||
{
|
||||
await fileStream.CopyToAsync(fileStream2);
|
||||
}
|
||||
@@ -105,7 +101,7 @@ public class CosStorageProvider : IStorageProvider
|
||||
var transferManager = new TransferManager(_cosXmlClient, transferConfig);
|
||||
var uploadTask = new COSXMLUploadTask(_bucketName, objectKey);
|
||||
uploadTask.SetSrcPath(tempPath);
|
||||
var result = await transferManager.UploadAsync(uploadTask);
|
||||
await transferManager.UploadAsync(uploadTask);
|
||||
return objectKey;
|
||||
}
|
||||
finally
|
||||
@@ -216,7 +212,7 @@ public class CosStorageProvider : IStorageProvider
|
||||
var transferConfig = new TransferConfig();
|
||||
var transferManager = new TransferManager(_cosXmlClient, transferConfig);
|
||||
var downloadTask = new COSXMLDownloadTask(_bucketName, storagePath, tempDir, fileName);
|
||||
var result = await transferManager.DownloadAsync(downloadTask);
|
||||
await transferManager.DownloadAsync(downloadTask);
|
||||
return localFilePath;
|
||||
}
|
||||
catch (CosClientException clientEx)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Foxel.Services.Attributes;
|
||||
using Foxel.Services.Interface;
|
||||
|
||||
namespace Foxel.Services.StorageProvider;
|
||||
|
||||
[StorageProvider(StorageType.Local)]
|
||||
public class LocalStorageProvider(IConfigService config) : IStorageProvider
|
||||
{
|
||||
private readonly string _baseDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Uploads");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Foxel.Services.Attributes;
|
||||
using Foxel.Services.Interface;
|
||||
using Amazon.S3;
|
||||
using Amazon.S3.Model;
|
||||
@@ -5,6 +6,7 @@ using Amazon.S3.Transfer;
|
||||
|
||||
namespace Foxel.Services.StorageProvider;
|
||||
|
||||
[StorageProvider(StorageType.S3)]
|
||||
public class S3StorageProvider : IStorageProvider
|
||||
{
|
||||
private readonly string _accessKey;
|
||||
@@ -13,7 +15,6 @@ public class S3StorageProvider : IStorageProvider
|
||||
private readonly string _region;
|
||||
private readonly string _endpoint;
|
||||
private readonly bool _usePathStyleUrls;
|
||||
private readonly string _serverUrl;
|
||||
private readonly string _cdnUrl;
|
||||
|
||||
public S3StorageProvider(IConfigService configService)
|
||||
@@ -22,9 +23,8 @@ public class S3StorageProvider : IStorageProvider
|
||||
_secretKey = configService["Storage:S3StorageSecretKey"];
|
||||
_bucketName = configService["Storage:S3StorageBucketName"];
|
||||
_region = configService["Storage:S3StorageRegion"];
|
||||
_serverUrl = configService["AppSettings:ServerUrl"];
|
||||
_cdnUrl = configService["Storage:S3StorageCdnUrl"] ?? string.Empty;
|
||||
_endpoint = configService["Storage:S3StorageEndpoint"] ?? $"https://s3.{_region}.amazonaws.com";
|
||||
_cdnUrl = configService["Storage:S3StorageCdnUrl"];
|
||||
_endpoint = configService["Storage:S3StorageEndpoint"];
|
||||
_usePathStyleUrls = bool.TryParse(configService["Storage:S3StorageUsePathStyleUrls"], out var usePathStyle) && usePathStyle;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ public class S3StorageProvider : IStorageProvider
|
||||
};
|
||||
|
||||
using var response = await client.GetObjectAsync(request);
|
||||
using var fileStream = new FileStream(tempFilePath, FileMode.Create);
|
||||
await using var fileStream = new FileStream(tempFilePath, FileMode.Create);
|
||||
await response.ResponseStream.CopyToAsync(fileStream);
|
||||
|
||||
return tempFilePath;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Foxel.Services.Attributes;
|
||||
using Foxel.Services.Interface;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
@@ -5,6 +6,7 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace Foxel.Services.StorageProvider;
|
||||
|
||||
[StorageProvider(StorageType.Telegram)]
|
||||
public class TelegramStorageProvider(IConfigService configService) : IStorageProvider
|
||||
{
|
||||
private readonly string _botToken = configService["Storage:TelegramStorageBotToken"];
|
||||
@@ -83,7 +85,7 @@ public class TelegramStorageProvider(IConfigService configService) : IStoragePro
|
||||
using var httpClient = new HttpClient();
|
||||
var url =
|
||||
$"https://api.telegram.org/bot{_botToken}/deleteMessage?chat_id={metadata.ChatId}&message_id={metadata.MessageId}";
|
||||
var response = await httpClient.GetAsync(url);
|
||||
await httpClient.GetAsync(url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -165,8 +167,8 @@ public class TelegramStorageProvider(IConfigService configService) : IStoragePro
|
||||
string tempFilePath = Path.Combine(tempDir, tempFileName);
|
||||
|
||||
// 保存文件
|
||||
using var fileStream = await fileResponse.Content.ReadAsStreamAsync();
|
||||
using var outputStream = new FileStream(tempFilePath, FileMode.Create);
|
||||
await using var fileStream = await fileResponse.Content.ReadAsStreamAsync();
|
||||
await using var outputStream = new FileStream(tempFilePath, FileMode.Create);
|
||||
await fileStream.CopyToAsync(outputStream);
|
||||
|
||||
return tempFilePath;
|
||||
|
||||
Reference in New Issue
Block a user