Mercurial > hg > orthanc-dicomweb
changeset 290:77d6374435dd refactoring
multipart implementation of STOW-RS
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 08 Jun 2019 17:21:53 +0200 |
parents | d7a831acaa16 |
children | 05b4f440a961 |
files | Plugin/Plugin.cpp Plugin/StowRs.cpp Plugin/StowRs.h |
diffstat | 3 files changed, 159 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/Plugin/Plugin.cpp Sat Jun 08 11:58:49 2019 +0200 +++ b/Plugin/Plugin.cpp Sat Jun 08 17:21:53 2019 +0200 @@ -175,6 +175,7 @@ +#include "DicomWebFormatter.h" class StowServer : public OrthancPlugins::MultipartRestCallback { @@ -182,14 +183,29 @@ class Handler : public IHandler { private: - unsigned int count_; - unsigned int part_; + OrthancPluginContext* context_; + bool xml_; + std::string wadoBase_; + std::string expectedStudy_; + bool isFirst_; + Json::Value result_; + Json::Value success_; + Json::Value failed_; public: - Handler(unsigned int count) : - count_(count), part_(0) + Handler(OrthancPluginContext* context, + bool xml, + const std::string& wadoBase, + const std::string& expectedStudy) : + context_(context), + xml_(xml), + wadoBase_(wadoBase), + expectedStudy_(expectedStudy), + isFirst_(true), + result_(Json::objectValue), + success_(Json::arrayValue), + failed_(Json::arrayValue) { - printf(" created handler: %d\n", count_); } virtual OrthancPluginErrorCode AddPart(const std::string& contentType, @@ -197,34 +213,119 @@ const void* data, size_t size) { - printf(" %d - %d - part received: [%s] %d\n", count_, part_++, contentType.c_str(), size); + if (contentType != "application/dicom") + { + throw Orthanc::OrthancException( + Orthanc::ErrorCode_UnsupportedMediaType, + "The STOW-RS request contains a part that is not " + "\"application/dicom\" (it is: \"" + contentType + "\")"); + } + + Json::Value dicom; + + try + { + OrthancPlugins::OrthancString s; + s.Assign(OrthancPluginDicomBufferToJson(context_, data, size, + OrthancPluginDicomToJsonFormat_Short, + OrthancPluginDicomToJsonFlags_None, 256)); + s.ToJson(dicom); + } + catch (Orthanc::OrthancException&) + { + // Bad DICOM file => TODO add to error + OrthancPlugins::LogWarning("STOW-RS cannot parse an incoming DICOM file"); + return OrthancPluginErrorCode_Success; + } + + if (dicom.type() != Json::objectValue || + !dicom.isMember(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID.Format()) || + !dicom.isMember(Orthanc::DICOM_TAG_SOP_CLASS_UID.Format()) || + !dicom.isMember(Orthanc::DICOM_TAG_SOP_INSTANCE_UID.Format()) || + !dicom.isMember(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID.Format()) || + dicom[Orthanc::DICOM_TAG_SERIES_INSTANCE_UID.Format()].type() != Json::stringValue || + dicom[Orthanc::DICOM_TAG_SOP_CLASS_UID.Format()].type() != Json::stringValue || + dicom[Orthanc::DICOM_TAG_SOP_INSTANCE_UID.Format()].type() != Json::stringValue || + dicom[Orthanc::DICOM_TAG_STUDY_INSTANCE_UID.Format()].type() != Json::stringValue) + { + OrthancPlugins::LogWarning("STOW-RS: Missing a mandatory tag in incoming DICOM file"); + return OrthancPluginErrorCode_Success; + } + + const std::string seriesInstanceUid = dicom[Orthanc::DICOM_TAG_SERIES_INSTANCE_UID.Format()].asString(); + const std::string sopClassUid = dicom[Orthanc::DICOM_TAG_SOP_CLASS_UID.Format()].asString(); + const std::string sopInstanceUid = dicom[Orthanc::DICOM_TAG_SOP_INSTANCE_UID.Format()].asString(); + const std::string studyInstanceUid = dicom[Orthanc::DICOM_TAG_STUDY_INSTANCE_UID.Format()].asString(); - Json::Value v; - OrthancPlugins::RestApiPost(v, "/instances", data, size, false); - std::cout << v << std::endl; + Json::Value item = Json::objectValue; + item[OrthancPlugins::DICOM_TAG_REFERENCED_SOP_CLASS_UID.Format()] = sopClassUid; + item[OrthancPlugins::DICOM_TAG_REFERENCED_SOP_INSTANCE_UID.Format()] = sopInstanceUid; + + if (!expectedStudy_.empty() && + studyInstanceUid != expectedStudy_) + { + OrthancPlugins::LogInfo("STOW-RS request restricted to study [" + expectedStudy_ + + "]: Ignoring instance from study [" + studyInstanceUid + "]"); + + /*item[OrthancPlugins::DICOM_TAG_WARNING_REASON.Format()] = + boost::lexical_cast<std::string>(0xB006); // Elements discarded + success.append(item);*/ + } + else + { + if (isFirst_) + { + std::string url = wadoBase_ + "studies/" + studyInstanceUid; + result_[OrthancPlugins::DICOM_TAG_RETRIEVE_URL.Format()] = url; + isFirst_ = false; + } + OrthancPlugins::MemoryBuffer tmp; + bool ok = tmp.RestApiPost("/instances", data, size, false); + tmp.Clear(); + + if (ok) + { + std::string url = (wadoBase_ + + "studies/" + studyInstanceUid + + "/series/" + seriesInstanceUid + + "/instances/" + sopInstanceUid); + + item[OrthancPlugins::DICOM_TAG_RETRIEVE_URL.Format()] = url; + success_.append(item); + } + else + { + OrthancPlugins::LogError("Orthanc was unable to store one instance in a STOW-RS request"); + item[OrthancPlugins::DICOM_TAG_FAILURE_REASON.Format()] = + boost::lexical_cast<std::string>(0x0110); // Processing failure + failed_.append(item); + } + } + return OrthancPluginErrorCode_Success; } virtual OrthancPluginErrorCode Execute(OrthancPluginRestOutput* output) { - printf(" %d - execute (total = %d)\n", count_, part_); - //throw Orthanc::OrthancException(Orthanc::ErrorCode_CanceledJob); + result_[OrthancPlugins::DICOM_TAG_FAILED_SOP_SEQUENCE.Format()] = failed_; + result_[OrthancPlugins::DICOM_TAG_REFERENCED_SOP_SEQUENCE.Format()] = success_; + + std::string answer; + + { + OrthancPlugins::DicomWebFormatter::Locker locker(OrthancPluginDicomWebBinaryMode_Ignore, ""); + locker.Apply(answer, context_, result_, xml_); + } - std::string s = "{}\n"; + OrthancPluginAnswerBuffer(context_, output, answer.c_str(), answer.size(), + xml_ ? "application/dicom+xml" : "application/dicom+json"); - OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); return OrthancPluginErrorCode_Success; } }; - unsigned int count_; - public: - StowServer() : count_(0) - { - } - virtual IHandler* CreateHandler(OrthancPluginHttpMethod method, const std::string& url, const std::string& contentType, @@ -268,19 +369,7 @@ "The STOW-RS plugin currently only supports \"application/dicom\" subtype"); } - - - - - printf("new handler: [%s] [%s]\n", contentType.c_str(), subType.c_str()); - - for (std::map<std::string, std::string>::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - printf(" header: [%s] = [%s]\n", it->first.c_str(), it->second.c_str()); - } - - return new Handler(count_++); + return new Handler(context, IsXmlExpected(headers), wadoBase, expectedStudy); } };
--- a/Plugin/StowRs.cpp Sat Jun 08 11:58:49 2019 +0200 +++ b/Plugin/StowRs.cpp Sat Jun 08 17:21:53 2019 +0200 @@ -27,16 +27,12 @@ #include <Core/Toolbox.h> #include <Plugins/Samples/Common/OrthancPluginCppWrapper.h> -bool IsXmlExpected(const OrthancPluginHttpRequest* request) + +static bool IsXmlExpected(const std::string& acceptHeader) { std::string accept; - - if (!OrthancPlugins::LookupHttpHeader(accept, request, "accept")) - { - return false; // By default, return DICOM+JSON - } - - Orthanc::Toolbox::ToLowerCase(accept); + Orthanc::Toolbox::ToLowerCase(accept, acceptHeader); + if (accept == "application/dicom+json" || accept == "application/json" || accept == "*/*") @@ -58,6 +54,37 @@ } +bool IsXmlExpected(const std::map<std::string, std::string>& headers) +{ + std::map<std::string, std::string>::const_iterator found = headers.find("accept"); + + if (found == headers.end()) + { + return false; // By default, return DICOM+JSON + } + else + { + return IsXmlExpected(found->second); + } +} + + + // TODO => REMOVE +bool IsXmlExpected(const OrthancPluginHttpRequest* request) +{ + std::string accept; + + if (OrthancPlugins::LookupHttpHeader(accept, request, "accept")) + { + return IsXmlExpected(accept); + } + else + { + return false; // By default, return DICOM+JSON + } +} + + void StowCallback(OrthancPluginRestOutput* output, const char* url, const OrthancPluginHttpRequest* request)
--- a/Plugin/StowRs.h Sat Jun 08 11:58:49 2019 +0200 +++ b/Plugin/StowRs.h Sat Jun 08 17:21:53 2019 +0200 @@ -23,7 +23,9 @@ #include "Configuration.h" -bool IsXmlExpected(const OrthancPluginHttpRequest* request); +bool IsXmlExpected(const std::map<std::string, std::string>& headers); + + bool IsXmlExpected(const OrthancPluginHttpRequest* request); void StowCallback(OrthancPluginRestOutput* output, const char* url,