Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package orthanc-dicomweb for
openSUSE:Factory checked in at 2023-09-06 18:56:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/orthanc-dicomweb (Old)
and /work/SRC/openSUSE:Factory/.orthanc-dicomweb.new.1766 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "orthanc-dicomweb"
Wed Sep 6 18:56:59 2023 rev:13 rq:1108997 version:1.15
Changes:
--------
--- /work/SRC/openSUSE:Factory/orthanc-dicomweb/orthanc-dicomweb.changes
2023-07-12 17:27:56.446747622 +0200
+++
/work/SRC/openSUSE:Factory/.orthanc-dicomweb.new.1766/orthanc-dicomweb.changes
2023-09-06 18:58:47.920853588 +0200
@@ -1,0 +2,16 @@
+Sun Sep 3 22:23:04 UTC 2023 - Axel Braun <[email protected]>
+
+- Version 1.15
+
+* speed improvement:
+ - Now storing the output of /dicom-web/studies/../series/../metadata route
in an attachment that can be used
+ by the "Full" mode.
+ The json file is gzipped and stored in attachment 4301 everytime a series
is stable or the first time
+ its /dicom-web/studies/../series/../metadata route is called in "Full"
mode if the attachment does not exist yet.
+ A new route /studies/{orthancId}/update-dicomweb-cache has also been added
to allow e.g. the Housekeeper plugin
+ to generate these attachment for old studies.
+ This cache can be disabled by setting "EnableMetadataCache" to false.
However, disabling the cache
+ won't delete the already cached data. You may call DELETE
/series/../attachments/4031 to clear the cache.
+* framework.diff added to compile against Orthanc framework
+
+-------------------------------------------------------------------
Old:
----
OrthancDicomWeb-1.14.tar.gz
New:
----
OrthancDicomWeb-1.15.tar.gz
framework.diff
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ orthanc-dicomweb.spec ++++++
--- /var/tmp/diff_new_pack.WXP8PL/_old 2023-09-06 18:58:50.080930590 +0200
+++ /var/tmp/diff_new_pack.WXP8PL/_new 2023-09-06 18:58:50.084930733 +0200
@@ -21,7 +21,7 @@
Summary: WebViewer plugin for Orthanc
License: AGPL-3.0-or-later
Group: Productivity/Graphics/Viewers
-Version: 1.14
+Version: 1.15
Release: 0
URL: https://orthanc-server.com
Source0:
https://www.orthanc-server.com/downloads/get.php?path=/plugin-dicom-web/OrthancDicomWeb-%{version}.tar.gz
@@ -35,6 +35,7 @@
Source8: babel-polyfill-6.26.0.min.js.gz
Source9: orthanc-dicomweb-readme.SUSE
Source10: dicomweb.json
+Patch0: framework.diff
BuildRequires: cmake
BuildRequires: e2fsprogs-devel
@@ -64,6 +65,7 @@
%prep
%setup -q -n OrthancDicomWeb-%{version}
+%autopatch -p1
#OrthanPlugins may ask for additional files to be loaded
#Putting them into this folder prevents download of sources from the web
++++++ OrthancDicomWeb-1.14.tar.gz -> OrthancDicomWeb-1.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/.hg_archival.txt
new/OrthancDicomWeb-1.15/.hg_archival.txt
--- old/OrthancDicomWeb-1.14/.hg_archival.txt 2023-07-05 14:13:54.000000000
+0200
+++ new/OrthancDicomWeb-1.15/.hg_archival.txt 2023-08-24 16:29:33.000000000
+0200
@@ -1,6 +1,6 @@
repo: d5f45924411123cfd02d035fd50b8e37536eadef
-node: b208c07f0fcea822e44208ee4d9927ea0af803ee
-branch: OrthancDicomWeb-1.14
+node: 8ccaf9f005a783c7ccd0a98aa438c58bd07a922a
+branch: OrthancDicomWeb-1.15
latesttag: null
-latesttagdistance: 540
-changessincelatesttag: 572
+latesttagdistance: 549
+changessincelatesttag: 581
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/CMakeLists.txt
new/OrthancDicomWeb-1.15/CMakeLists.txt
--- old/OrthancDicomWeb-1.14/CMakeLists.txt 2023-07-05 14:13:54.000000000
+0200
+++ new/OrthancDicomWeb-1.15/CMakeLists.txt 2023-08-24 16:29:33.000000000
+0200
@@ -22,13 +22,13 @@
project(OrthancDicomWeb)
-set(ORTHANC_DICOM_WEB_VERSION "1.14")
+set(ORTHANC_DICOM_WEB_VERSION "1.15")
if (ORTHANC_DICOM_WEB_VERSION STREQUAL "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
else()
- set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "1.12.1")
+ set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "daf4807631c5") # TODO: upgrade to
1.12.2 when available
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
endif()
@@ -85,7 +85,8 @@
set(ENABLE_PUGIXML ON)
set(ENABLE_MODULE_JOBS OFF)
set(USE_BOOST_ICONV ON)
-
+ set(ENABLE_ZLIB ON)
+
include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkConfiguration.cmake)
include_directories(${ORTHANC_FRAMEWORK_ROOT})
endif()
@@ -204,6 +205,8 @@
add_dependencies(OrthancDicomWeb AutogeneratedTarget)
+DefineSourceBasenameForTarget(OrthancDicomWeb)
+
message("Setting the version of the library to ${ORTHANC_DICOM_WEB_VERSION}")
add_definitions(-DORTHANC_DICOM_WEB_VERSION="${ORTHANC_DICOM_WEB_VERSION}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/NEWS
new/OrthancDicomWeb-1.15/NEWS
--- old/OrthancDicomWeb-1.14/NEWS 2023-07-05 14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/NEWS 2023-08-24 16:29:33.000000000 +0200
@@ -1,3 +1,16 @@
+Version 1.15 (2023-08-24)
+=========================
+
+* speed improvement:
+ - Now storing the output of /dicom-web/studies/../series/../metadata route
in an attachment that can be used
+ by the "Full" mode.
+ The json file is gzipped and stored in attachment 4301 everytime a series
is stable or the first time
+ its /dicom-web/studies/../series/../metadata route is called in "Full"
mode if the attachment does not exist yet.
+ A new route /studies/{orthancId}/update-dicomweb-cache has also been added
to allow e.g. the Housekeeper plugin
+ to generate these attachment for old studies.
+ This cache can be disabled by setting "EnableMetadataCache" to false.
However, disabling the cache
+ won't delete the already cached data. You may call DELETE
/series/../attachments/4031 to clear the cache.
+
Version 1.14 (2023-07-05)
=========================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/Configuration.cpp
new/OrthancDicomWeb-1.15/Plugin/Configuration.cpp
--- old/OrthancDicomWeb-1.14/Plugin/Configuration.cpp 2023-07-05
14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/Plugin/Configuration.cpp 2023-08-24
16:29:33.000000000 +0200
@@ -676,6 +676,11 @@
return GetUnsignedIntegerValue("MetadataWorkerThreadsCount", 4);
}
+ bool IsMetadataCacheEnabled()
+ {
+ return GetBooleanValue("EnableMetadataCache", true);
+ }
+
MetadataMode GetMetadataMode(Orthanc::ResourceType level)
{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/Configuration.h
new/OrthancDicomWeb-1.15/Plugin/Configuration.h
--- old/OrthancDicomWeb-1.14/Plugin/Configuration.h 2023-07-05
14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/Plugin/Configuration.h 2023-08-24
16:29:33.000000000 +0200
@@ -48,7 +48,7 @@
enum MetadataMode
{
- MetadataMode_Full, // Read all the DICOM instances from the
storage area
+ MetadataMode_Full, // Read all the DICOM instances from the
storage area and store them in an attachment on StableSeries event
MetadataMode_MainDicomTags, // Only use the Orthanc database (main DICOM
tags only)
MetadataMode_Extrapolate // Extrapolate user-specified tags from a few
DICOM instances
};
@@ -139,5 +139,7 @@
void SaveDicomWebServers();
unsigned int GetMetadataWorkerThreadsCount();
+
+ bool IsMetadataCacheEnabled();
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/DicomWebFormatter.cpp
new/OrthancDicomWeb-1.15/Plugin/DicomWebFormatter.cpp
--- old/OrthancDicomWeb-1.14/Plugin/DicomWebFormatter.cpp 2023-07-05
14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/Plugin/DicomWebFormatter.cpp 2023-08-24
16:29:33.000000000 +0200
@@ -165,7 +165,7 @@
first_(true)
{
if (context_ == NULL ||
- output_ == NULL)
+ (isXml_ && output_ == NULL)) // allow no output when working with
Json output.
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
}
@@ -289,8 +289,8 @@
}
- void DicomWebFormatter::HttpWriter::AddDicomWebSerializedJson(const void*
data,
- size_t size)
+ void DicomWebFormatter::HttpWriter::AddDicomWebInstanceSerializedJson(const
void* data,
+ size_t
size)
{
if (isXml_)
{
@@ -318,6 +318,41 @@
jsonBuffer_.AddChunk(data, size);
}
+ void DicomWebFormatter::HttpWriter::AddDicomWebSeriesSerializedJson(const
void* data,
+ size_t
size)
+ {
+ if (isXml_)
+ {
+ // This function can only be used in the JSON case
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+ }
+
+#if !defined(NDEBUG) // In debug mode, check that the value is actually a
JSON string
+ Json::Value json;
+ if (!OrthancPlugins::ReadJson(json, data, size))
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+ }
+#endif
+
+ if (size <= 2 ||
+ reinterpret_cast<const char*>(data)[0] != '[' ||
+ reinterpret_cast<const char*>(data)[size-1] != ']')
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "The
series metadata json does not contain an array.");
+ }
+
+ if (first_)
+ {
+ first_ = false;
+ }
+ else
+ {
+ jsonBuffer_.AddChunk(",");
+ }
+
+ jsonBuffer_.AddChunk(reinterpret_cast<const char*>(data) + 1, size - 2);
// remove leading and trailing []
+ }
void DicomWebFormatter::HttpWriter::Send()
{
@@ -331,6 +366,15 @@
}
}
+ void DicomWebFormatter::HttpWriter::CloseAndGetJsonOutput(std::string&
target)
+ {
+ if (!isXml_)
+ {
+ jsonBuffer_.AddChunk("]");
+
+ jsonBuffer_.Flatten(target);
+ }
+ }
void DicomWebFormatter::HttpWriter::AddInstance(const DicomInstance&
instance,
const std::string& bulkRoot)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/DicomWebFormatter.h
new/OrthancDicomWeb-1.15/Plugin/DicomWebFormatter.h
--- old/OrthancDicomWeb-1.14/Plugin/DicomWebFormatter.h 2023-07-05
14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/Plugin/DicomWebFormatter.h 2023-08-24
16:29:33.000000000 +0200
@@ -115,11 +115,16 @@
void AddOrthancJson(const Json::Value& value);
- void AddDicomWebSerializedJson(const void* data,
- size_t size);
+ void AddDicomWebInstanceSerializedJson(const void* data,
+ size_t size);
+
+ void AddDicomWebSeriesSerializedJson(const void* data,
+ size_t size);
void Send();
+ void CloseAndGetJsonOutput(std::string& target);
+
void AddInstance(const DicomInstance& instance,
const std::string& bulkRoot);
};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/Plugin.cpp
new/OrthancDicomWeb-1.15/Plugin/Plugin.cpp
--- old/OrthancDicomWeb-1.14/Plugin/Plugin.cpp 2023-07-05 14:13:54.000000000
+0200
+++ new/OrthancDicomWeb-1.15/Plugin/Plugin.cpp 2023-08-24 16:29:33.000000000
+0200
@@ -471,6 +471,10 @@
OrthancPlugins::Configuration::LoadDicomWebServers();
break;
+ case OrthancPluginChangeType_StableSeries:
+ CacheSeriesMetadata(resourceId);
+ break;
+
default:
break;
}
@@ -599,6 +603,8 @@
OrthancPlugins::RegisterRestCallback<RetrieveInstanceRendered>(root +
"studies/([^/]*)/series/([^/]*)/instances/([^/]*)/rendered", true);
OrthancPlugins::RegisterRestCallback<RetrieveFrameRendered>(root +
"studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)/rendered",
true);
+
OrthancPlugins::RegisterRestCallback<UpdateSeriesMetadataCache>("/studies/([^/]*)/update-dicomweb-cache",
true);
+
OrthancPluginRegisterOnChangeCallback(context, OnChangeCallback);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/WadoRs.cpp
new/OrthancDicomWeb-1.15/Plugin/WadoRs.cpp
--- old/OrthancDicomWeb-1.14/Plugin/WadoRs.cpp 2023-07-05 14:13:54.000000000
+0200
+++ new/OrthancDicomWeb-1.15/Plugin/WadoRs.cpp 2023-08-24 16:29:33.000000000
+0200
@@ -29,12 +29,18 @@
#include <HttpServer/HttpContentNegociation.h>
#include <Logging.h>
#include <Toolbox.h>
+#include <SerializationToolbox.h>
#include <MultiThreading/SharedMessageQueue.h>
+#include <Compression/GzipCompressor.h>
#include <memory>
#include <boost/thread/mutex.hpp>
#include <boost/thread.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+static const std::string SERIES_METADATA_ATTACHMENT_ID = "4301";
+static std::string WADO_BASE_PLACEHOLDER = "$WADO_BASE_PLACEHOLDER$";
static const char* const MAIN_DICOM_TAGS = "MainDicomTags";
static const char* const REQUESTED_TAGS = "RequestedTags";
static const char* const INSTANCES = "Instances";
@@ -878,7 +884,7 @@
{
if (buffer.RestApiGet("/instances/" + orthancId +
"/attachments/4444/data", false))
{
- writer.AddDicomWebSerializedJson(buffer.GetData(), buffer.GetSize());
+ writer.AddDicomWebInstanceSerializedJson(buffer.GetData(),
buffer.GetSize());
}
else if (buffer.RestApiGet("/instances/" + orthancId + "/file", false))
{
@@ -894,7 +900,7 @@
}
buffer.RestApiPut("/instances/" + orthancId + "/attachments/4444",
dicomweb, false);
- writer.AddDicomWebSerializedJson(dicomweb.c_str(), dicomweb.size());
+ writer.AddDicomWebInstanceSerializedJson(dicomweb.c_str(),
dicomweb.size());
}
}
#endif
@@ -1074,7 +1080,7 @@
}
-static void GetChildrenIdentifiers(std::list<std::string>& target,
+static void GetChildrenIdentifiers(std::set<std::string>& target,
std::string& resourceDicomUid,
Orthanc::ResourceType level,
const std::string& orthancId)
@@ -1119,7 +1125,7 @@
for (Json::Value::ArrayIndex i = 0; i < children.size(); i++)
{
- target.push_back(children[i].asString());
+ target.insert(children[i].asString());
}
}
}
@@ -1250,7 +1256,7 @@
instanceToLoad->bulkRoot = (data->wadoBase +
"studies/" + instanceToLoad->studyInstanceUid +
"/series/" + instanceToLoad->seriesInstanceUid +
- "/instances/" +
instanceResource["MainDicomTags"]["SOPInstanceUID"].asString() + "/bulk");
+ "/instances/" +
instanceResource[MAIN_DICOM_TAGS]["SOPInstanceUID"].asString() + "/bulk");
}
}
@@ -1278,7 +1284,7 @@
}
}
-void RetrieveSeriesMetadataInternal(OrthancPluginRestOutput* output,
+void RetrieveSeriesMetadataInternal(std::set<std::string>& instancesIds,
OrthancPlugins::DicomWebFormatter::HttpWriter& writer,
MainDicomTagsCache& cache,
const OrthancPlugins::MetadataMode& mode,
@@ -1289,7 +1295,6 @@
const std::string& wadoBase)
{
ChildrenMainDicomMaps instancesDicomMaps;
- std::list<std::string> instancesIds;
std::string seriesDicomUid;
unsigned int workersCount =
OrthancPlugins::Configuration::GetMetadataWorkerThreadsCount();
@@ -1299,6 +1304,10 @@
if (oneLargeQuery)
{
GetChildrenMainDicomTags(instancesDicomMaps, seriesDicomUid,
Orthanc::ResourceType_Series, seriesOrthancId);
+ for (ChildrenMainDicomMaps::const_iterator it =
instancesDicomMaps.begin(); it != instancesDicomMaps.end(); ++it)
+ {
+ instancesIds.insert(it->first);
+ }
}
else
{
@@ -1334,7 +1343,7 @@
}
else
{
- for (std::list<std::string>::const_iterator i = instancesIds.begin(); i
!= instancesIds.end(); ++i)
+ for (std::set<std::string>::const_iterator i = instancesIds.begin(); i
!= instancesIds.end(); ++i)
{
instancesQueue.Enqueue(new InstanceToLoad(*i, "", writerMutex, writer,
isXml, OrthancPluginDicomWebBinaryMode_BulkDataUri, studyInstanceUid,
seriesInstanceUid));
}
@@ -1358,18 +1367,190 @@
}
else
{ // old single threaded code
- std::list<std::string> instances;
+ std::set<std::string> instances;
std::string seriesDicomUid; // not used
GetChildrenIdentifiers(instances, seriesDicomUid,
Orthanc::ResourceType_Series, seriesOrthancId);
- for (std::list<std::string>::const_iterator i = instances.begin(); i !=
instances.end(); ++i)
+ for (std::set<std::string>::const_iterator i = instances.begin(); i !=
instances.end(); ++i)
{
WriteInstanceMetadata(writer, mode, cache, *i, studyInstanceUid,
seriesInstanceUid, wadoBase);
}
}
}
+void CacheSeriesMetadataInternal(std::string& serializedSeriesMetadata,
+
OrthancPlugins::DicomWebFormatter::HttpWriter& writer,
+ MainDicomTagsCache& cache,
+ const std::string& studyInstanceUid,
+ const std::string& seriesInstanceUid,
+ const std::string& seriesOrthancId)
+{
+ Orthanc::GzipCompressor compressor;
+ std::string compressedSeriesMetadata;
+ std::set<std::string> instancesIds;
+
+ // compute the series metadata with a placeholder WADO base url because, the
base url might change (e.g if there are 2 Orthanc connected to the same DB)
+ RetrieveSeriesMetadataInternal(instancesIds, writer, cache,
OrthancPlugins::MetadataMode_Full, false /* isXml */, seriesOrthancId,
studyInstanceUid, seriesInstanceUid, WADO_BASE_PLACEHOLDER);
+ writer.CloseAndGetJsonOutput(serializedSeriesMetadata);
+
+ // save in attachments for future use
+ Orthanc::IBufferCompressor::Compress(compressedSeriesMetadata, compressor,
serializedSeriesMetadata);
+ std::string instancesMd5;
+ Orthanc::Toolbox::ComputeMD5(instancesMd5, instancesIds);
+
+ std::string cacheContent = "2;" + instancesMd5 + ";" +
compressedSeriesMetadata;
+
+ Json::Value putResult;
+ std::string attachmentUrl = "/series/" + seriesOrthancId + "/attachments/" +
SERIES_METADATA_ATTACHMENT_ID;
+ if (!OrthancPlugins::RestApiPut(putResult, attachmentUrl, cacheContent,
false))
+ {
+ LOG(WARNING) << "DicomWEB: failed to write series metadata attachment";
+ }
+
+}
+
+void CacheSeriesMetadata(const std::string& seriesOrthancId)
+{
+ if (!OrthancPlugins::Configuration::IsMetadataCacheEnabled())
+ {
+ return;
+ }
+
+ LOG(INFO) << "DicomWEB: pre-computing the WADO-RS series metadata for series
" << seriesOrthancId;
+
+ std::string studyInstanceUid, seriesInstanceUid;
+
+ Json::Value result;
+ if (OrthancPlugins::RestApiGet(result, "/series/" + seriesOrthancId, false))
+ {
+ seriesInstanceUid =
result[MAIN_DICOM_TAGS]["SeriesInstanceUID"].asString();
+ if (OrthancPlugins::RestApiGet(result, "/studies/" +
result["ParentStudy"].asString(), false))
+ {
+ studyInstanceUid =
result[MAIN_DICOM_TAGS]["StudyInstanceUID"].asString();
+
+ MainDicomTagsCache cache;
+ OrthancPlugins::DicomWebFormatter::HttpWriter writer(NULL /* output */,
false /* isXml */); // we cache only the JSON format -> no need for an
HttpOutput
+
+ std::string serializedSeriesMetadataNotUsed;
+ CacheSeriesMetadataInternal(serializedSeriesMetadataNotUsed, writer,
cache, studyInstanceUid, seriesInstanceUid, seriesOrthancId);
+ }
+ }
+}
+
+void UpdateSeriesMetadataCache(OrthancPluginRestOutput* output,
+ const char* /*url*/,
+ const OrthancPluginHttpRequest* request)
+{
+ if (request->method != OrthancPluginHttpMethod_Post)
+ {
+ OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(),
output, "POST");
+ return;
+ }
+
+ if (request->groupsCount != 1)
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest);
+ }
+
+ if (!OrthancPlugins::Configuration::IsMetadataCacheEnabled())
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "The
metadata cache is disabled in the Orthanc configuration.");
+ }
+
+ std::string studyId(request->groups[0]);
+
+ LOG(INFO) << "DicomWEB: updating the series metadata cache for study " <<
studyId;
+
+ Json::Value study;
+
+ if (OrthancPlugins::RestApiGet(study, "/studies/" + studyId, false) &&
study.type() == Json::objectValue)
+ {
+ for (Json::ArrayIndex i = 0; i < study["Series"].size(); ++i)
+ {
+ CacheSeriesMetadata(study["Series"][i].asString());
+ }
+ }
+
+ std::string answer = "{}";
+ OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output,
answer.c_str(), answer.size(), "application/json");
+}
+
+
+
+void
RetrieveSeriesMetadataInternalWithCache(OrthancPlugins::DicomWebFormatter::HttpWriter&
writer,
+ MainDicomTagsCache& cache,
+ const
OrthancPlugins::MetadataMode& mode,
+ bool isXml,
+ const std::string&
seriesOrthancId,
+ const std::string&
studyInstanceUid,
+ const std::string&
seriesInstanceUid,
+ const std::string& wadoBase)
+{
+ if (OrthancPlugins::Configuration::IsMetadataCacheEnabled() &&
+ mode == OrthancPlugins::MetadataMode_Full &&
+ !isXml)
+ {
+ // check if we already have computed the series metadata and saved them in
an attachment
+ std::string serializedSeriesMetadata;
+ std::string cacheContent;
+ bool hasBeenReadFromCache = false;
+ Orthanc::GzipCompressor compressor;
+
+ std::string attachmentUrl = "/series/" + seriesOrthancId + "/attachments/"
+ SERIES_METADATA_ATTACHMENT_ID;
+
+ if (OrthancPlugins::RestApiGetString(cacheContent, attachmentUrl +
"/data", false))
+ {
+ if (boost::starts_with(cacheContent, "2;")) // version 2, cacheContent
is "2;sorted-instances-list-md5;compressedSeriesMetadata"
+ {
+ // check that the instances count have not changed since we have saved
the data in cache
+ // StableSeries event will always overwrite it but this is usefull if
retrieving the metadata while
+ // the instances are being received
+ // Note: we can not use Toolbox::SplitString because the compressed
metadata contain a lot of ";"
+ const char* secondSemiColon = strchr(&cacheContent[2], ';');
+ std::string instancesMd5InCache(&cacheContent[2], secondSemiColon -
&cacheContent[2]);
+ std::string compressedSeriesMetadata(secondSemiColon + 1,
cacheContent.size() - (secondSemiColon+1 - cacheContent.c_str()));
+
+ Json::Value seriesInfo;
+
+ if (!OrthancPlugins::RestApiGet(seriesInfo, "/series/" +
seriesOrthancId, false))
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+ }
+ std::set<std::string> currentInstancesIds;
+ Orthanc::SerializationToolbox::ReadSetOfStrings(currentInstancesIds,
seriesInfo, "Instances");
+ std::string currentInstancesMd5;
+ Orthanc::Toolbox::ComputeMD5(currentInstancesMd5, currentInstancesIds);
+
+ if (currentInstancesMd5 == instancesMd5InCache)
+ {
+ Orthanc::IBufferCompressor::Uncompress(serializedSeriesMetadata,
compressor, compressedSeriesMetadata);
+
+ hasBeenReadFromCache = true;
+ }
+ }
+ }
+
+ if (!hasBeenReadFromCache) // regenerate and overwrite current cache
+ {
+ MainDicomTagsCache tmpCache;
+ OrthancPlugins::DicomWebFormatter::HttpWriter tmpWriter(NULL /* output
*/, false /* isXml */); // we cache only the JSON format -> no need for an
HttpOutput
+
+ CacheSeriesMetadataInternal(serializedSeriesMetadata, tmpWriter,
tmpCache, studyInstanceUid, seriesInstanceUid, seriesOrthancId);
+ }
+
+ boost::replace_all(serializedSeriesMetadata, WADO_BASE_PLACEHOLDER,
wadoBase);
+
+ writer.AddDicomWebSeriesSerializedJson(serializedSeriesMetadata.c_str(),
serializedSeriesMetadata.size());
+ }
+ else
+ {
+ std::set<std::string> instancesIdsNotUsed;
+ RetrieveSeriesMetadataInternal(instancesIdsNotUsed, writer, cache, mode,
isXml, seriesOrthancId, studyInstanceUid, seriesInstanceUid, wadoBase);
+ }
+
+}
+
void RetrieveSeriesMetadata(OrthancPluginRestOutput* output,
const char* /*url*/,
@@ -1389,7 +1570,7 @@
if (LocateSeries(output, seriesOrthancId, studyInstanceUid,
seriesInstanceUid, request))
{
std::string wadoBase =
OrthancPlugins::Configuration::GetBasePublicUrl(request);
- RetrieveSeriesMetadataInternal(output, writer, cache, mode, isXml,
seriesOrthancId, studyInstanceUid, seriesInstanceUid, wadoBase);
+ RetrieveSeriesMetadataInternalWithCache(writer, cache, mode, isXml,
seriesOrthancId, studyInstanceUid, seriesInstanceUid, wadoBase);
}
writer.Send();
@@ -1415,17 +1596,17 @@
std::string wadoBase =
OrthancPlugins::Configuration::GetBasePublicUrl(request);
- std::list<std::string> series;
+ std::set<std::string> series;
std::string studyDicomUid;
GetChildrenIdentifiers(series, studyDicomUid, Orthanc::ResourceType_Study,
studyOrthancId);
- for (std::list<std::string>::const_iterator s = series.begin(); s !=
series.end(); ++s)
+ for (std::set<std::string>::const_iterator s = series.begin(); s !=
series.end(); ++s)
{
- std::list<std::string> instances;
+ std::set<std::string> instances;
std::string seriesDicomUid;
GetChildrenIdentifiers(instances, seriesDicomUid,
Orthanc::ResourceType_Series, *s);
- RetrieveSeriesMetadataInternal(output, writer, cache, mode, isXml, *s,
studyDicomUid, seriesDicomUid, wadoBase);
+ RetrieveSeriesMetadataInternalWithCache(writer, cache, mode, isXml, *s,
studyDicomUid, seriesDicomUid, wadoBase);
}
writer.Send();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/Plugin/WadoRs.h
new/OrthancDicomWeb-1.15/Plugin/WadoRs.h
--- old/OrthancDicomWeb-1.14/Plugin/WadoRs.h 2023-07-05 14:13:54.000000000
+0200
+++ new/OrthancDicomWeb-1.15/Plugin/WadoRs.h 2023-08-24 16:29:33.000000000
+0200
@@ -63,6 +63,12 @@
const char* url,
const OrthancPluginHttpRequest* request);
+void UpdateSeriesMetadataCache(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request);
+
+void CacheSeriesMetadata(const std::string& seriesOrthancId);
+
void RetrieveInstanceMetadata(OrthancPluginRestOutput* output,
const char* url,
const OrthancPluginHttpRequest* request);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/OrthancDicomWeb-1.14/README
new/OrthancDicomWeb-1.15/README
--- old/OrthancDicomWeb-1.14/README 2023-07-05 14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/README 2023-08-24 16:29:33.000000000 +0200
@@ -39,6 +39,14 @@
http://book.orthanc-server.com/plugins/dicomweb.html
+Contributing
+------------
+
+Instructions for contributing to the Orthanc project are included in
+the Orthanc Book:
+https://book.orthanc-server.com/developers/repositories.html
+
+
Licensing: AGPL
---------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/OrthancDicomWeb-1.14/Resources/CMake/JavaScriptLibraries.cmake
new/OrthancDicomWeb-1.15/Resources/CMake/JavaScriptLibraries.cmake
--- old/OrthancDicomWeb-1.14/Resources/CMake/JavaScriptLibraries.cmake
2023-07-05 14:13:54.000000000 +0200
+++ new/OrthancDicomWeb-1.15/Resources/CMake/JavaScriptLibraries.cmake
2023-08-24 16:29:33.000000000 +0200
@@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-set(BASE_URL "https://orthanc.uclouvain.be/third-party-downloads/dicom-web")
+set(BASE_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dicom-web")
DownloadPackage(
"da0189f7c33bf9f652ea65401e0a3dc9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/OrthancDicomWeb-1.14/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
new/OrthancDicomWeb-1.15/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
---
old/OrthancDicomWeb-1.14/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
2023-07-05 14:13:54.000000000 +0200
+++
new/OrthancDicomWeb-1.15/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
2023-08-24 16:29:33.000000000 +0200
@@ -153,11 +153,9 @@
elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.11.2")
set(ORTHANC_FRAMEWORK_MD5 "ede3de356493a8868545f8cb4b8bc8b5")
elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.11.3")
- set(ORTHANC_FRAMEWORK_MD5 "f941c0f5771db7616e7b7961026a60e2")
+ set(ORTHANC_FRAMEWORK_MD5 "5c1b11009d782f248739919db6bf7f7a")
elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.0")
set(ORTHANC_FRAMEWORK_MD5 "d32a0cde03b6eb603d8dd2b33d38bf1b")
- elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.1")
- set(ORTHANC_FRAMEWORK_MD5 "8a435140efc8ff4a01d8242f092f21de")
# Below this point are development snapshots that were used to
# release some plugin, before an official release of the Orthanc
@@ -181,6 +179,9 @@
elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "b2e08d83e21d")
# WSI 1.1 (framework pre-1.10.0), to remove "-std=c++11"
set(ORTHANC_FRAMEWORK_MD5 "2eaa073cbb4b44ffba199ad93393b2b1")
+ elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "daf4807631c5")
+ # DICOMweb 1.15 (framework pre-1.12.2)
+ set(ORTHANC_FRAMEWORK_MD5 "c644aff2817306b3207c98c92e43f35f")
endif()
endif()
endif()
++++++ framework.diff ++++++
--- a/CMakeLists.txt Thu Aug 24 16:29:33 2023 +0200
+++ b/CMakeLists.txt Mon Sep 04 07:49:29 2023 +0200
@@ -54,6 +54,10 @@
set(BUILD_BABEL_POLYFILL OFF CACHE BOOL "Retrieve babel-polyfill from npm")
+# Hotfix to compile against system-wide Orthanc framework
+function(DefineSourceBasenameForTarget targetname)
+endfunction()
+
# Download and setup the Orthanc framework
include(${CMAKE_SOURCE_DIR}/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake)
--- a/Plugin/WadoRs.cpp Thu Aug 24 16:29:33 2023 +0200
+++ b/Plugin/WadoRs.cpp Mon Sep 04 07:49:29 2023 +0200
@@ -70,6 +70,20 @@
}
+// Hotfix: This function corresponds to a new signature introduced in Orthanc
> 1.12.1
+static void ComputeMD5OfSet(std::string& result,
+ const std::set<std::string>& data)
+{
+ std::string s;
+
+ for (std::set<std::string>::const_iterator it = data.begin(); it !=
data.end(); ++it)
+ {
+ s += *it;
+ }
+
+ Orthanc::Toolbox::ComputeMD5(result, s);
+}
+
namespace
{
@@ -1397,7 +1411,7 @@
// save in attachments for future use
Orthanc::IBufferCompressor::Compress(compressedSeriesMetadata, compressor,
serializedSeriesMetadata);
std::string instancesMd5;
- Orthanc::Toolbox::ComputeMD5(instancesMd5, instancesIds);
+ ComputeMD5OfSet(instancesMd5, instancesIds);
std::string cacheContent = "2;" + instancesMd5 + ";" +
compressedSeriesMetadata;
@@ -1520,7 +1534,7 @@
std::set<std::string> currentInstancesIds;
Orthanc::SerializationToolbox::ReadSetOfStrings(currentInstancesIds,
seriesInfo, "Instances");
std::string currentInstancesMd5;
- Orthanc::Toolbox::ComputeMD5(currentInstancesMd5, currentInstancesIds);
+ ComputeMD5OfSet(currentInstancesMd5, currentInstancesIds);
if (currentInstancesMd5 == instancesMd5InCache)
{