Mercurial > hg > orthanc
changeset 6369:99f6accf4270
Get SCU jobs details
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Fri, 07 Nov 2025 15:02:25 +0100 |
| parents | 41152b638a4a |
| children | 7c8e00ea7830 |
| files | NEWS OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.cpp OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.h |
| diffstat | 4 files changed, 120 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Wed Nov 05 15:52:01 2025 +0100 +++ b/NEWS Fri Nov 07 15:02:25 2025 +0100 @@ -15,6 +15,10 @@ actually failed. * C-Store, C-Move and C-Get jobs and HTTP responses now include a new "DimseErrorStatus" field (ONLY if the operation fails). +* C-Get jobs and HTTP responses now include a new "Details" field with the "DimseErrorStatus" + of each operation and the list of "RetrievedInstancesIds". Note that, if you have multiple + resources to retrieve and one of them fails, you'll only get those details if you have set + "Permissive" to true to allow other operations to continue after the failure. Maintenance
--- a/OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp Wed Nov 05 15:52:01 2025 +0100 +++ b/OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp Fri Nov 07 15:02:25 2025 +0100 @@ -46,7 +46,7 @@ const std::string& calledAet) { // this code is equivalent to OrthancStoreRequestHandler - ServerContext* context = reinterpret_cast<ServerContext*>(callbackContext); + DicomRetrieveScuBaseJob* job = reinterpret_cast<DicomRetrieveScuBaseJob*>(callbackContext); std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromDcmDataset(dataset)); @@ -56,7 +56,14 @@ (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str())); std::string id; - ServerContext::StoreResult result = context->Store(id, *toStore, StoreInstanceMode_Default); + ServerContext::StoreResult result = job->GetContext().Store(id, *toStore, StoreInstanceMode_Default); + + // keep track of the received instances in the job + if (result.GetStatus() == StoreStatus_Success || result.GetStatus() == StoreStatus_AlreadyStored) + { + job->AddReceivedInstance(id); + } + return result.GetCStoreStatusCode(); } @@ -99,7 +106,7 @@ } connection_->SetProgressListener(this); - connection_->Get(findAnswer, InstanceReceivedHandler, &context_); + connection_->Get(findAnswer, InstanceReceivedHandler, this); } void DicomGetScuJob::AddFindAnswer(const DicomMap& answer)
--- a/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.cpp Wed Nov 05 15:52:01 2025 +0100 +++ b/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.cpp Fri Nov 07 15:02:25 2025 +0100 @@ -39,6 +39,53 @@ namespace Orthanc { + bool DicomRetrieveScuBaseJob::Command::Execute(const std::string &jobId) + { + try + { + that_.currentCommand_ = this; + that_.Retrieve(*findAnswer_); // here + } + catch (OrthancException& e) + { + dimseErrorStatus_ = e.GetDimseErrorStatus(); + throw e; + } + return true; + } + + void DicomRetrieveScuBaseJob::Command::Serialize(Json::Value &target) const + { + findAnswer_->Serialize(target["Query"]); + target["DimseErrorStatus"] = dimseErrorStatus_; + SerializationToolbox::WriteListOfStrings(target, receivedInstancesIds_, "ReceivedInstancesIds"); + } + + SetOfCommandsJob::ICommand* DicomRetrieveScuBaseJob::Unserializer::Unserialize(const Json::Value &source) const + { + DicomMap findAnswer; + + if (!source.isMember("Query")) // old format before 1.12.10, just in case we need to read old jobs after an upgrade + { + findAnswer.Unserialize(source); + return new DicomRetrieveScuBaseJob::Command(that_, findAnswer); + } + + findAnswer.Unserialize(source["Query"]); + + std::unique_ptr<DicomRetrieveScuBaseJob::Command> command(new DicomRetrieveScuBaseJob::Command(that_, findAnswer)); + command->SetDimseErrorStatus(static_cast<uint16_t>(source["DimseErrorStatus"].asUInt())); + + std::list<std::string> receivedInstancesIds; + SerializationToolbox::ReadListOfStrings(receivedInstancesIds, source, "ReceivedInstancesIds"); + for (std::list<std::string>::const_iterator it = receivedInstancesIds.begin(); it != receivedInstancesIds.end(); ++it) + { + command->AddReceivedInstance(*it); + } + + return command.release(); + } + static void AddToQuery(DicomFindAnswers& query, const DicomMap& item) { @@ -152,6 +199,20 @@ value[QUERY] = Json::objectValue; query_.ToJson(value[QUERY], queryFormat_); + + value["Details"] = Json::arrayValue; + + for (size_t i = 0; i < GetCommandsCount(); ++i) + { + const DicomRetrieveScuBaseJob::Command& command = dynamic_cast<const DicomRetrieveScuBaseJob::Command&>(GetCommand(i)); + + Json::Value v; + v["DimseErrorStatus"] = command.GetDimseErrorStatus(); + query_.ToJson(v["Query"], i, DicomToJsonFormat_Short); + SerializationToolbox::WriteListOfStrings(v, command.GetReceivedInstancesIds(), "ReceivedInstancesIds"); + + value["Details"].append(v); + } } @@ -162,7 +223,8 @@ nbRemainingSubOperations_(0), nbCompletedSubOperations_(0), nbFailedSubOperations_(0), - nbWarningSubOperations_(0) + nbWarningSubOperations_(0), + currentCommand_(NULL) { } @@ -172,12 +234,13 @@ SetOfCommandsJob(new Unserializer(*this), serialized), context_(context), parameters_(DicomAssociationParameters::UnserializeJob(serialized)), - query_(true), + query_(false /* this is not for worklists */), queryFormat_(DicomToJsonFormat_Short), nbRemainingSubOperations_(0), nbCompletedSubOperations_(0), nbFailedSubOperations_(0), - nbWarningSubOperations_(0) + nbWarningSubOperations_(0), + currentCommand_(NULL) { if (serialized.isMember(QUERY)) { @@ -245,4 +308,12 @@ return float(nbCompletedSubOperations_ + nbFailedSubOperations_ + nbWarningSubOperations_) / float(totalOperations); } + + void DicomRetrieveScuBaseJob::AddReceivedInstance(const std::string& instanceId) + { + if (currentCommand_ != NULL) + { + currentCommand_->AddReceivedInstance(instanceId); + } + } }
--- a/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.h Wed Nov 05 15:52:01 2025 +0100 +++ b/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.h Fri Nov 07 15:02:25 2025 +0100 @@ -42,23 +42,40 @@ DicomRetrieveScuBaseJob &that_; std::unique_ptr<DicomMap> findAnswer_; + uint16_t dimseErrorStatus_; + std::list<std::string> receivedInstancesIds_; + public: Command(DicomRetrieveScuBaseJob &that, const DicomMap &findAnswer) : that_(that), - findAnswer_(findAnswer.Clone()) + findAnswer_(findAnswer.Clone()), + dimseErrorStatus_(0) { } - virtual bool Execute(const std::string &jobId) ORTHANC_OVERRIDE + virtual bool Execute(const std::string &jobId) ORTHANC_OVERRIDE; + + virtual void Serialize(Json::Value &target) const ORTHANC_OVERRIDE; + + uint16_t GetDimseErrorStatus() const { - that_.Retrieve(*findAnswer_); - return true; + return dimseErrorStatus_; } - virtual void Serialize(Json::Value &target) const ORTHANC_OVERRIDE + void SetDimseErrorStatus(uint16_t dimseErrorStatus) + { + dimseErrorStatus_ = dimseErrorStatus; + } + + void AddReceivedInstance(const std::string& instanceId) { - findAnswer_->Serialize(target); + receivedInstancesIds_.push_back(instanceId); + } + + const std::list<std::string>& GetReceivedInstancesIds() const + { + return receivedInstancesIds_; } }; @@ -73,12 +90,7 @@ { } - virtual ICommand *Unserialize(const Json::Value &source) const ORTHANC_OVERRIDE - { - DicomMap findAnswer; - findAnswer.Unserialize(source); - return new Command(that_, findAnswer); - } + virtual ICommand *Unserialize(const Json::Value &source) const ORTHANC_OVERRIDE; }; ServerContext &context_; @@ -94,6 +106,8 @@ uint16_t nbFailedSubOperations_; uint16_t nbWarningSubOperations_; + Command* currentCommand_; + virtual void Retrieve(const DicomMap &findAnswer) = 0; explicit DicomRetrieveScuBaseJob(ServerContext &context); @@ -145,5 +159,11 @@ return true; } + ServerContext& GetContext() + { + return context_; + } + + void AddReceivedInstance(const std::string& instanceId); }; }
