This commit is contained in:
@@ -22,6 +22,7 @@ using SharpCompress.Common;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using FellowOakDicom.IO.Buffer;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
@@ -40,9 +41,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
private IServiceProvider _serviceProvider { get; set; }
|
||||
|
||||
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
|
||||
private List<Guid> _SCPStudyIdList => _ImageUploadList.Where(t => t.SCPStudyId != Guid.Empty).Select(t => t.SCPStudyId).ToList();
|
||||
|
||||
private List<string> _StudyInstanceUIdList { get; set; } = new List<string>();
|
||||
private List<ImageUploadInfo> _ImageUploadList { get; set; } = new List<ImageUploadInfo>();
|
||||
|
||||
private SCPImageUpload _upload { get; set; }
|
||||
|
||||
@@ -165,27 +166,48 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
public async Task OnReceiveAssociationReleaseRequestAsync()
|
||||
{
|
||||
await DataMaintenanceAsaync();
|
||||
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||
|
||||
var @lock = _distributedLockProvider.CreateLock($"{_upload.CallingAE}");
|
||||
|
||||
using (await @lock.AcquireAsync())
|
||||
{
|
||||
|
||||
await DataMaintenanceAsaync();
|
||||
|
||||
//记录监控
|
||||
|
||||
await AddUploadLogAsync();
|
||||
|
||||
|
||||
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
|
||||
}
|
||||
|
||||
await SendAssociationReleaseResponseAsync();
|
||||
|
||||
}
|
||||
|
||||
private async Task AddUploadLogAsync()
|
||||
{
|
||||
//记录监控
|
||||
|
||||
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
||||
|
||||
_upload.EndTime = DateTime.Now;
|
||||
_upload.StudyCount = _StudyInstanceUIdList.Count;
|
||||
_upload.StudyCount = _ImageUploadList.Count;
|
||||
_upload.TrialId = _trialId;
|
||||
_upload.TrialSiteId = _trialSiteId;
|
||||
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
|
||||
|
||||
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
|
||||
await SendAssociationReleaseResponseAsync();
|
||||
//可能是测试echo 导致记录了
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, _upload.FileCount > 0 ? true : false);
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +273,11 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
//记录日志
|
||||
await AddUploadLogAsync();
|
||||
}
|
||||
|
||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
||||
}
|
||||
@@ -261,20 +288,22 @@ namespace IRaCIS.Core.SCP.Service
|
||||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||
{
|
||||
|
||||
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID,string.Empty);
|
||||
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
|
||||
string seriesInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
|
||||
string sopInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
|
||||
string patientIdStr = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||
|
||||
if(studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||
if (studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||
{
|
||||
Log.Logger.Error($"接收数据读取StudyInstanceUID:{studyInstanceUid}、SeriesInstanceUID:{seriesInstanceUid}、SOPInstanceUID:{sopInstanceUid}有空 ");
|
||||
|
||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||
}
|
||||
|
||||
if (!_StudyInstanceUIdList.Contains(studyInstanceUid))
|
||||
//确保来了影像集合存在
|
||||
if (!_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||
{
|
||||
_StudyInstanceUIdList.Add(studyInstanceUid);
|
||||
_ImageUploadList.Add(new ImageUploadInfo() { StudyInstanceUid = studyInstanceUid });
|
||||
}
|
||||
|
||||
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
@@ -295,11 +324,70 @@ namespace IRaCIS.Core.SCP.Service
|
||||
long fileSize = 0;
|
||||
try
|
||||
{
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
await request.File.SaveAsync(ms);
|
||||
|
||||
#region 1帧拆成多个固定大小的,方便移动端浏览
|
||||
|
||||
// 回到开头,读取 dicom
|
||||
ms.Position = 0;
|
||||
var dicomFile = DicomFile.Open(ms);
|
||||
|
||||
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||
var syntax = pixelData.Syntax;
|
||||
|
||||
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
|
||||
int fragmentSize = 20 * 1024;
|
||||
|
||||
if (syntax.IsEncapsulated)
|
||||
{
|
||||
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
||||
|
||||
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
||||
{
|
||||
var frameData = pixelData.GetFrame(n); // 获取完整一帧
|
||||
var data = frameData.Data;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < data.Length)
|
||||
{
|
||||
int size = Math.Min(fragmentSize, data.Length - offset);
|
||||
var buffer = new byte[size];
|
||||
Buffer.BlockCopy(data, offset, buffer, 0, size);
|
||||
|
||||
newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
// 替换原 PixelData
|
||||
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||
|
||||
|
||||
// 重新保存 dicom 到流
|
||||
ms.SetLength(0);
|
||||
dicomFile.Save(ms);
|
||||
}
|
||||
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 本地测试
|
||||
//// --- 保存到本地文件测试 ---
|
||||
//var localPath = @"D:\TestDicom.dcm";
|
||||
//using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write))
|
||||
//{
|
||||
// ms.CopyTo(fs);
|
||||
//}
|
||||
//return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//irc 从路径最后一截取Guid
|
||||
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
||||
|
||||
@@ -322,12 +410,8 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
try
|
||||
{
|
||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.File, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
||||
|
||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
||||
{
|
||||
_SCPStudyIdList.Add(scpStudyId);
|
||||
}
|
||||
|
||||
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||
|
||||
@@ -356,12 +440,40 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
|
||||
await _seriesRepository.SaveChangesAsync();
|
||||
|
||||
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||
{
|
||||
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||
|
||||
|
||||
find.SuccessImageCount++;
|
||||
|
||||
if (!find.PatientNameList.Any(t => t == patientIdStr) && patientIdStr.IsNotNullOrEmpty())
|
||||
{
|
||||
find.PatientNameList.Add(patientIdStr);
|
||||
}
|
||||
|
||||
//首次 (默认是Guid 空,数据库归档出了Id)
|
||||
if (find.SCPStudyId != scpStudyId)
|
||||
{
|
||||
find.SCPStudyId = scpStudyId;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
||||
|
||||
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||
{
|
||||
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||
|
||||
find.FailedImageCount++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using IRaCIS.Core.Infra.EFCore;
|
||||
using MassTransit;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Serilog.Sinks.File;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
@@ -52,8 +53,10 @@ namespace IRaCIS.Core.SCP.Service
|
||||
/// <param name="dataset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
||||
{
|
||||
var dataset = dicomFile.Dataset;
|
||||
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
@@ -82,7 +85,7 @@ namespace IRaCIS.Core.SCP.Service
|
||||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
||||
|
||||
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||
if (findPatient == null && findStudy==null)
|
||||
if (findPatient == null /*&& findStudy==null*/)
|
||||
{
|
||||
isPatientNeedAdd = true;
|
||||
|
||||
@@ -151,6 +154,32 @@ namespace IRaCIS.Core.SCP.Service
|
||||
}
|
||||
|
||||
findPatient.LatestPushTime = DateTime.Now;
|
||||
findPatient.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
findPatient.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||
findPatient.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||
findPatient.PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty);
|
||||
|
||||
if (findPatient.PatientBirthDate.Length == 8)
|
||||
{
|
||||
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||||
|
||||
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||||
|
||||
int year = 0;
|
||||
|
||||
var canParse = int.TryParse(yearStr, out year);
|
||||
|
||||
if (canParse && year > 1900)
|
||||
{
|
||||
findPatient.PatientBirthDate = birthDateStr;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
findPatient.PatientBirthDate = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (findStudy == null)
|
||||
@@ -167,6 +196,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
TrialSiteId = trialSiteId,
|
||||
StudyInstanceUid = studyInstanceUid,
|
||||
StudyTime = studyTime,
|
||||
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||
|
||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
//ModalityForEdit = modalityForEdit,
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
@@ -201,6 +233,19 @@ namespace IRaCIS.Core.SCP.Service
|
||||
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
findStudy.DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
|
||||
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
||||
findStudy.CalledAE = calledAE;
|
||||
findStudy.CallingAE = callingAE;
|
||||
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||
findStudy.UpdateTime = DateTime.Now;
|
||||
|
||||
await _patientRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.PatientId, u => new SCPPatient() { LatestPushTime = DateTime.Now });
|
||||
}
|
||||
|
||||
|
||||
if (findSerice == null)
|
||||
@@ -218,6 +263,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
||||
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
||||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||||
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
@@ -239,7 +287,20 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
++findStudy.SeriesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
findSerice.DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty);
|
||||
findSerice.DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty);
|
||||
findSerice.UpdateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
var transferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
|
||||
|
||||
var isEncapsulated = false;
|
||||
if (transferSyntaxUID.IsNotNullOrEmpty())
|
||||
{
|
||||
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
|
||||
}
|
||||
|
||||
if (findInstance == null)
|
||||
{
|
||||
@@ -280,6 +341,15 @@ namespace IRaCIS.Core.SCP.Service
|
||||
++findStudy.InstanceCount;
|
||||
++findSerice.InstanceCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
findInstance.SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
|
||||
findInstance.MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
|
||||
findInstance.TransferSytaxUID = transferSyntaxUID;
|
||||
findInstance.MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
|
||||
findInstance.IsEncapsulated = isEncapsulated;
|
||||
findInstance.UpdateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
if (isPatientNeedAdd)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
public interface IDicomArchiveService
|
||||
{
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user