From 84d08c037878c906e15d81070164df45ccd7e62f Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Mon, 15 Sep 2025 17:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=88=A0=E9=99=A4=E6=A0=87?= =?UTF-8?q?=E8=AE=B0=E6=96=B9=E6=B3=95=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IRaCIS.Core.Application/TestService.cs | 211 ++++++++++++++++++++++++- 1 file changed, 208 insertions(+), 3 deletions(-) diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index 9b29f6f71..634ad7f0d 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -1,5 +1,6 @@ using Aliyun.OSS; using DocumentFormat.OpenXml.Spreadsheet; +using FellowOakDicom; using FellowOakDicom.Imaging; using IRaCIS.Application.Contracts; using IRaCIS.Core.Application.BusinessFilter; @@ -15,7 +16,9 @@ using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure.Encryption; using IRaCIS.Core.Infrastructure.NewtonsoftJson; using MassTransit; +using MassTransit.Caching.Internals; using MassTransit.Mediator; +using MathNet.Numerics; using MaxMind.GeoIP2; using Medallion.Threading; using Microsoft.AspNetCore.Authorization; @@ -27,18 +30,22 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MiniExcelLibs; +using Minio.DataModel; using NPOI.SS.Formula.Functions; using NPOI.XWPF.UserModel; using SharpCompress.Common; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Processing; +using System.Collections.Concurrent; +using System.Diagnostics; using System.Globalization; using System.Linq.Dynamic.Core; using System.Reactive.Subjects; using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Text; +using static IRaCIS.Core.Domain.Share.StaticData; @@ -136,7 +143,7 @@ namespace IRaCIS.Core.Application.Service { if (!_readingMedicineSystemQuestion.Any(t => t.CriterionTypeEnum == CriterionType.mRECISTHCC)) { - var list = _readingMedicineSystemQuestion.Where(t => t.CriterionTypeEnum == CriterionType.RECIST1Point1).OrderBy(t=>t.ShowOrder).ToList(); + var list = _readingMedicineSystemQuestion.Where(t => t.CriterionTypeEnum == CriterionType.RECIST1Point1).OrderBy(t => t.ShowOrder).ToList(); var initOrder = 500; foreach (var item in list) @@ -151,10 +158,10 @@ namespace IRaCIS.Core.Application.Service initOrder = initOrder + 1; } - await _readingMedicineSystemQuestion.AddRangeAsync(list,true); + await _readingMedicineSystemQuestion.AddRangeAsync(list, true); } - + return ResponseOutput.Ok(); } @@ -365,6 +372,204 @@ namespace IRaCIS.Core.Application.Service } + [AllowAnonymous] + public async Task RestoreDBOSSDate( + [FromServices] IOSSService _oSSService, [FromServices] IWebHostEnvironment _hostEnvironment, [FromServices] IRepository _studyRepository) + { + var folder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment); + + var outputFile = Path.Combine(folder, $"{Guid.NewGuid()}_deleteKey_info.txt"); + + var outputErrorFile = Path.Combine(folder, $"{Guid.NewGuid()}_deleteKeyerror.txt"); + var outputErrorFile2 = Path.Combine(folder, $"{Guid.NewGuid()}_deleteKeyerrorStudy.txt"); + + + var aliConfig = _oSSService.ObjectStoreServiceOptions.AliyunOSS; + + var tempToken = _oSSService.GetObjectStoreTempToken(); + + var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, + tempToken.AliyunOSS.AccessKeyId, + tempToken.AliyunOSS.AccessKeySecret, + tempToken.AliyunOSS.SecurityToken); + + + var allVersions = new List(); + var allDeleteMarkers = new List(); + + var request = new ListObjectVersionsRequest(tempToken.AliyunOSS.BucketName) + { + Prefix = "01000000-ac13-0242-6397-08dcd2d2a091/Image", + //Prefix = "01000000-ac13-0242-6397-08dcd2d2a091/Image/08dd9c04-c1b2-c2da-0242-ac1301000000/01000000-ac13-0242-235b-08dd9c04c1b3", + MaxKeys = 1000, + }; + + ObjectVersionList result; + do + { + + //var tt = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName) + //{ + // Prefix = "01000000-ac13-0242-6397-08dcd2d2a091/Image/08dd9c04-c1b2-c2da-0242-ac1301000000/01000000-ac13-0242-235b-08dd9c04c1b3", // 根目录,留空即可 + // MaxKeys = 100, + //}); + + result = _ossClient.ListObjectVersions(request); + + if (result.ObjectVersionSummaries != null) + allVersions.AddRange(result.ObjectVersionSummaries); + + if (result.DeleteMarkerSummaries != null) + allDeleteMarkers.AddRange(result.DeleteMarkerSummaries); + + request.KeyMarker = result.NextKeyMarker; + request.VersionIdMarker = result.NextVersionIdMarker; + + } while (result.IsTruncated); + + Console.WriteLine($"共找到 {allDeleteMarkers.Count} 个删除标记"); + + + + int total = allDeleteMarkers.Count; + + int processed = 0; + double lastPercent = 0; + + + // 按 Key 分组,找每个删除标记前的最近版本 + var versionsByKey = allVersions + .GroupBy(v => v.Key) + .ToDictionary(g => g.Key, g => g.OrderByDescending(x => x.LastModified).ToList()); + + foreach (var del in allDeleteMarkers) + { + #region 防止阿里云过期 + if (tempToken.AliyunOSS.Expiration.AddSeconds(10) <= DateTime.Now) + { + tempToken = _oSSService.GetObjectStoreTempToken(); + + _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, + tempToken.AliyunOSS.AccessKeyId, + tempToken.AliyunOSS.AccessKeySecret, + tempToken.AliyunOSS.SecurityToken); + } + + #endregion + + if (!versionsByKey.TryGetValue(del.Key, out var versions)) + continue; // 没有历史版本无法恢复 + + var prevVersion = versions.FirstOrDefault(v => v.LastModified < del.LastModified); + if (prevVersion == null) + continue; // 没找到可恢复版本 + + + var localPath = Path.Combine(folder, prevVersion.Key.Trim('/').Replace('/', Path.DirectorySeparatorChar)); + Directory.CreateDirectory(Path.GetDirectoryName(localPath)); + + + try + { + await File.AppendAllTextAsync(outputFile, $"{prevVersion.Key},{prevVersion.VersionId}" + Environment.NewLine); + + var getReq = new GetObjectRequest(tempToken.AliyunOSS.BucketName, prevVersion.Key) + { + VersionId = prevVersion.VersionId + }; + + using (var getResult = _ossClient.GetObject(getReq)) + using (var memStream = new MemoryStream()) + { + // 先把 OSS 流复制到内存流 + getResult.Content.CopyTo(memStream); + memStream.Position = 0; + + // 读取 DICOM 信息 + var dicomFile = DicomFile.Open(memStream); + var studyInstanceUID = dicomFile.Dataset.GetString(DicomTag.StudyInstanceUID); + + var findInfo = await _studyRepository.Where(t => t.StudyInstanceUid == studyInstanceUID && t.TrialId == Guid.Parse("01000000-ac13-0242-6397-08dcd2d2a091")) + .Select(t => new { t.StudyInstanceUid, t.Subject.Code, t.SubjectVisit.VisitName }).FirstOrDefaultAsync(); + + if (findInfo != null) + { + + // 再保存到另一个路径(可以使用 fo-dicom 保存) + var anotherPath = Path.Combine(folder, findInfo.Code, findInfo.VisitName, studyInstanceUID); + Directory.CreateDirectory(Path.GetDirectoryName(anotherPath)); + dicomFile.Save(anotherPath); + } + else + { + await File.AppendAllTextAsync(outputErrorFile2, $"{studyInstanceUID},{prevVersion.Key},{prevVersion.VersionId}" + Environment.NewLine); + } + + Console.WriteLine($"读取到 studyInstanceUID: {studyInstanceUID}"); + + // 保存到原本路径 + memStream.Position = 0; + using (var fs = File.Create(localPath)) + { + memStream.CopyTo(fs); + } + + + } + + + + Console.WriteLine($"✅ 下载成功: {prevVersion.Key} (version={prevVersion.VersionId})"); + } + catch (Exception ex) + { + Console.WriteLine($"❌ 下载失败: {prevVersion.Key}, 错误: {ex.Message}"); + + await File.AppendAllTextAsync(outputErrorFile, $"{prevVersion.Key},{prevVersion.VersionId}" + Environment.NewLine); + } + finally + { + processed++; + double percent = processed * 100.0 / total; + + // 每提升 5% 或完成时输出 + if (percent - lastPercent >= 2.0 || processed == total) + { + lastPercent = percent; + Console.WriteLine($"{DateTime.Now} 进度: {processed}/{total} ({percent:F2}%)"); + } + } + + + // 使用 CopyObject 把历史版本拷贝为最新版本(恢复) + //var copyReq = new CopyObjectRequest + //{ + // Bucket = bucketName, + // Key = prevVersion.Key, + // SourceBucket = bucketName, + // SourceKey = prevVersion.Key, + // SourceVersionId = prevVersion.VersionId + //}; + + //try + //{ + // var copyResult = client.CopyObject(copyReq); + // Console.WriteLine($"✅ 恢复成功: {prevVersion.Key} -> newVersionId={copyResult.VersionId}"); + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"❌ 恢复失败: {prevVersion.Key}, 错误: {ex.Message}"); + //} + } + + + + return ResponseOutput.Ok(); + } + + + + [AllowAnonymous] public async Task UserCreateSourceDeal([FromServices] IRepository _identityUserRepository, [FromServices] IRepository _trialUserRoleRepository)