# HG changeset patch # User Alain Mazy # Date 1686588126 -7200 # Node ID b5c502bcaf9970c18a7c332a4ac5abd4dfb8a2fb # Parent fb231da5c0f119c299de2206a0dd60a0587e433e added a route to DELETE /jobs/../archive diff -r fb231da5c0f1 -r b5c502bcaf99 NEWS --- a/NEWS Wed Jun 07 10:48:14 2023 +0200 +++ b/NEWS Mon Jun 12 18:42:06 2023 +0200 @@ -1,6 +1,13 @@ Pending changes in the mainline =============================== +REST API +-------- + +* API version upgraded to 21 +* added a route to delete the output of an asynchronous job (right now only for archive jobs): + e.g. DELETE /jobs/../archive + Maintenance ----------- diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/Cache/SharedArchive.cpp --- a/OrthancFramework/Sources/Cache/SharedArchive.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -102,7 +102,7 @@ std::string SharedArchive::Add(IDynamicObject* obj) { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); if (archive_.size() == maxSize_) { @@ -122,7 +122,7 @@ void SharedArchive::Remove(const std::string& id) { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); RemoveInternal(id); } @@ -132,7 +132,7 @@ items.clear(); { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); for (Archive::const_iterator it = archive_.begin(); it != archive_.end(); ++it) diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/Cache/SharedArchive.h --- a/OrthancFramework/Sources/Cache/SharedArchive.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.h Mon Jun 12 18:42:06 2023 +0200 @@ -44,9 +44,9 @@ private: typedef std::map Archive; - size_t maxSize_; - boost::mutex mutex_; - Archive archive_; + size_t maxSize_; + boost::recursive_mutex mutex_; + Archive archive_; LeastRecentlyUsedIndex lru_; void RemoveInternal(const std::string& id); @@ -55,8 +55,8 @@ class ORTHANC_PUBLIC Accessor : public boost::noncopyable { private: - boost::mutex::scoped_lock lock_; - IDynamicObject* item_; + boost::recursive_mutex::scoped_lock lock_; + IDynamicObject* item_; public: Accessor(SharedArchive& that, diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/IJob.h --- a/OrthancFramework/Sources/JobsEngine/IJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -62,5 +62,9 @@ MimeType& mime, std::string& filename, const std::string& key) = 0; + + // This function can only be called if the job has reached its + // "success" state + virtual bool DeleteOutput(const std::string& key) = 0; }; } diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp --- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -679,6 +679,33 @@ } } + bool JobsRegistry::DeleteJobOutput(const std::string& job, + const std::string& key) + { + boost::mutex::scoped_lock lock(mutex_); + CheckInvariants(); + + JobsIndex::const_iterator found = jobsIndex_.find(job); + + if (found == jobsIndex_.end()) + { + return false; + } + else + { + const JobHandler& handler = *found->second; + + if (handler.GetState() == JobState_Success) + { + return handler.GetJob().DeleteOutput(key); + } + else + { + return false; + } + } + } + void JobsRegistry::SubmitInternal(std::string& id, JobHandler* handler) diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/JobsRegistry.h --- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Mon Jun 12 18:42:06 2023 +0200 @@ -153,6 +153,9 @@ const std::string& job, const std::string& key); + bool DeleteJobOutput(const std::string& job, + const std::string& key); + void Serialize(Json::Value& target); void Submit(std::string& id, diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -447,13 +447,6 @@ return true; } - bool SequenceOfOperationsJob::GetOutput(std::string& output, - MimeType& mime, - std::string& filename, - const std::string& key) - { - return false; - } void SequenceOfOperationsJob::AwakeTrailingSleep() { diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h --- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -127,7 +127,15 @@ virtual bool GetOutput(std::string& output, MimeType& mime, std::string& filename, - const std::string& key) ORTHANC_OVERRIDE; + const std::string& key) ORTHANC_OVERRIDE + { + return false; + } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } void AwakeTrailingSleep(); }; diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp --- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -269,14 +269,6 @@ return true; } - bool SetOfCommandsJob::GetOutput(std::string &output, - MimeType &mime, - std::string& filename, - const std::string &key) - { - return false; - } - SetOfCommandsJob::SetOfCommandsJob(ICommandUnserializer* unserializer, const Json::Value& source) : diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h --- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -106,6 +106,14 @@ virtual bool GetOutput(std::string& output, MimeType& mime, std::string& filename, - const std::string& key) ORTHANC_OVERRIDE; + const std::string& key) ORTHANC_OVERRIDE + { + return false; + } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } }; } diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancFramework/UnitTestsSources/JobsTests.cpp --- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -131,6 +131,11 @@ { return false; } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } }; diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Plugins/Engine/PluginsJob.h --- a/OrthancServer/Plugins/Engine/PluginsJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -76,6 +76,12 @@ // TODO return false; } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + // TODO + return false; + } }; } diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -770,6 +770,36 @@ } + static void DeleteJobOutput(RestApiDeleteCall& call) + { + if (call.IsDocumentation()) + { + call.GetDocumentation() + .SetTag("Jobs") + .SetSummary("Delete a job output") + .SetDescription("Delete the output produced by a job. As of Orthanc 1.12.1, only the jobs that generate a " + "DICOMDIR media or a ZIP archive provide such an output (with `key` equals to `archive`).") + .SetUriArgument("id", "Identifier of the job of interest") + .SetUriArgument("key", "Name of the output of interest"); + return; + } + + std::string job = call.GetUriComponent("id", ""); + std::string key = call.GetUriComponent("key", ""); + + if (OrthancRestApi::GetContext(call).GetJobsEngine(). + GetRegistry().DeleteJobOutput(job, key)) + { + call.GetOutput().AnswerBuffer("", MimeType_PlainText); + } + else + { + throw OrthancException(ErrorCode_InexistentItem, + "Job has no such output: " + key); + } + } + + enum JobAction { JobAction_Cancel, @@ -1113,6 +1143,7 @@ Register("/jobs/{id}/resubmit", ApplyJobAction); Register("/jobs/{id}/resume", ApplyJobAction); Register("/jobs/{id}/{key}", GetJobOutput); + Register("/jobs/{id}/{key}", DeleteJobOutput); // New in Orthanc 1.9.0 Register("/tools/accepted-transfer-syntaxes", GetAcceptedTransferSyntaxes); diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Sources/ServerJobs/ArchiveJob.cpp --- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -1459,4 +1459,27 @@ return false; } } + + bool ArchiveJob::DeleteOutput(const std::string& key) + { + if (key == "archive" && + !mediaArchiveId_.empty()) + { + SharedArchive::Accessor accessor(context_.GetMediaArchive(), mediaArchiveId_); + + if (accessor.IsValid()) + { + context_.GetMediaArchive().Remove(mediaArchiveId_); + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } } diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Sources/ServerJobs/ArchiveJob.h --- a/OrthancServer/Sources/ServerJobs/ArchiveJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -120,5 +120,7 @@ MimeType& mime, std::string& filename, const std::string& key) ORTHANC_OVERRIDE; + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE; }; } diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp --- a/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -295,15 +295,6 @@ } - bool ThreadedSetOfInstancesJob::GetOutput(std::string &output, - MimeType &mime, - std::string& filename, - const std::string &key) - { - return false; - } - - size_t ThreadedSetOfInstancesJob::GetInstancesCount() const { boost::recursive_mutex::scoped_lock lock(mutex_); diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.h --- a/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.h Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.h Mon Jun 12 18:42:06 2023 +0200 @@ -152,7 +152,15 @@ virtual bool GetOutput(std::string& output, MimeType& mime, std::string& filename, - const std::string& key) ORTHANC_OVERRIDE; + const std::string& key) ORTHANC_OVERRIDE + { + return false; + } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } bool IsFailedInstance(const std::string& instance) const; diff -r fb231da5c0f1 -r b5c502bcaf99 OrthancServer/UnitTestsSources/ServerJobsTests.cpp --- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Wed Jun 07 10:48:14 2023 +0200 +++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Mon Jun 12 18:42:06 2023 +0200 @@ -134,6 +134,11 @@ { return false; } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } };