diff --git a/CHANGELOG.md b/CHANGELOG.md index 8abd1b66..41507201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.7] 2020-08-17 + +### Fixed + +- Allow the PACS to send us lossy compressed versions if it wants, otherwise we won't be able to receive anything it has in that format + +### Added + +- Accept video (MPEG/HEVC) content if the PACS offers it +- Added new cache source `ProcessBasedCacheSource` that calls out to a remote process + ## [2.1.6] 2020-06-17 ### Fixed diff --git a/Packages.md b/Packages.md index 916ed39f..425b02d5 100644 --- a/Packages.md +++ b/Packages.md @@ -10,4 +10,4 @@ | Package | Source Code | Version | License | Purpose | Additional Risk Assessment | | ------- | ------------| --------| ------- | ------- | -------------------------- | | HIC.DicomTypeTranslation | [GitHub](https://github.com/HicServices/DicomTypeTranslation) | [2.3.0](https://www.nuget.org/packages/HIC.DicomTypeTranslation/2.3.0) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html) | Translate dicom types into C# / database types | | -| HIC.RDMP.Plugin | [GitHub](https://github.com/HicServices/RDMP) | [4.1.4](https://www.nuget.org/packages/HIC.RDMP.Plugin/4.1.4) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html) | Interact with RDMP objects, base classes for plugin components etc | | +| HIC.RDMP.Plugin | [GitHub](https://github.com/HicServices/RDMP) | [4.1.7](https://www.nuget.org/packages/HIC.RDMP.Plugin/4.1.7) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html) | Interact with RDMP objects, base classes for plugin components etc | | diff --git a/Plugin/netcoreapp2.2/netcoreapp2.2.csproj b/Plugin/netcoreapp2.2/netcoreapp2.2.csproj index ce0afd5b..dc7d84b5 100644 --- a/Plugin/netcoreapp2.2/netcoreapp2.2.csproj +++ b/Plugin/netcoreapp2.2/netcoreapp2.2.csproj @@ -17,12 +17,12 @@ - + - + diff --git a/Rdmp.Dicom.Library.nuspec b/Rdmp.Dicom.Library.nuspec index 00a39d1a..a7ed2a4e 100644 --- a/Rdmp.Dicom.Library.nuspec +++ b/Rdmp.Dicom.Library.nuspec @@ -14,7 +14,7 @@ Copyright 2018-2019 - + diff --git a/Rdmp.Dicom.Tests/Rdmp.Dicom.Tests.csproj b/Rdmp.Dicom.Tests/Rdmp.Dicom.Tests.csproj index da694188..dbd93a9b 100644 --- a/Rdmp.Dicom.Tests/Rdmp.Dicom.Tests.csproj +++ b/Rdmp.Dicom.Tests/Rdmp.Dicom.Tests.csproj @@ -37,8 +37,8 @@ - - + + diff --git a/Rdmp.Dicom.Tests/TestProcessBasedCacheSource.cs b/Rdmp.Dicom.Tests/TestProcessBasedCacheSource.cs new file mode 100644 index 00000000..231834b5 --- /dev/null +++ b/Rdmp.Dicom.Tests/TestProcessBasedCacheSource.cs @@ -0,0 +1,80 @@ +using MapsDirectlyToDatabaseTable; +using NUnit.Framework; +using Rdmp.Core.Caching.Requests; +using Rdmp.Core.Caching.Requests.FetchRequestProvider; +using Rdmp.Core.Curation; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Curation.Data.Cache; +using Rdmp.Core.DataFlowPipeline; +using Rdmp.Core.Startup; +using Rdmp.Dicom.Cache.Pipeline; +using ReusableLibraryCode.Checks; +using ReusableLibraryCode.Progress; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Tests.Common; + +namespace Rdmp.Dicom.Tests +{ + class TestProcessBasedCacheSource : UnitTests + { + [Test] + public void TestWithEcho() + { + var source = new ProcessBasedCacheSource(); + + if(IsLinux) + { + source.Command = "/bin/echo"; + source.Args = "Hey Thomas go get %s and store in %d"; + } + else + { + source.Command = "cmd.exe"; + source.Args = "/c echo Hey Thomas go get %s and store in %d"; + } + source.TimeFormat = "dd/MM/yy"; + source.ThrowOnNonZeroExitCode = true; + + // What dates to load + var cp = WhenIHaveA(); + cp.CacheFillProgress = new DateTime(2001,12,24); + cp.SaveToDatabase(); + + // Where to put files + var lmd = cp.LoadProgress.LoadMetadata; + + var dir = new DirectoryInfo(TestContext.CurrentContext.WorkDirectory); + var loadDir = LoadDirectory.CreateDirectoryStructure(dir,"blah",true); + + lmd.LocationOfFlatFiles = loadDir.RootPath.FullName; + lmd.SaveToDatabase(); + + source.PreInitialize(new CacheFetchRequestProvider(cp), new ThrowImmediatelyDataLoadEventListener()); + source.PreInitialize(cp.CatalogueRepository,new ThrowImmediatelyDataLoadEventListener()); + source.PreInitialize(new PermissionWindow(cp.CatalogueRepository),new ThrowImmediatelyDataLoadEventListener()); + + var toMem = new ToMemoryDataLoadEventListener(true); + var fork = new ForkDataLoadEventListener(toMem,new ThrowImmediatelyDataLoadEventListener(){WriteToConsole = true}); + + source.GetChunk(fork,new GracefulCancellationToken()); + + Assert.Contains($"Hey Thomas go get 24/12/01 and store in {Path.Combine(loadDir.Cache.FullName,"ALL")}",toMem.GetAllMessagesByProgressEventType()[ProgressEventType.Information].Select(v=>v.Message).ToArray()); + + + + } + + public static bool IsLinux + { + get + { + int p = (int) Environment.OSVersion.Platform; + return (p == 4) || (p == 6) || (p == 128); + } + } + } +} diff --git a/Rdmp.Dicom.UI/CreateNewImagingDatasetUI.cs b/Rdmp.Dicom.UI/CreateNewImagingDatasetUI.cs index 3944fedd..bec0968b 100644 --- a/Rdmp.Dicom.UI/CreateNewImagingDatasetUI.cs +++ b/Rdmp.Dicom.UI/CreateNewImagingDatasetUI.cs @@ -51,23 +51,26 @@ private bool CreateDatabaseIfNotExists(DiscoveredDatabase db) private void btnCreateSuiteWithTemplate_Click(object sender, EventArgs e) { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "Imaging Template|*.it"; + string filename; + using (OpenFileDialog ofd = new OpenFileDialog() + { + Filter = "Imaging Template|*.it" + }) + { + if (ofd.ShowDialog() != DialogResult.OK) + return; + filename = ofd.FileName; + } - if (ofd.ShowDialog() == DialogResult.OK) + try + { + var yaml = File.ReadAllText(filename); + var template = ImageTableTemplateCollection.LoadFrom(yaml); + CreateSuite(template); + } + catch (Exception exception) { - try - { - var yaml = File.ReadAllText(ofd.FileName); - - var template = ImageTableTemplateCollection.LoadFrom(yaml); - - CreateSuite(template); - } - catch (Exception exception) - { - ExceptionViewer.Show(exception); - } + ExceptionViewer.Show(exception); } } @@ -78,17 +81,19 @@ private void CreateSuite(ImageTableTemplateCollection template) if (!CreateDatabaseIfNotExists(db)) return; - - FolderBrowserDialog dialog = new FolderBrowserDialog(); - DirectoryInfo dir = null; - dialog.Description = "Select Project Directory (For Sql scripts/Executables etc)"; - //if we are creating a load we need to know where to store load scripts etc - if(cbCreateLoad.Checked) - if (dialog.ShowDialog() == DialogResult.OK) - dir = new DirectoryInfo(dialog.SelectedPath); - else - return; + DirectoryInfo dir = null; + using (FolderBrowserDialog dialog = new FolderBrowserDialog() { + Description = "Select Project Directory (For Sql scripts/Executables etc)" + }) + { + //if we are creating a load we need to know where to store load scripts etc + if (cbCreateLoad.Checked) + if (dialog.ShowDialog() == DialogResult.OK) + dir = new DirectoryInfo(dialog.SelectedPath); + else + return; + } var cmd = new ExecuteCommandCreateNewImagingDatasetSuite(_activator.RepositoryLocator, db,dir); cmd.DicomSourceType = rbJsonSources.Checked ? typeof(DicomDatasetCollectionSource) : typeof(DicomFileCollectionSource); diff --git a/Rdmp.Dicom.UI/Rdmp.Dicom.UI.csproj b/Rdmp.Dicom.UI/Rdmp.Dicom.UI.csproj index 9d8670be..174c5f80 100644 --- a/Rdmp.Dicom.UI/Rdmp.Dicom.UI.csproj +++ b/Rdmp.Dicom.UI/Rdmp.Dicom.UI.csproj @@ -12,7 +12,7 @@ - + diff --git a/Rdmp.Dicom.UI/TagElevationXmlUI.cs b/Rdmp.Dicom.UI/TagElevationXmlUI.cs index c1d7dbc8..78dc168e 100644 --- a/Rdmp.Dicom.UI/TagElevationXmlUI.cs +++ b/Rdmp.Dicom.UI/TagElevationXmlUI.cs @@ -84,7 +84,7 @@ private void RunChecks() try { - var collection = new TagElevationRequestCollection(queryEditor.Text); + new TagElevationRequestCollection(queryEditor.Text); RagSmiley1.OnCheckPerformed(new CheckEventArgs("Succesfully created elevator",CheckResult.Success)); } catch(Exception ex) diff --git a/Rdmp.Dicom/Attachers/Routing/AutoRoutingAttacher.cs b/Rdmp.Dicom/Attachers/Routing/AutoRoutingAttacher.cs index d31036bd..787c4770 100644 --- a/Rdmp.Dicom/Attachers/Routing/AutoRoutingAttacher.cs +++ b/Rdmp.Dicom/Attachers/Routing/AutoRoutingAttacher.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text.RegularExpressions; using FAnsi.Implementations.MySql; -using MySql.Data.MySqlClient; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.DataLoad; using Rdmp.Core.Curation.Data.Pipelines; @@ -171,9 +170,6 @@ public IPipelineUseCase GetDesignTimePipelineUseCase(RequiredPropertyInfo proper #region Process Results Of Pipeline Read public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener,GracefulCancellationToken cancellationToken) { - - //todo: This really shouldn't be needed surely - MySqlConnection.ClearAllPools(); MySqlBulkCopy.BulkInsertBatchTimeoutInSeconds = int.MaxValue; //forever _sw.Start(); diff --git a/Rdmp.Dicom/Cache/Pipeline/CachingSCP.cs b/Rdmp.Dicom/Cache/Pipeline/CachingSCP.cs index a049e66e..931c72d4 100644 --- a/Rdmp.Dicom/Cache/Pipeline/CachingSCP.cs +++ b/Rdmp.Dicom/Cache/Pipeline/CachingSCP.cs @@ -27,6 +27,23 @@ public class CachingSCP : DicomService, IDicomServiceProvider, IDicomCStoreProvi DicomTransferSyntax.JPEGProcess14SV1, DicomTransferSyntax.JPEGProcess14, DicomTransferSyntax.RLELossless, + + // Lossy - if that's all the PACS has, that's all it can give us + DicomTransferSyntax.JPEGLSNearLossless, + DicomTransferSyntax.JPEG2000Lossy, + DicomTransferSyntax.JPEGProcess1, + DicomTransferSyntax.JPEGProcess2_4, + + // Also allow video files, just in case + DicomTransferSyntax.HEVCH265Main10ProfileLevel51, + DicomTransferSyntax.HEVCH265MainProfileLevel51, + DicomTransferSyntax.MPEG2, + DicomTransferSyntax.MPEG2MainProfileHighLevel, + DicomTransferSyntax.MPEG4AVCH264BDCompatibleHighProfileLevel41, + DicomTransferSyntax.MPEG4AVCH264HighProfileLevel41, + DicomTransferSyntax.MPEG4AVCH264HighProfileLevel42For2DVideo, + DicomTransferSyntax.MPEG4AVCH264HighProfileLevel42For3DVideo, + DicomTransferSyntax.MPEG4AVCH264StereoHighProfileLevel42, // Uncompressed DicomTransferSyntax.ExplicitVRLittleEndian, diff --git a/Rdmp.Dicom/Cache/Pipeline/Dicom/DicomRequestSender.cs b/Rdmp.Dicom/Cache/Pipeline/Dicom/DicomRequestSender.cs index 13a96f96..5330efa4 100644 --- a/Rdmp.Dicom/Cache/Pipeline/Dicom/DicomRequestSender.cs +++ b/Rdmp.Dicom/Cache/Pipeline/Dicom/DicomRequestSender.cs @@ -70,7 +70,7 @@ public void ThrottleRequest(DicomClient client, CancellationToken cancellationTo SendRequest(client,cancellationToken); transferTimer.Stop(); //valuein mills - var delay = ((int)(_dicomConfiguration.RequestDelayFactor * (1000 * transferTimer.Elapsed.Seconds)) + _dicomConfiguration.RequestCooldownInMilliseconds); + var delay = ((int)(_dicomConfiguration.RequestDelayFactor * (1000f * transferTimer.Elapsed.Seconds)) + _dicomConfiguration.RequestCooldownInMilliseconds); if (delay > 0) { _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Requests sleeping for " + delay / 1000 + "seconds")); diff --git a/Rdmp.Dicom/Cache/Pipeline/Ordering/HierarchyBasedOrder.cs b/Rdmp.Dicom/Cache/Pipeline/Ordering/HierarchyBasedOrder.cs index ff09f457..e40eaa99 100644 --- a/Rdmp.Dicom/Cache/Pipeline/Ordering/HierarchyBasedOrder.cs +++ b/Rdmp.Dicom/Cache/Pipeline/Ordering/HierarchyBasedOrder.cs @@ -411,10 +411,7 @@ public int Total() { foreach (var series in study.Series.Values) { - foreach (var image in series.Images.Values) - { - count++; - } + count += series.Images.Values.Count; } } } diff --git a/Rdmp.Dicom/Cache/Pipeline/ProcessBasedCacheSource.cs b/Rdmp.Dicom/Cache/Pipeline/ProcessBasedCacheSource.cs new file mode 100644 index 00000000..29e8b8c8 --- /dev/null +++ b/Rdmp.Dicom/Cache/Pipeline/ProcessBasedCacheSource.cs @@ -0,0 +1,106 @@ +using Rdmp.Core.Caching.Pipeline.Sources; +using Rdmp.Core.Caching.Requests; +using Rdmp.Core.Curation; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.DataFlowPipeline; +using ReusableLibraryCode.Checks; +using ReusableLibraryCode.Progress; +using System; +using System.Diagnostics; + +namespace Rdmp.Dicom.Cache.Pipeline +{ + public class ProcessBasedCacheSource : CacheSource + { + [DemandsInitialization(@"Process to start (path only)",Mandatory = true)] + public string Command {get;set;} + + [DemandsInitialization(@"Arguments to provide to the Process. Template with +%s start time +%e end time time to fetch +%d directory to put files fetched +Example:. './GetImages.exe ""%s"" ""%e%""'")] + public string Args {get;set;} + + [DemandsInitialization("The datetime format for %s and %e.",Mandatory = true,DefaultValue = "yyyy-MM-dd HH:mm:ss")] + public string TimeFormat {get;set;} + + [DemandsInitialization("True to throw an Exception if the process run returns a nonzero exit code", DefaultValue = true)] + public bool ThrowOnNonZeroExitCode {get;set;} + + public override void Abort(IDataLoadEventListener listener) + { + + } + + public override void Check(ICheckNotifier notifier) + { + + } + + public override void Dispose(IDataLoadEventListener listener, Exception pipelineFailureExceptionIfAny) + { + + } + + public override SMIDataChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) + { + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,$"ProcessBasedCacheSource version is {typeof(ProcessBasedCacheSource).Assembly.GetName().Version}. Assembly is {typeof(ProcessBasedCacheSource).Assembly} " )); + + // Where we are putting the files + var cacheDir = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache; + var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver("ALL")); + + Chunk = new SMIDataChunk(Request) + { + FetchDate = Request.Start, + Modality = "ALL", + Layout = cacheLayout + }; + + var workingDirectory = cacheLayout.GetLoadCacheDirectory(listener); + + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Working directory is:" + workingDirectory)); + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Fetch Start is:" + request.Start)); + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Fetch End is:" + request.End)); + + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Command is:" + Command)); + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Args template is:" + Args)); + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Datetime format is:" + TimeFormat)); + + + string args = Args + .Replace("%s",request.Start.ToString(TimeFormat)) + .Replace("%e",request.End.ToString(TimeFormat)) + .Replace("%d",workingDirectory.FullName); + + listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,"Args resolved is:" + args)); + + using(var p = new Process()) + { + p.StartInfo.FileName = Command; + p.StartInfo.Arguments = args; + p.StartInfo.UseShellExecute = false; + p.StartInfo.RedirectStandardOutput = true; + p.OutputDataReceived += (sender, a) => listener.OnNotify(this,new NotifyEventArgs(ProgressEventType.Information,a.Data)); + + p.Start(); + p.BeginOutputReadLine(); + + p.WaitForExit(); + + listener.OnNotify(this,new NotifyEventArgs( p.ExitCode == 0 ? ProgressEventType.Information : ProgressEventType.Warning , "Process exited with code " + p.ExitCode)); + + if(p.ExitCode != 0 && ThrowOnNonZeroExitCode) + throw new Exception("Process exited with code " + p.ExitCode); + } + + return Chunk; + } + + public override SMIDataChunk TryGetPreview() + { + return null; + } + } +} diff --git a/Rdmp.Dicom/CommandExecution/ExecuteCommandCreateNewImagingDatasetSuite.cs b/Rdmp.Dicom/CommandExecution/ExecuteCommandCreateNewImagingDatasetSuite.cs index 31db50ba..4f811faf 100644 --- a/Rdmp.Dicom/CommandExecution/ExecuteCommandCreateNewImagingDatasetSuite.cs +++ b/Rdmp.Dicom/CommandExecution/ExecuteCommandCreateNewImagingDatasetSuite.cs @@ -113,9 +113,11 @@ bool createLoad public override void Execute() { if (DicomSourceType == null) + { SetImpossible("You must specify a Type for DicomSourceType"); + throw new ImpossibleCommandException(this, ReasonCommandImpossible); + } - base.Execute(); List tablesCreated = new List(); @@ -258,12 +260,16 @@ private string GetNameWithPrefix(string name) private void SetArgument(IArgument[] args, string property, object value) { + if (value == null) + throw new ArgumentNullException(nameof(value)); + var arg = args.Single(a => a.Name.Equals(property)); var mef = ((CatalogueRepository) arg.Repository).MEF; - var found = mef.GetType(value.GetType().FullName); + if (mef.GetType(value.GetType().FullName) == null) + throw new ArgumentException($"No type found for { value.GetType().FullName }"); - //if this fails, look to see if found is null (indicates that your Type is not loaded by MEF). Look at mef.DescribeBadAssembliesIfAny() to investigate this issue + //if this fails, look to see if GetType returned null (indicates that your Type is not loaded by MEF). Look at mef.DescribeBadAssembliesIfAny() to investigate this issue arg.SetValue(value); arg.SaveToDatabase(); } diff --git a/Rdmp.Dicom/Extraction/MappingRepository.cs b/Rdmp.Dicom/Extraction/MappingRepository.cs index ae29b662..acdc3999 100644 --- a/Rdmp.Dicom/Extraction/MappingRepository.cs +++ b/Rdmp.Dicom/Extraction/MappingRepository.cs @@ -98,32 +98,34 @@ public void InsertMappings(UIDMapping[] newMappings) var table = _database.ExpectTable(_tableName); // Create data table - var dt = new DataTable(_tableName); - using (var conn = (SqlConnection) _server.GetConnection()) + using (var dt = new DataTable(_tableName)) { - conn.Open(); - var da = new SqlDataAdapter(table.GetTopXSql(0), conn); - da.Fill(dt); - } + using (var conn = (SqlConnection)_server.GetConnection()) + { + conn.Open(); + using (var da = new SqlDataAdapter(table.GetTopXSql(0), conn)) + da.Fill(dt); + } - // Fill up the data table - foreach (var mapping in newMappings) - { - var row = dt.NewRow(); - row["PrivateUID"] = mapping.PrivateUID; - row["ReleaseUID"] = mapping.ReleaseUID; - row["ProjectNumber"] = mapping.ProjectNumber; - row["UIDType"] = mapping.UIDType; - row["IsExternalReference"] = mapping.IsExternalReference; - dt.Rows.Add(row); - } + // Fill up the data table + foreach (var mapping in newMappings) + { + var row = dt.NewRow(); + row["PrivateUID"] = mapping.PrivateUID; + row["ReleaseUID"] = mapping.ReleaseUID; + row["ProjectNumber"] = mapping.ProjectNumber; + row["UIDType"] = mapping.UIDType; + row["IsExternalReference"] = mapping.IsExternalReference; + dt.Rows.Add(row); + } - // Perform the bulk copy - using (var conn = (SqlConnection) _server.GetConnection()) - { - conn.Open(); - using (var bulkCopy = table.BeginBulkInsert()) - bulkCopy.Upload(dt); + // Perform the bulk copy + using (var conn = (SqlConnection)_server.GetConnection()) + { + conn.Open(); + using (var bulkCopy = table.BeginBulkInsert()) + bulkCopy.Upload(dt); + } } } diff --git a/Rdmp.Dicom/PipelineComponents/DicomSources/DicomFileCollectionSource.cs b/Rdmp.Dicom/PipelineComponents/DicomSources/DicomFileCollectionSource.cs index a2e5c7af..3ff63eba 100644 --- a/Rdmp.Dicom/PipelineComponents/DicomSources/DicomFileCollectionSource.cs +++ b/Rdmp.Dicom/PipelineComponents/DicomSources/DicomFileCollectionSource.cs @@ -64,30 +64,33 @@ public override DataTable GetChunk(IDataLoadEventListener listener, GracefulCanc if (!_fileWorklist.GetNextFileOrDirectoryToProcess(out directory, out file)) return null; - if(file != null && directory == null) - dt.TableName = QuerySyntaxHelper.MakeHeaderNameSensible(Path.GetFileNameWithoutExtension(file.FullPath)); - else if (directory != null) - dt.TableName = QuerySyntaxHelper.MakeHeaderNameSensible(Path.GetFileNameWithoutExtension(directory.Name)); - else + // Exactly one of file/directory must be null: + if ((file!=null) == (directory!=null)) throw new Exception("Expected IDicomProcessListProvider to return either a DirectoryInfo or a FileInfo not both/neither"); - - if(directory != null) - { - ProcessDirectoryAsync(dt, directory, listener); - Task.WaitAll(tasks.ToArray()); - } - else - //Input is a single zip file - if (file.FullPath.EndsWith(".zip")) + + if (file != null) { - ProcessZipArchive(dt, listener, file.FullPath); + dt.TableName = QuerySyntaxHelper.MakeHeaderNameSensible(Path.GetFileNameWithoutExtension(file.FullPath)); + if (file.FullPath.EndsWith(".zip")) + { + //Input is a single zip file + ProcessZipArchive(dt, listener, file.FullPath); + } + else + { + var df = file.GetDataset(_zipPool); + ProcessDataset(file.FullPath, df.Dataset, dt, listener); + } } - else + + if (directory!=null) { - var df = file.GetDataset(_zipPool); - ProcessDataset(file.FullPath, df.Dataset, dt, listener); + // Processing a directory + dt.TableName = QuerySyntaxHelper.MakeHeaderNameSensible(Path.GetFileNameWithoutExtension(directory.Name)); + ProcessDirectoryAsync(dt, directory, listener); + Task.WaitAll(tasks.ToArray()); } - + } finally { diff --git a/Rdmp.Dicom/PipelineComponents/PrimaryKeyCollisionIsolationMutilation.cs b/Rdmp.Dicom/PipelineComponents/PrimaryKeyCollisionIsolationMutilation.cs index 8c942b16..39fba540 100644 --- a/Rdmp.Dicom/PipelineComponents/PrimaryKeyCollisionIsolationMutilation.cs +++ b/Rdmp.Dicom/PipelineComponents/PrimaryKeyCollisionIsolationMutilation.cs @@ -60,10 +60,11 @@ public void Check(ICheckNotifier notifier) //if there are multiple tables then we must know how to join them if (TablesToIsolate.Length >1 && TablesToIsolate.Count(t => t.IsPrimaryExtractionTable) != 1) { + var primaryTables = TablesToIsolate.Where(t => t.IsPrimaryExtractionTable).ToArray(); + notifier.OnCheckPerformed( new CheckEventArgs( - "There are " + TablesToIsolate.Length + - " tables to operate on but none are marked IsPrimaryExtractionTable. This should be set on the top level table e.g. Study", + $"There are {TablesToIsolate.Length} tables to operate on but {primaryTables.Length} are marked IsPrimaryExtractionTable ({string.Join(",",primaryTables.Select(t=>t.Name))}). This should be set on a single top level table only e.g. Study", CheckResult.Fail)); } diff --git a/Rdmp.Dicom/Rdmp.Dicom.csproj b/Rdmp.Dicom/Rdmp.Dicom.csproj index e9a44202..63ef5a5f 100644 --- a/Rdmp.Dicom/Rdmp.Dicom.csproj +++ b/Rdmp.Dicom/Rdmp.Dicom.csproj @@ -26,6 +26,6 @@ - + diff --git a/Rdmp.Dicom/TagPromotionSchema/TagColumnAdder.cs b/Rdmp.Dicom/TagPromotionSchema/TagColumnAdder.cs index 8ee231e0..b5563482 100644 --- a/Rdmp.Dicom/TagPromotionSchema/TagColumnAdder.cs +++ b/Rdmp.Dicom/TagPromotionSchema/TagColumnAdder.cs @@ -83,7 +83,7 @@ public void Check(ICheckNotifier notifier) try { var cSharpType = db.Server.GetQuerySyntaxHelper().TypeTranslater.GetCSharpTypeForSQLDBType(_datatype); - notifier.OnCheckPerformed(new CheckEventArgs("Datatype is compatible with TypeTranslater",CheckResult.Success)); + notifier.OnCheckPerformed(new CheckEventArgs($"Datatype { _datatype } is compatible with TypeTranslater as { cSharpType }",CheckResult.Success)); } catch (Exception ex) { diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index b0952eb9..15c35b7e 100644 --- a/SharedAssemblyInfo.cs +++ b/SharedAssemblyInfo.cs @@ -7,6 +7,6 @@ [assembly: AssemblyCulture("")] // These should be replaced with correct values by the release process -[assembly: AssemblyVersion("2.1.6")] -[assembly: AssemblyFileVersion("2.1.6")] -[assembly: AssemblyInformationalVersion("2.1.6")] +[assembly: AssemblyVersion("2.1.7")] +[assembly: AssemblyFileVersion("2.1.7")] +[assembly: AssemblyInformationalVersion("2.1.7")]