changeset 6112:91dde382f780 attach-custom-data

integration mainline->attach-custom-data
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 16 May 2025 17:19:35 +0200 (2 weeks ago)
parents e08274ea166e (current diff) 4e7f565e2604 (diff)
children 7dcc5e0a23b7
files NEWS OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp
diffstat 10 files changed, 123 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu May 15 18:49:47 2025 +0200
+++ b/NEWS	Fri May 16 17:19:35 2025 +0200
@@ -14,6 +14,15 @@
 * New storage plugin SDK (v3) to handle customData for attachments.
 * New functions available to all plugins to store key-values and queues.
 
+Maintenance
+-----------
+
+* In verbose logs, added the elapsed time spent in each HTTP call.
+* Housekeeper plugin: 
+  - If "LimitMainDicomTagsReconstructLevel" was set, files were not transcoded if they had to.
+    The "LimitMainDicomTagsReconstructLevel" configuration is now ignored when a full processing
+    is required.
+
 
 Version 1.12.7 (2025-04-07)
 ===========================
--- a/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake	Fri May 16 17:19:35 2025 +0200
@@ -80,6 +80,12 @@
       ${DCMTK_SOURCES_DIR}/dcmimage/include
       )
   endif()
+
+  if (ENABLE_DCMTK_TRANSCODING OR ENABLE_DCMTK_JPEG OR ENABLE_DCMTK_JPEG_LOSSLESS)
+    include_directories(
+      ${DCMTK_SOURCES_DIR}/dcmimgle/include
+      )
+  endif()
   
   if (ENABLE_DCMTK_JPEG)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc DCMTK_SOURCES)
@@ -91,7 +97,6 @@
       ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8
       ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12
       ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg16
-      ${DCMTK_SOURCES_DIR}/dcmimgle/include
       )
     list(REMOVE_ITEM DCMTK_SOURCES 
       ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/ddpiimpl.cc
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Fri May 16 17:19:35 2025 +0200
@@ -1257,10 +1257,12 @@
     
     HttpMethod filterMethod;
 
-    
+    std::unique_ptr<Toolbox::ApiElapsedTimeLogger> apiLogTimer; // to log the time spent in the API call
+
     if (ExtractMethod(method, request, headers, argumentsGET))
     {
-      CLOG(INFO, HTTP) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
+      apiLogTimer.reset(new Toolbox::ApiElapsedTimeLogger(std::string(EnumerationToString(method)) + " " + Toolbox::FlattenUri(uri)));
+      
       filterMethod = method;
     }
 #if ORTHANC_ENABLE_PUGIXML == 1
@@ -1268,8 +1270,7 @@
              !strcmp(request->request_method, "PROPFIND") ||
              !strcmp(request->request_method, "HEAD"))
     {
-      CLOG(INFO, HTTP) << "Incoming read-only WebDAV request: "
-                       << request->request_method << " " << requestUri;
+      apiLogTimer.reset(new Toolbox::ApiElapsedTimeLogger(std::string("Incoming read-only WebDAV request: ") + request->request_method + " " + requestUri));
       filterMethod = HttpMethod_Get;
       isWebDav = true;
     }
@@ -1278,8 +1279,7 @@
              !strcmp(request->request_method, "UNLOCK") ||
              !strcmp(request->request_method, "MKCOL"))
     {
-      CLOG(INFO, HTTP) << "Incoming read-write WebDAV request: "
-                       << request->request_method << " " << requestUri;
+      apiLogTimer.reset(new Toolbox::ApiElapsedTimeLogger(std::string("Incoming read-write WebDAV request: ") + request->request_method + " " + requestUri));
       filterMethod = HttpMethod_Put;
       isWebDav = true;
     }
--- a/OrthancFramework/Sources/Toolbox.cpp	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancFramework/Sources/Toolbox.cpp	Fri May 16 17:19:35 2025 +0200
@@ -2576,14 +2576,14 @@
     return Toolbox::GetHumanTransferSpeed(full, sizeInBytes, GetElapsedNanoseconds());
   }
 
-  Toolbox::ElapsedTimeLogger::ElapsedTimeLogger(const std::string& message)
+  Toolbox::DebugElapsedTimeLogger::DebugElapsedTimeLogger(const std::string& message)
   : message_(message),
     logged_(false)
   {
     Restart();
   }
 
-  Toolbox::ElapsedTimeLogger::~ElapsedTimeLogger()
+  Toolbox::DebugElapsedTimeLogger::~DebugElapsedTimeLogger()
   {
     if (!logged_)
     {
@@ -2591,17 +2591,29 @@
     }
   }
 
-  void Toolbox::ElapsedTimeLogger::Restart()
+  void Toolbox::DebugElapsedTimeLogger::Restart()
   {
     timer_.Restart();
   }
 
-  void Toolbox::ElapsedTimeLogger::StopAndLog()
+  void Toolbox::DebugElapsedTimeLogger::StopAndLog()
   {
     LOG(WARNING) << "ELAPSED TIMER: " << message_ << " (" << timer_.GetElapsedMicroseconds() << " us)";
     logged_ = true;
   }
 
+  Toolbox::ApiElapsedTimeLogger::ApiElapsedTimeLogger(const std::string& message) :
+    message_(message)
+  {
+    timer_.Restart();
+    CLOG(INFO, HTTP) << message_;
+  }
+  
+  Toolbox::ApiElapsedTimeLogger::~ApiElapsedTimeLogger()
+  {
+    CLOG(INFO, HTTP) << message_ << " (elapsed: " << timer_.GetElapsedMicroseconds() << " us)";
+  }
+
   std::string Toolbox::GetHumanFileSize(uint64_t sizeInBytes)
   {
     if (sizeInBytes < 1024)
--- a/OrthancFramework/Sources/Toolbox.h	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancFramework/Sources/Toolbox.h	Fri May 16 17:19:35 2025 +0200
@@ -82,7 +82,7 @@
   class ORTHANC_PUBLIC Toolbox
   {
   public:
-    class ORTHANC_PUBLIC LinesIterator
+    class ORTHANC_PUBLIC LinesIterator : public boost::noncopyable
     {
     private:
       const std::string& content_;
@@ -377,11 +377,13 @@
 
     static void RemoveSurroundingQuotes(std::string& value);
 
-    class ORTHANC_PUBLIC ElapsedTimer
+    class ORTHANC_PUBLIC ElapsedTimer : public boost::noncopyable
     {
+    private:
       boost::posix_time::ptime  start_;
+
     public:
-      explicit ElapsedTimer();
+      ElapsedTimer();
 
       uint64_t GetElapsedMilliseconds();
       uint64_t GetElapsedMicroseconds();
@@ -394,23 +396,38 @@
     };
 
     // This is a helper class to measure and log time spend e.g in a method.
-    // This should be used only during debugging and should likely not ever used in a release.
+    // This should be used only during debugging and should likely not ever be used in a release.
     // By default, you should use it as a RAII but you may force Restart/StopAndLog manually if needed.
-    class ORTHANC_PUBLIC ElapsedTimeLogger
+    class ORTHANC_PUBLIC DebugElapsedTimeLogger : public boost::noncopyable
     {
     private:
       ElapsedTimer      timer_;
       const std::string message_;
-      bool logged_;
+      bool              logged_;
 
     public:
-      explicit ElapsedTimeLogger(const std::string& message);
-      ~ElapsedTimeLogger();  
+      explicit DebugElapsedTimeLogger(const std::string& message);
+
+      ~DebugElapsedTimeLogger();  
 
       void Restart();
       void StopAndLog();
     };
 
+    // This variant logs the same message when entering the method and when exiting (with the elapsed time).
+    // Logs goes to verbose-http.
+    class ORTHANC_PUBLIC ApiElapsedTimeLogger : public boost::noncopyable
+    {
+    private:
+      ElapsedTimer      timer_;
+      const std::string message_;
+
+    public:
+      explicit ApiElapsedTimeLogger(const std::string& message);
+
+      ~ApiElapsedTimeLogger();
+    };
+
     static std::string GetHumanFileSize(uint64_t sizeInBytes);
 
     static std::string GetHumanDuration(uint64_t durationInNanoseconds);
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri May 16 17:19:35 2025 +0200
@@ -1620,6 +1620,10 @@
    * concurrently by different threads of the Web server of
    * Orthanc. You must implement proper locking if applicable.
    *
+   * Note that if you are using HTTP basic authentication, you can extract
+   * the username from the "Authorization" HTTP header.  The value of that header
+   * contains username:pwd encoded in base64.
+   *
    * @param method The HTTP method used by the request.
    * @param uri The URI of interest.
    * @param ip The IP address of the HTTP client.
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Fri May 16 17:19:35 2025 +0200
@@ -2052,6 +2052,26 @@
             DoPost(target, index, uri, body, headers));
   }
 
+  bool OrthancPeers::DoPost(Json::Value& target,
+                            size_t index,
+                            const std::string& uri,
+                            const std::string& body,
+                            const HttpHeaders& headers, 
+                            unsigned int timeout) const
+  {
+    MemoryBuffer buffer;
+
+    if (DoPost(buffer, index, uri, body, headers, timeout))
+    {
+      buffer.ToJson(target);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
 
   bool OrthancPeers::DoPost(Json::Value& target,
                             size_t index,
@@ -2099,6 +2119,17 @@
                             const std::string& body,
                             const HttpHeaders& headers) const
   {
+    return DoPost(target, index, uri, body, headers, timeout_);
+  }
+
+
+  bool OrthancPeers::DoPost(MemoryBuffer& target,
+                            size_t index,
+                            const std::string& uri,
+                            const std::string& body,
+                            const HttpHeaders& headers,
+                            unsigned int timeout) const
+  {
     if (index >= index_.size())
     {
       ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
@@ -2117,7 +2148,7 @@
     OrthancPluginErrorCode code = OrthancPluginCallPeerApi
       (GetGlobalContext(), *answer, NULL, &status, peers_,
        static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
-       pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_);
+       pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout);
 
     if (code == OrthancPluginErrorCode_Success)
     {
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Fri May 16 17:19:35 2025 +0200
@@ -855,6 +855,13 @@
                 const HttpHeaders& headers) const;
 
     bool DoPost(MemoryBuffer& target,
+                size_t index,
+                const std::string& uri,
+                const std::string& body,
+                const HttpHeaders& headers,
+                unsigned int timeout) const;
+
+    bool DoPost(MemoryBuffer& target,
                 const std::string& name,
                 const std::string& uri,
                 const std::string& body,
@@ -867,6 +874,13 @@
                 const HttpHeaders& headers) const;
 
     bool DoPost(Json::Value& target,
+                size_t index,
+                const std::string& uri,
+                const std::string& body,
+                const HttpHeaders& headers,
+                unsigned int timeout) const;
+
+    bool DoPost(Json::Value& target,
                 const std::string& name,
                 const std::string& uri,
                 const std::string& body,
--- a/OrthancServer/Plugins/Samples/Housekeeper/Plugin.cpp	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancServer/Plugins/Samples/Housekeeper/Plugin.cpp	Fri May 16 17:19:35 2025 +0200
@@ -651,6 +651,13 @@
     needsFullProcessing = needsReconstruct || needsReingest || needsDicomWebCaching;
     needsProcessing = needsFullProcessing;
 
+    if (needsFullProcessing && !limitToChange_.empty())
+    {
+      ORTHANC_PLUGINS_LOG_WARNING("Housekeeper: full processing needed -> ignoring the \"LimitMainDicomTagsReconstructLevel\" configuration");
+      limitToChange_.clear();
+      limitToUrl_.clear();
+    }
+
       // if a processing was in progress, check if the config has changed since
     if (pluginStatus_.currentlyProcessingConfiguration.IsDefined())
     {
@@ -679,7 +686,7 @@
     }
     else
     {
-      ORTHANC_PLUGINS_LOG_WARNING("Housekeeper: the DB configuration has changed since last run, will reprocess the whole DB !");
+      ORTHANC_PLUGINS_LOG_WARNING("Housekeeper: the Orthanc configuration has changed since last run, will reprocess the whole DB !");
     }
     
     Json::Value changes;
@@ -695,7 +702,7 @@
   }
   else
   {
-    ORTHANC_PLUGINS_LOG_WARNING("Housekeeper: the DB configuration has not changed since last run, will continue processing changes");
+    ORTHANC_PLUGINS_LOG_WARNING("Housekeeper: the Orthanc configuration has not changed since last run, will continue processing changes");
   }
 
   bool completed = false;
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu May 15 18:49:47 2025 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri May 16 17:19:35 2025 +0200
@@ -976,6 +976,8 @@
         ImageToEncode image(decoded, mode, invert);
 
         HttpContentNegociation negociation;
+
+        // The first call to "Register()" indicates the default content type (here, PNG)
         EncodePng png(image);
         negociation.Register(MIME_PNG, png);