changeset 4809:2ca4213fb50a

merged ReceivedCStoreInstanceFilter
author Alain Mazy <am@osimis.io>
date Tue, 23 Nov 2021 09:20:59 +0100
parents 7e1740813fa4 (diff) 0bd98c52474b (current diff)
children 7afbb54bd028
files NEWS OrthancServer/UnitTestsSources/ServerJobsTests.cpp
diffstat 24 files changed, 82 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Oct 15 18:31:20 2021 +0200
+++ b/NEWS	Tue Nov 23 09:20:59 2021 +0100
@@ -1,12 +1,28 @@
 Pending changes in the mainline
 ===============================
 
-
 * Fix handling of option "DeidentifyLogs", notably for tags (0010,0010) and (0010,0020)
 
 * New configuration options:
   - "DicomThreadsCount" to set the number of threads in the embedded DICOM server
 
+REST API
+--------
+
+* API version upgraded to 16
+* If an image can not be decoded, ../preview and ../rendered routes are now returning 
+  unsupported.png only if the ?returnUnsupportedImage option is specified; otherwise, 
+  it raises a 415 error code.
+* Archive jobs response now contains a header Content-Disposition:filename='archive.zip'
+  
+
+
+Maintenance
+-----------
+
+* Fix instances accumulating in DB while their attachments were not stored because of 
+  MaximumStorageSize limit reached with a single patient in DB.
+
 Lua
 ---
 
@@ -19,6 +35,7 @@
 
 * New function in the SDK: OrthancPluginRegisterIncomingCStoreInstanceFilter()
 
+
 Version 1.9.7 (2021-08-31)
 ==========================
 
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Tue Nov 23 09:20:59 2021 +0100
@@ -37,7 +37,7 @@
 # Version of the Orthanc API, can be retrieved from "/system" URI in
 # order to check whether new URI endpoints are available even if using
 # the mainline version of Orthanc
-set(ORTHANC_API_VERSION "15")
+set(ORTHANC_API_VERSION "16")
 
 
 #####################################################################
--- a/OrthancFramework/Sources/Compression/ZipReader.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/Compression/ZipReader.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -353,7 +353,7 @@
         }
         else
         {
-          throw OrthancException(ErrorCode_BadFileFormat);
+          throw OrthancException(ErrorCode_BadFileFormat, "Invalid file or unsupported compression method (e.g. Deflate64)");
         }
       }
       
--- a/OrthancFramework/Sources/JobsEngine/IJob.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/IJob.h	Tue Nov 23 09:20:59 2021 +0100
@@ -59,6 +59,7 @@
     // "success" state
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) = 0;
   };
 }
--- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -650,6 +650,7 @@
 
   bool JobsRegistry::GetJobOutput(std::string& output,
                                   MimeType& mime,
+                                  std::string& filename,
                                   const std::string& job,
                                   const std::string& key)
   {
@@ -668,7 +669,7 @@
 
       if (handler.GetState() == JobState_Success)
       {
-        return handler.GetJob().GetOutput(output, mime, key);
+        return handler.GetJob().GetOutput(output, mime, filename, key);
       }
       else
       {
--- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.h	Tue Nov 23 09:20:59 2021 +0100
@@ -148,6 +148,7 @@
 
     bool GetJobOutput(std::string& output,
                       MimeType& mime,
+                      std::string& filename,
                       const std::string& job,
                       const std::string& key);
 
--- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -448,6 +448,7 @@
 
   bool SequenceOfOperationsJob::GetOutput(std::string& output,
                                           MimeType& mime,
+                                          std::string& filename,
                                           const std::string& key)
   {
     return false;
--- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h	Tue Nov 23 09:20:59 2021 +0100
@@ -125,6 +125,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE;
 
     void AwakeTrailingSleep();
--- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -270,6 +270,7 @@
 
   bool SetOfCommandsJob::GetOutput(std::string &output,
                                    MimeType &mime,
+                                   std::string& filename,
                                    const std::string &key)
   {
     return false;
--- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h	Tue Nov 23 09:20:59 2021 +0100
@@ -104,6 +104,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE;
   };
 }
--- a/OrthancFramework/Sources/RestApi/RestApiOutput.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/RestApi/RestApiOutput.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -214,4 +214,9 @@
     // empty string
     SetCookie(name, "", 1);
   }
+
+  void RestApiOutput::SetContentFilename(const char* filename)
+  {
+    output_.SetContentFilename(filename);
+  }
 }
--- a/OrthancFramework/Sources/RestApi/RestApiOutput.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/Sources/RestApi/RestApiOutput.h	Tue Nov 23 09:20:59 2021 +0100
@@ -77,6 +77,8 @@
                       size_t length,
                       MimeType contentType);
 
+    void SetContentFilename(const char* filename);
+
     void SignalError(HttpStatus status);
 
     void SignalError(HttpStatus status,
--- a/OrthancFramework/UnitTestsSources/JobsTests.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -125,6 +125,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE
     {
       return false;
--- a/OrthancServer/OrthancExplorer/explorer.js	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/OrthancExplorer/explorer.js	Tue Nov 23 09:20:59 2021 +0100
@@ -1113,7 +1113,7 @@
           if (frames.length == 1)
           {
             // Viewing a single-frame image
-            jQuery.slimbox('../instances/' + pageData.uuid + '/preview', '', {
+            jQuery.slimbox('../instances/' + pageData.uuid + '/preview?returnUnsupportedImage', '', {
               overlayFadeDuration : 1,
               resizeDuration : 1,
               imageFadeDuration : 1
@@ -1125,7 +1125,7 @@
 
             images = [];
             for (var i = 0; i < frames.length; i++) {
-              images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview' ]);
+              images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview?returnUnsupportedImage' ]);
             }
 
             jQuery.slimbox(images, 0, {
@@ -1155,7 +1155,7 @@
 
         images = [];
         for (var i = 0; i < instances.length; i++) {
-          images.push([ '../instances/' + instances[i].ID + '/preview',
+          images.push([ '../instances/' + instances[i].ID + '/preview?returnUnsupportedImage',
                         (i + 1).toString() + '/' + instances.length.toString() ])
         }
 
--- a/OrthancServer/Plugins/Engine/PluginsJob.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Plugins/Engine/PluginsJob.h	Tue Nov 23 09:20:59 2021 +0100
@@ -75,6 +75,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE
     {
       // TODO
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -2810,7 +2810,7 @@
         
         if (!ok)
         {
-          throw OrthancException(ErrorCode_FullStorage);
+          throw OrthancException(ErrorCode_FullStorage, "Cannot recycle more patients");
         }
       
         LOG(TRACE) << "Recycling one patient";
@@ -3264,11 +3264,18 @@
         {
           if (e.GetErrorCode() == ErrorCode_DatabaseCannotSerialize)
           {
-            throw;
+            throw;  // the transaction has failed -> do not commit the current transaction (and retry)
           }
           else
           {
-            LOG(ERROR) << "EXCEPTION [" << e.What() << "]";
+            LOG(ERROR) << "EXCEPTION [" << e.What() << " - " << e.GetDetails() << "]";
+
+            if (e.GetErrorCode() == ErrorCode_FullStorage)
+            {
+              throw; // do not commit the current transaction
+            }
+
+            // this is an expected failure, exit normaly and commit the current transaction
             storeStatus_ = StoreStatus_Failure;
           }
         }
--- a/OrthancServer/Sources/OrthancGetRequestHandler.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/OrthancGetRequestHandler.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -497,7 +497,7 @@
   {
     MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_get_scp_duration_ms");
 
-    CLOG(WARNING, DICOM) << "C-GET-SCU request received from AET \"" << originatorAet << "\"";
+    CLOG(INFO, DICOM) << "C-GET-SCU request received from AET \"" << originatorAet << "\"";
 
     {
       DicomArray query(input);
--- a/OrthancServer/Sources/OrthancMoveRequestHandler.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/OrthancMoveRequestHandler.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -334,7 +334,7 @@
   {
     MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_move_scp_duration_ms");
 
-    CLOG(WARNING, DICOM) << "Move-SCU request received for AET \"" << targetAet << "\"";
+    CLOG(INFO, DICOM) << "Move-SCU request received for AET \"" << targetAet << "\"";
 
     {
       DicomArray query(input);
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -755,6 +755,7 @@
             .SetTag("Instances")
             .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
             .SetHttpGetArgument("quality", RestApiCallDocumentation::Type_Number, "Quality for JPEG images (between 1 and 100, defaults to 90)", false)
+            .SetHttpGetArgument("returnUnsupportedImage", RestApiCallDocumentation::Type_Boolean, "Returns an unsupported.png placeholder image if unable to provide the image instead of returning a 415 HTTP error (defaults to false)", false)
             .SetHttpHeader("Accept", "Format of the resulting image. Can be `image/png` (default), `image/jpeg` or `image/x-portable-arbitrarymap`")
             .AddAnswerType(MimeType_Png, "PNG image")
             .AddAnswerType(MimeType_Jpeg, "JPEG image")
@@ -817,13 +818,20 @@
           }
           else
           {
-            std::string root = "";
-            for (size_t i = 1; i < call.GetFullUri().size(); i++)
+            if (call.HasArgument("returnUnsupportedImage"))
             {
-              root += "../";
+              std::string root = "";
+              for (size_t i = 1; i < call.GetFullUri().size(); i++)
+              {
+                root += "../";
+              }
+
+              call.GetOutput().Redirect(root + "app/images/unsupported.png");
             }
-
-            call.GetOutput().Redirect(root + "app/images/unsupported.png");
+            else
+            {
+              call.GetOutput().SignalError(HttpStatus_415_UnsupportedMediaType);
+            }
           }
           return;
         }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -696,10 +696,16 @@
 
     std::string value;
     MimeType mime;
+    std::string filename;
     
     if (OrthancRestApi::GetContext(call).GetJobsEngine().
-        GetRegistry().GetJobOutput(value, mime, job, key))
+        GetRegistry().GetJobOutput(value, mime, filename, job, key))
     {
+      if (!filename.empty())
+      {
+        call.GetOutput().SetContentFilename(filename.c_str());
+      }
+
       call.GetOutput().AnswerBuffer(value, mime);
     }
     else
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -1196,6 +1196,7 @@
 
   bool ArchiveJob::GetOutput(std::string& output,
                              MimeType& mime,
+                             std::string& filename,
                              const std::string& key)
   {   
     if (key == "archive" &&
@@ -1208,6 +1209,7 @@
         const DynamicTemporaryFile& f = dynamic_cast<DynamicTemporaryFile&>(accessor.GetItem());
         f.GetFile().Read(output);
         mime = MimeType_Zip;
+        filename = "archive.zip";
         return true;
       }
       else
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.h	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.h	Tue Nov 23 09:20:59 2021 +0100
@@ -118,6 +118,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE;
   };
 }
--- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp	Fri Oct 15 18:31:20 2021 +0200
+++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp	Tue Nov 23 09:20:59 2021 +0100
@@ -140,6 +140,7 @@
 
     virtual bool GetOutput(std::string& output,
                            MimeType& mime,
+                           std::string& filename,
                            const std::string& key) ORTHANC_OVERRIDE
     {
       return false;
--- a/TODO	Fri Oct 15 18:31:20 2021 +0200
+++ b/TODO	Tue Nov 23 09:20:59 2021 +0100
@@ -60,6 +60,8 @@
   image. The SOPClassUID might be used to identify such secondary
   captures.
 * Support "/preview" and "/matlab" for LUT color images
+* Try to transcode files if a simple decoding fails:
+  https://groups.google.com/g/orthanc-users/c/b8168-NkAhA/m/Df3j-CO9CgAJ
 * Add asynchronous mode in "/modalitities/.../move" for C-MOVE SCU:
   https://groups.google.com/g/orthanc-users/c/G3_jBy4X4NQ/m/8BanTsdMBQAJ
 * Ranges of DICOM tags for "Keep" and "Remove" in ".../modify" and ".../anonymize": 
@@ -125,7 +127,10 @@
   useful in ServerContext::DecodeDicomInstance()
 * DicomMap: create a cache to the main DICOM tags index
 * Check out rapidjson: https://github.com/miloyip/nativejson-benchmark
-
+* optimize tools/find with ModalitiesInStudies: 
+  https://groups.google.com/g/orthanc-users/c/aN8nqcRd3jw/m/pmc9ylVeAwAJ.
+  One solution could be: filter first without ModalitiesInStudies and then
+  cycle through the responses to filter out with ModalitiesInStudies
 
 ========
 Database