# HG changeset patch # User Alain Mazy # Date 1637655659 -3600 # Node ID 2ca4213fb50acc3b53b58b59eadf4fee35b6fed4 # Parent 7e1740813fa44d81122d8a5aec30ca09735000a2# Parent 0bd98c52474b593ab7a0ff950436e6b977a9e649 merged ReceivedCStoreInstanceFilter diff -r 7e1740813fa4 -r 2ca4213fb50a NEWS --- a/NEWS Wed Nov 17 10:08:44 2021 +0100 +++ b/NEWS Tue Nov 23 09:20:59 2021 +0100 @@ -23,6 +23,18 @@ * Fix instances accumulating in DB while their attachments were not stored because of MaximumStorageSize limit reached with a single patient in DB. +Lua +--- + +* New "ReceivedCStoreInstanceFilter" Lua callback to filter instances received + through C-Store and return a specific C-Store status code. + + +Plugins +------- + +* New function in the SDK: OrthancPluginRegisterIncomingCStoreInstanceFilter() + Version 1.9.7 (2021-08-31) ========================== diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Tue Nov 23 09:20:59 2021 +0100 @@ -39,9 +39,9 @@ { } - virtual void Handle(DcmDataset& dicom, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; + virtual uint16_t Handle(DcmDataset& dicom, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) = 0; }; } diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -161,14 +161,14 @@ // which SOP class and SOP instance ? #if DCMTK_VERSION_NUMBER >= 364 - if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sizeof(sopClass), - sopInstance, sizeof(sopInstance), /*opt_correctUIDPadding*/ OFFalse)) + if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sizeof(sopClass), + sopInstance, sizeof(sopInstance), /*opt_correctUIDPadding*/ OFFalse)) #else if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sopInstance, /*opt_correctUIDPadding*/ OFFalse)) #endif { - //LOG4CPP_ERROR(Internals::GetLogger(), "bad DICOM file: " << fileName); - rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand; + //LOG4CPP_ERROR(Internals::GetLogger(), "bad DICOM file: " << fileName); + rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand; } else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0) { @@ -182,7 +182,7 @@ { try { - cbdata->handler->Handle(**imageDataSet, *cbdata->remoteIp, cbdata->remoteAET, cbdata->calledAET); + rsp->DimseStatus = cbdata->handler->Handle(**imageDataSet, *cbdata->remoteIp, cbdata->remoteAET, cbdata->calledAET); } catch (OrthancException& e) { diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancFramework/Sources/Lua/LuaFunctionCall.cpp --- a/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -146,6 +146,20 @@ } } + void LuaFunctionCall::ExecuteToInt(int& result) + { + ExecuteInternal(1); + + int top = lua_gettop(context_.lua_); + if (lua_isnumber(context_.lua_, top)) + { + result = static_cast(lua_tointeger(context_.lua_, top)); + } + else + { + throw OrthancException(ErrorCode_LuaReturnsNoString); + } + } void LuaFunctionCall::PushStringMap(const std::map& value) { diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancFramework/Sources/Lua/LuaFunctionCall.h --- a/OrthancFramework/Sources/Lua/LuaFunctionCall.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.h Tue Nov 23 09:20:59 2021 +0100 @@ -78,6 +78,8 @@ void ExecuteToString(std::string& result); + void ExecuteToInt(int& result); + #if ORTHANC_ENABLE_DCMTK == 1 void ExecuteToDicom(DicomMap& target); #endif diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Plugins/Engine/OrthancPlugins.cpp --- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -79,6 +79,7 @@ #include #include #include +#include #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc API is necessary" @@ -1165,6 +1166,7 @@ typedef std::list IncomingHttpRequestFilters; typedef std::list IncomingHttpRequestFilters2; typedef std::list IncomingDicomInstanceFilters; + typedef std::list IncomingCStoreInstanceFilters; typedef std::list DecodeImageCallbacks; typedef std::list TranscoderCallbacks; typedef std::list JobsUnserializers; @@ -1187,6 +1189,7 @@ IncomingHttpRequestFilters incomingHttpRequestFilters_; IncomingHttpRequestFilters2 incomingHttpRequestFilters2_; IncomingDicomInstanceFilters incomingDicomInstanceFilters_; + IncomingCStoreInstanceFilters incomingCStoreInstanceFilters_; // New in Orthanc 1.9.8 RefreshMetricsCallbacks refreshMetricsCallbacks_; StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; std::unique_ptr storageArea_; @@ -2261,7 +2264,36 @@ return true; } - + + + uint16_t OrthancPlugins::FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified) + { + DicomInstanceFromCallback wrapped(instance); + + boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); + + for (PImpl::IncomingCStoreInstanceFilters::const_iterator + filter = pimpl_->incomingCStoreInstanceFilters_.begin(); + filter != pimpl_->incomingCStoreInstanceFilters_.end(); ++filter) + { + int32_t filterResult = (*filter) (reinterpret_cast(&wrapped)); + + if (filterResult >= 0 && filterResult <= 0xFFFF) + { + return static_cast(filterResult); + } + else + { + // The callback is only allowed to answer uint16_t + throw OrthancException(ErrorCode_Plugin); + } + } + + return STATUS_Success; + } + + void OrthancPlugins::SignalChangeInternal(OrthancPluginChangeType changeType, OrthancPluginResourceType resourceType, const char* resource) @@ -2479,6 +2511,16 @@ } + void OrthancPlugins::RegisterIncomingCStoreInstanceFilter(const void* parameters) + { + const _OrthancPluginIncomingCStoreInstanceFilter& p = + *reinterpret_cast(parameters); + + CLOG(INFO, PLUGINS) << "Plugin has registered a callback to filter incoming C-Store DICOM instances"; + pimpl_->incomingCStoreInstanceFilters_.push_back(p.callback); + } + + void OrthancPlugins::RegisterRefreshMetricsCallback(const void* parameters) { const _OrthancPluginRegisterRefreshMetricsCallback& p = @@ -4957,6 +4999,10 @@ RegisterIncomingDicomInstanceFilter(parameters); return true; + case _OrthancPluginService_RegisterIncomingCStoreInstanceFilter: + RegisterIncomingCStoreInstanceFilter(parameters); + return true; + case _OrthancPluginService_RegisterRefreshMetricsCallback: RegisterRefreshMetricsCallback(parameters); return true; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Plugins/Engine/OrthancPlugins.h --- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Tue Nov 23 09:20:59 2021 +0100 @@ -133,6 +133,8 @@ void RegisterIncomingDicomInstanceFilter(const void* parameters); + void RegisterIncomingCStoreInstanceFilter(const void* parameters); + void RegisterRefreshMetricsCallback(const void* parameters); void RegisterStorageCommitmentScpCallback(const void* parameters); @@ -279,6 +281,9 @@ virtual bool FilterIncomingInstance(const DicomInstanceToStore& instance, const Json::Value& simplified) ORTHANC_OVERRIDE; + virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified) ORTHANC_OVERRIDE; + bool HasStorageArea() const; IStorageArea* CreateStorageArea(); // To be freed after use diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h --- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Tue Nov 23 09:20:59 2021 +0100 @@ -461,7 +461,8 @@ _OrthancPluginService_RegisterIncomingDicomInstanceFilter = 1014, _OrthancPluginService_RegisterTranscoderCallback = 1015, /* New in Orthanc 1.7.0 */ _OrthancPluginService_RegisterStorageArea2 = 1016, /* New in Orthanc 1.9.0 */ - + _OrthancPluginService_RegisterIncomingCStoreInstanceFilter = 1017, /* New in Orthanc 1.9.8 */ + /* Sending answers to REST calls */ _OrthancPluginService_AnswerBuffer = 2000, _OrthancPluginService_CompressAndAnswerPngImage = 2001, /* Unused as of Orthanc 0.9.4 */ @@ -7764,6 +7765,63 @@ /** + * @brief Callback to filter incoming DICOM instances received by + * Orthanc through C-Store. + * + * Signature of a callback function that is triggered whenever + * Orthanc receives a new DICOM instance (through DICOM protocol), + * and that answers whether this DICOM instance should be accepted + * or discarded by Orthanc. If the instance is discarded, the callback + * can specify the C-Store error code. + * + * Note that the metadata information is not available + * (i.e. GetInstanceMetadata() should not be used on "instance"). + * + * @param instance The received DICOM instance. + * @return 0 to accept the instance, any valid C-Store error code + * to reject the instance, -1 if error. + * @ingroup Callback + **/ + typedef int32_t (*OrthancPluginIncomingCStoreInstanceFilter) ( + const OrthancPluginDicomInstance* instance); + + + typedef struct + { + OrthancPluginIncomingCStoreInstanceFilter callback; + } _OrthancPluginIncomingCStoreInstanceFilter; + + /** + * @brief Register a callback to filter incoming DICOM instances + * received by Orthanc through C-Store. + * + * + * @warning Your callback function will be called synchronously with + * the core of Orthanc. This implies that deadlocks might emerge if + * you call other core primitives of Orthanc in your callback (such + * deadlocks are particular visible in the presence of other plugins + * or Lua scripts). It is thus strongly advised to avoid any call to + * the REST API of Orthanc in the callback. If you have to call + * other primitives of Orthanc, you should make these calls in a + * separate thread, passing the pending events to be processed + * through a message queue. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingCStoreInstanceFilter( + OrthancPluginContext* context, + OrthancPluginIncomingCStoreInstanceFilter callback) + { + _OrthancPluginIncomingCStoreInstanceFilter params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterIncomingCStoreInstanceFilter, ¶ms); + } + + /** * @brief Get the transfer syntax of a DICOM file. * * This function returns a pointer to a newly created string that diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/IServerListener.h --- a/OrthancServer/Sources/IServerListener.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/IServerListener.h Tue Nov 23 09:20:59 2021 +0100 @@ -55,5 +55,9 @@ virtual bool FilterIncomingInstance(const DicomInstanceToStore& instance, const Json::Value& simplified) = 0; + + virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified) = 0; + }; } diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/LuaScripting.cpp --- a/OrthancServer/Sources/LuaScripting.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/LuaScripting.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -43,6 +43,8 @@ #include "../../OrthancFramework/Sources/Logging.h" #include "../../OrthancFramework/Sources/Lua/LuaFunctionCall.h" +#include + #include @@ -945,6 +947,41 @@ return true; } + uint16_t LuaScripting::FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified) + { + static const char* NAME = "ReceivedCStoreInstanceFilter"; + + boost::recursive_mutex::scoped_lock lock(mutex_); + + if (lua_.IsExistingFunction(NAME)) + { + LuaFunctionCall call(lua_, NAME); + call.PushJson(simplified); + + Json::Value origin; + instance.GetOrigin().Format(origin); + call.PushJson(origin); + + Json::Value info = Json::objectValue; + info["HasPixelData"] = instance.HasPixelData(); + + DicomTransferSyntax s; + if (instance.LookupTransferSyntax(s)) + { + info["TransferSyntaxUID"] = GetTransferSyntaxUid(s); + } + + call.PushJson(info); + + int result; + call.ExecuteToInt(result); + return static_cast(result); + } + + return STATUS_Success; + } + void LuaScripting::Execute(const std::string& command) { diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/LuaScripting.h --- a/OrthancServer/Sources/LuaScripting.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/LuaScripting.h Tue Nov 23 09:20:59 2021 +0100 @@ -129,6 +129,9 @@ bool FilterIncomingInstance(const DicomInstanceToStore& instance, const Json::Value& simplifiedTags); + uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified); + void Execute(const std::string& command); void SignalJobSubmitted(const std::string& jobId); diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -554,16 +554,16 @@ toStore->SetOrigin(DicomInstanceOrigin::FromRest(call)); ServerContext& context = OrthancRestApi::GetContext(call); - StoreStatus status = context.Store(id, *toStore, StoreInstanceMode_Default); + ServerContext::StoreResult result = context.Store(id, *toStore, StoreInstanceMode_Default); - if (status == StoreStatus_Failure) + if (result.GetStatus() == StoreStatus_Failure) { throw OrthancException(ErrorCode_CannotStoreInstance); } if (sendAnswer) { - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, *toStore, status, id); + OrthancRestApi::GetApi(call).AnswerStoredInstance(call, *toStore, result.GetStatus(), id); } } diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -199,10 +199,10 @@ try { - StoreStatus status = context.Store(publicId, *toStore, StoreInstanceMode_Default); + ServerContext::StoreResult result = context.Store(publicId, *toStore, StoreInstanceMode_Default); Json::Value info; - SetupResourceAnswer(info, *toStore, status, publicId); + SetupResourceAnswer(info, *toStore, result.GetStatus(), publicId); answer.append(info); } catch (OrthancException& e) @@ -252,9 +252,9 @@ toStore->SetOrigin(DicomInstanceOrigin::FromRest(call)); std::string publicId; - StoreStatus status = context.Store(publicId, *toStore, StoreInstanceMode_Default); + ServerContext::StoreResult result = context.Store(publicId, *toStore, StoreInstanceMode_Default); - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, *toStore, status, publicId); + OrthancRestApi::GetApi(call).AnswerStoredInstance(call, *toStore, result.GetStatus(), publicId); } } diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/OrthancWebDav.cpp --- a/OrthancServer/Sources/OrthancWebDav.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/OrthancWebDav.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -1313,9 +1313,9 @@ try { std::string publicId; - StoreStatus status = context_.Store(publicId, *instance, StoreInstanceMode_Default); - if (status == StoreStatus_Success || - status == StoreStatus_AlreadyStored) + ServerContext::StoreResult result = context_.Store(publicId, *instance, StoreInstanceMode_Default); + if (result.GetStatus() == StoreStatus_Success || + result.GetStatus() == StoreStatus_AlreadyStored) { LOG(INFO) << "Successfully imported DICOM instance from WebDAV: " << path << " (Orthanc ID: " << publicId << ")"; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/ServerContext.cpp --- a/OrthancServer/Sources/ServerContext.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/ServerContext.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -57,6 +57,7 @@ #include "StorageCommitmentReports.h" #include +#include static size_t DICOM_CACHE_SIZE = 128 * 1024 * 1024; // 128 MB @@ -100,6 +101,13 @@ transferSyntax != DicomTransferSyntax_XML); } + + ServerContext::StoreResult::StoreResult() : + status_(StoreStatus_Failure), + cstoreStatusCode_(0) + { + } + void ServerContext::ChangeThread(ServerContext* that, unsigned int sleepDelay) @@ -489,9 +497,9 @@ } - StoreStatus ServerContext::StoreAfterTranscoding(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode) + ServerContext::StoreResult ServerContext::StoreAfterTranscoding(std::string& resultPublicId, + DicomInstanceToStore& dicom, + StoreInstanceMode mode) { bool overwrite; switch (mode) @@ -538,7 +546,7 @@ Toolbox::SimplifyDicomAsJson(simplifiedTags, dicomAsJson, DicomToJsonFormat_Human); // Test if the instance must be filtered out - bool accepted = true; + StoreResult result; { boost::shared_lock lock(listenersMutex_); @@ -549,9 +557,22 @@ { if (!it->GetListener().FilterIncomingInstance(dicom, simplifiedTags)) { - accepted = false; + result.SetStatus(StoreStatus_FilteredOut); + result.SetCStoreStatusCode(STATUS_Success); // to keep backward compatibility, we still return 'success' break; } + + if (dicom.GetOrigin().GetRequestOrigin() == Orthanc::RequestOrigin_DicomProtocol) + { + uint16_t filterResult = it->GetListener().FilterIncomingCStoreInstance(dicom, simplifiedTags); + if (filterResult != 0x0000) + { + result.SetStatus(StoreStatus_FilteredOut); + result.SetCStoreStatusCode(filterResult); + break; + } + } + } catch (OrthancException& e) { @@ -563,10 +584,10 @@ } } - if (!accepted) + if (result.GetStatus() == StoreStatus_FilteredOut) { LOG(INFO) << "An incoming instance has been discarded by the filter"; - return StoreStatus_FilteredOut; + return result; } // Remove the file from the DicomCache (useful if @@ -595,9 +616,9 @@ typedef std::map InstanceMetadata; InstanceMetadata instanceMetadata; - StoreStatus status = index_.Store( + result.SetStatus(index_.Store( instanceMetadata, summary, attachments, dicom.GetMetadata(), dicom.GetOrigin(), overwrite, - hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset); + hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset)); // Only keep the metadata for the "instance" level dicom.ClearMetadata(); @@ -608,7 +629,7 @@ dicom.AddMetadata(ResourceType_Instance, it->first, it->second); } - if (status != StoreStatus_Success) + if (result.GetStatus() != StoreStatus_Success) { accessor.Remove(dicomInfo); @@ -618,7 +639,7 @@ } } - switch (status) + switch (result.GetStatus()) { case StoreStatus_Success: LOG(INFO) << "New instance stored"; @@ -637,8 +658,8 @@ break; } - if (status == StoreStatus_Success || - status == StoreStatus_AlreadyStored) + if (result.GetStatus() == StoreStatus_Success || + result.GetStatus() == StoreStatus_AlreadyStored) { boost::shared_lock lock(listenersMutex_); @@ -657,7 +678,7 @@ } } - return status; + return result; } catch (OrthancException& e) { @@ -671,9 +692,9 @@ } - StoreStatus ServerContext::Store(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode) + ServerContext::StoreResult ServerContext::Store(std::string& resultPublicId, + DicomInstanceToStore& dicom, + StoreInstanceMode mode) { if (!isIngestTranscoding_) { @@ -733,10 +754,10 @@ std::unique_ptr toStore(DicomInstanceToStore::CreateFromParsedDicomFile(*tmp)); toStore->SetOrigin(dicom.GetOrigin()); - StoreStatus ok = StoreAfterTranscoding(resultPublicId, *toStore, mode); + StoreResult result = StoreAfterTranscoding(resultPublicId, *toStore, mode); assert(resultPublicId == tmp->GetHasher().HashInstance()); - return ok; + return result; } else { diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/ServerContext.h --- a/OrthancServer/Sources/ServerContext.h Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/ServerContext.h Tue Nov 23 09:20:59 2021 +0100 @@ -93,6 +93,36 @@ const Json::Value* dicomAsJson) = 0; }; + struct StoreResult + { + private: + StoreStatus status_; + uint16_t cstoreStatusCode_; + // uint16_t httpStatusCode_; // for future use + + public: + StoreResult(); + + void SetStatus(StoreStatus status) + { + status_ = status; + } + + StoreStatus GetStatus() + { + return status_; + } + + void SetCStoreStatusCode(uint16_t statusCode) + { + cstoreStatusCode_ = statusCode; + } + + uint16_t GetCStoreStatusCode() + { + return cstoreStatusCode_; + } + }; private: class LuaServerListener : public IServerListener @@ -123,6 +153,12 @@ { return context_.filterLua_.FilterIncomingInstance(instance, simplified); } + + virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, + const Json::Value& simplified) ORTHANC_OVERRIDE + { + return context_.filterLua_.FilterIncomingCStoreInstance(instance, simplified); + } }; class ServerListener @@ -231,7 +267,7 @@ bool isUnknownSopClassAccepted_; std::set acceptedTransferSyntaxes_; - StoreStatus StoreAfterTranscoding(std::string& resultPublicId, + StoreResult StoreAfterTranscoding(std::string& resultPublicId, DicomInstanceToStore& dicom, StoreInstanceMode mode); @@ -304,7 +340,7 @@ int64_t oldRevision, const std::string& oldMD5); - StoreStatus Store(std::string& resultPublicId, + StoreResult Store(std::string& resultPublicId, DicomInstanceToStore& dicom, StoreInstanceMode mode); diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp --- a/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -161,8 +161,8 @@ toStore->SetOrigin(origin_); std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, *toStore, - StoreInstanceMode_Default) != StoreStatus_Success) + ServerContext::StoreResult result = GetContext().Store(modifiedInstance, *toStore, StoreInstanceMode_Default); + if (result.GetStatus() != StoreStatus_Success) { LOG(ERROR) << "Error while storing a modified instance " << instance; return false; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp --- a/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -290,8 +290,8 @@ **/ std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, *toStore, - StoreInstanceMode_Default) != StoreStatus_Success) + ServerContext::StoreResult result = GetContext().Store(modifiedInstance, *toStore, StoreInstanceMode_Default); + if (result.GetStatus() != StoreStatus_Success) { throw OrthancException(ErrorCode_CannotStoreInstance, "Error while storing a modified instance " + instance); diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp --- a/OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -143,8 +143,8 @@ toStore->SetOrigin(origin_); std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, *toStore, - StoreInstanceMode_Default) != StoreStatus_Success) + ServerContext::StoreResult result = GetContext().Store(modifiedInstance, *toStore, StoreInstanceMode_Default); + if (result.GetStatus() != StoreStatus_Success) { LOG(ERROR) << "Error while storing a modified instance " << instance; return false; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/Sources/main.cpp --- a/OrthancServer/Sources/main.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/Sources/main.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -84,10 +84,10 @@ } - virtual void Handle(DcmDataset& dicom, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) ORTHANC_OVERRIDE + virtual uint16_t Handle(DcmDataset& dicom, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) ORTHANC_OVERRIDE { std::unique_ptr toStore(DicomInstanceToStore::CreateFromDcmDataset(dicom)); @@ -97,8 +97,11 @@ (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str())); std::string id; - context_.Store(id, *toStore, StoreInstanceMode_Default); + ServerContext::StoreResult result = context_.Store(id, *toStore, StoreInstanceMode_Default); + return result.GetCStoreStatusCode(); } + + return STATUS_STORE_Error_CannotUnderstand; } }; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/UnitTestsSources/ServerIndexTests.cpp --- a/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -859,7 +859,8 @@ ASSERT_EQ(id, hasher.HashInstance()); std::string id2; - ASSERT_EQ(StoreStatus_Success, context.Store(id2, *toStore, StoreInstanceMode_Default)); + ServerContext::StoreResult result = context.Store(id2, *toStore, StoreInstanceMode_Default); + ASSERT_EQ(StoreStatus_Success, result.GetStatus()); ASSERT_EQ(id, id2); } @@ -908,8 +909,8 @@ toStore->SetOrigin(DicomInstanceOrigin::FromPlugins()); std::string id2; - ASSERT_EQ(overwrite ? StoreStatus_Success : StoreStatus_AlreadyStored, - context.Store(id2, *toStore, StoreInstanceMode_Default)); + ServerContext::StoreResult result = context.Store(id2, *toStore, StoreInstanceMode_Default); + ASSERT_EQ(overwrite ? StoreStatus_Success : StoreStatus_AlreadyStored, result.GetStatus()); ASSERT_EQ(id, id2); } @@ -1008,7 +1009,8 @@ std::unique_ptr toStore(DicomInstanceToStore::CreateFromParsedDicomFile(dicom)); dicomSize = toStore->GetBufferSize(); toStore->SetOrigin(DicomInstanceOrigin::FromPlugins()); - ASSERT_EQ(StoreStatus_Success, context.Store(id, *toStore, StoreInstanceMode_Default)); + ServerContext::StoreResult result = context.Store(id, *toStore, StoreInstanceMode_Default); + ASSERT_EQ(StoreStatus_Success, result.GetStatus()); } std::set attachments; diff -r 7e1740813fa4 -r 2ca4213fb50a OrthancServer/UnitTestsSources/ServerJobsTests.cpp --- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Wed Nov 17 10:08:44 2021 +0100 +++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Tue Nov 23 09:20:59 2021 +0100 @@ -538,7 +538,8 @@ std::unique_ptr toStore(DicomInstanceToStore::CreateFromParsedDicomFile(dicom)); - return (context_->Store(id, *toStore, StoreInstanceMode_Default) == StoreStatus_Success); + ServerContext::StoreResult result = context_->Store(id, *toStore, StoreInstanceMode_Default); + return (result.GetStatus() == StoreStatus_Success); } }; }