using Aliyun.OSS; using IRaCIS.Core.Infrastructure; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Minio.DataModel.Args; using Minio; using SharpCompress.Common; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Security.AccessControl; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Text.Json.Serialization; using Minio.ApiEndpoints; using System.Reactive.Linq; using IRaCIS.Core.Domain.Share; using static MassTransit.ValidationResultExtensions; using IRaCIS.Core.Infrastructure.NewtonsoftJson; namespace IRaCIS.Core.Application.Helper { [LowerCamelCaseJson] public class MinIOOptions : AWSOptions { public int Port { get; set; } } [LowerCamelCaseJson] public class AWSOptions { public string EndPoint { get; set; } public bool UseSSL { get; set; } public string AccessKey { get; set; } public string SecretKey { get; set; } public string BucketName { get; set; } public string ViewEndpoint { get; set; } } public class AliyunOSSOptions { public string RegionId { get; set; } public string AccessKeyId { get; set; } public string AccessKeySecret { get; set; } public string InternalEndpoint { get; set; } public string EndPoint { get; set; } public string BucketName { get; set; } public string RoleArn { get; set; } public string Region { get; set; } public string ViewEndpoint { get; set; } public int DurationSeconds { get; set; } } public class ObjectStoreServiceOptions { public string ObjectStoreUse { get; set; } public AliyunOSSOptions AliyunOSS { get; set; } public MinIOOptions MinIO { get; set; } public AWSOptions AWS { get; set; } } public class ObjectStoreDTO { public string ObjectStoreUse { get; set; } public AliyunOSSTempToken AliyunOSS { get; set; } public MinIOOptions MinIO { get; set; } public AWSOptions AWS { get; set; } } [LowerCamelCaseJson] public class AliyunOSSTempToken { public string AccessKeyId { get; set; } public string AccessKeySecret { get; set; } public string EndPoint { get; set; } public string BucketName { get; set; } public string Region { get; set; } public string ViewEndpoint { get; set; } public string SecurityToken { get; set; } public string Expiration { get; set; } } public enum ObjectStoreUse { AliyunOSS = 0, MinIO = 1, AWS = 2, } public interface IOSSService { public Task UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true); public Task UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true); public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath); public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; } public Task GetSignedUrl(string ossRelativePath); public Task DeleteFromPrefix(string prefix); } public class OSSService : IOSSService { public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; } public OSSService(IOptionsMonitor options) { ObjectStoreServiceOptions = options.CurrentValue; } /// /// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder /// /// /// /// /// /// public async Task UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true) { var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}"; //var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}"; //var ossRelativePath = oosFolderPath + "/" + fileRealName; try { using (var memoryStream = new MemoryStream()) { fileStream.Seek(0, SeekOrigin.Begin); fileStream.CopyTo(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS") { var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, aliConfig.AccessKeyId, aliConfig.AccessKeySecret); // 上传文件 var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, memoryStream); } else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") { var minIOConfig = ObjectStoreServiceOptions.MinIO; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var putObjectArgs = new PutObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithStreamData(memoryStream) .WithObjectSize(memoryStream.Length); await minioClient.PutObjectAsync(putObjectArgs); } else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS") { var minIOConfig = ObjectStoreServiceOptions.AWS; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var putObjectArgs = new PutObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithStreamData(memoryStream) .WithObjectSize(memoryStream.Length); await minioClient.PutObjectAsync(putObjectArgs); } else { throw new BusinessValidationFailedException("未定义的存储介质类型"); } } } catch (Exception ex) { throw new BusinessValidationFailedException($"上传发生异常:{ex.Message}"); } return "/" + ossRelativePath; } /// /// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder /// /// /// /// /// public async Task UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true) { var localFileName = Path.GetFileName(localFilePath); var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}"; //var ossRelativePath = oosFolderPath + "/" + localFileName; if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS") { var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, aliConfig.AccessKeyId, aliConfig.AccessKeySecret); // 上传文件 var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, localFilePath); } else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") { var minIOConfig = ObjectStoreServiceOptions.MinIO; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var putObjectArgs = new PutObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithFileName(localFilePath); await minioClient.PutObjectAsync(putObjectArgs); } else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS") { var minIOConfig = ObjectStoreServiceOptions.AWS; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var putObjectArgs = new PutObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithFileName(localFilePath); await minioClient.PutObjectAsync(putObjectArgs); } else { throw new BusinessValidationFailedException("未定义的存储介质类型"); } return "/" + ossRelativePath; } public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath) { ossRelativePath = ossRelativePath.TrimStart('/'); try { if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS") { var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, aliConfig.AccessKeyId, aliConfig.AccessKeySecret); // 上传文件 var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath); // 将下载的文件流保存到本地文件 using (var fs = File.OpenWrite(localFilePath)) { result.Content.CopyTo(fs); fs.Close(); } } else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") { var minIOConfig = ObjectStoreServiceOptions.MinIO; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var getObjectArgs = new GetObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithFile(localFilePath); await minioClient.GetObjectAsync(getObjectArgs); } else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS") { var minIOConfig = ObjectStoreServiceOptions.AWS; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var getObjectArgs = new GetObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithFile(localFilePath); await minioClient.GetObjectAsync(getObjectArgs); } else { throw new BusinessValidationFailedException("未定义的存储介质类型"); } } catch (Exception ex) { throw new BusinessValidationFailedException("oss下载失败!" + ex.Message); } } public async Task GetSignedUrl(string ossRelativePath) { ossRelativePath = ossRelativePath.TrimStart('/'); try { if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS") { var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, aliConfig.AccessKeyId, aliConfig.AccessKeySecret); // 生成签名URL。 var req = new GeneratePresignedUriRequest(aliConfig.BucketName, ossRelativePath, SignHttpMethod.Get) { // 设置签名URL过期时间,默认值为3600秒。 Expiration = DateTime.Now.AddHours(1), }; var uri = _ossClient.GeneratePresignedUri(req); return uri.PathAndQuery; } else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") { var minIOConfig = ObjectStoreServiceOptions.MinIO; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var args = new PresignedGetObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithExpiry(3600) /*.WithHeaders(reqParams)*/; var presignedUrl = await minioClient.PresignedGetObjectAsync(args); Uri uri = new Uri(presignedUrl); string relativePath = uri.PathAndQuery; return relativePath; } else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS") { var minIOConfig = ObjectStoreServiceOptions.AWS; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var args = new PresignedGetObjectArgs() .WithBucket(minIOConfig.BucketName) .WithObject(ossRelativePath) .WithExpiry(3600); var presignedUrl = await minioClient.PresignedGetObjectAsync(args); Uri uri = new Uri(presignedUrl); string relativePath = uri.PathAndQuery; return relativePath; } else { throw new BusinessValidationFailedException("未定义的存储介质类型"); } } catch (Exception ex) { throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message); } } /// /// 删除某个目录的文件 /// /// /// public async Task DeleteFromPrefix(string prefix) { if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS") { var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, aliConfig.AccessKeyId, aliConfig.AccessKeySecret); try { ObjectListing objectListing = null; string nextMarker = null; do { // 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker objectListing = _ossClient.ListObjects(new ListObjectsRequest(aliConfig.BucketName) { Prefix = prefix, MaxKeys = 1000, Marker = nextMarker }); List keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList(); // 删除获取到的文件 if (keys.Count > 0) { _ossClient.DeleteObjects(new DeleteObjectsRequest(aliConfig.BucketName, keys, false)); } // 设置 NextMarker 以获取下一页的数据 nextMarker = objectListing.NextMarker; } while (objectListing.IsTruncated); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") { var minIOConfig = ObjectStoreServiceOptions.MinIO; var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}") .WithCredentials(minIOConfig.AccessKey, minIOConfig.SecretKey).WithSSL(minIOConfig.UseSSL) .Build(); var listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true); var objects = minioClient.ListObjectsAsync(listArgs).ToListObservable().Select(t => t.Key).ToList(); if (objects.Count > 0) { var objArgs = new RemoveObjectsArgs() .WithBucket(minIOConfig.BucketName) .WithObjects(objects); // 删除对象 await minioClient.RemoveObjectsAsync(objArgs); } } else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS") { throw new BusinessValidationFailedException("未定义的存储介质类型"); } else { throw new BusinessValidationFailedException("未定义的存储介质类型"); } } } }