Mercurial > hg > orthanc
diff OrthancServer/ServerJobs/ArchiveJob.cpp @ 2976:cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 06 Dec 2018 12:23:46 +0100 |
parents | 10c610e80b15 |
children | 4e43e67f8ecf |
line wrap: on
line diff
--- a/OrthancServer/ServerJobs/ArchiveJob.cpp Thu Dec 06 10:10:58 2018 +0100 +++ b/OrthancServer/ServerJobs/ArchiveJob.cpp Thu Dec 06 12:23:46 2018 +0100 @@ -47,7 +47,12 @@ static const uint64_t MEGA_BYTES = 1024 * 1024; static const uint64_t GIGA_BYTES = 1024 * 1024 * 1024; -static const char* MEDIA_IMAGES_FOLDER = "IMAGES"; + +static const char* const MEDIA_IMAGES_FOLDER = "IMAGES"; +static const char* const KEY_DESCRIPTION = "Description"; +static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; +static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; + namespace Orthanc { @@ -791,6 +796,15 @@ { } + + ArchiveJob::~ArchiveJob() + { + if (!mediaArchiveId_.empty()) + { + context_.GetMediaArchive().Remove(mediaArchiveId_); + } + } + void ArchiveJob::SetSynchronousTarget(boost::shared_ptr<TemporaryFile>& target) { @@ -798,7 +812,9 @@ { throw OrthancException(ErrorCode_NullPointer); } - else if (synchronousTarget_.get() != NULL) + else if (writer_.get() != NULL || // Already started + synchronousTarget_.get() != NULL || + asynchronousTarget_.get() != NULL) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } @@ -809,15 +825,30 @@ } + void ArchiveJob::SetDescription(const std::string& description) + { + if (writer_.get() != NULL) // Already started + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + description_ = description; + } + } + + void ArchiveJob::AddResource(const std::string& publicId) { if (writer_.get() != NULL) // Already started { throw OrthancException(ErrorCode_BadSequenceOfCalls); } - - ResourceIdentifiers resource(context_.GetIndex(), publicId); - archive_->Add(context_.GetIndex(), resource); + else + { + ResourceIdentifiers resource(context_.GetIndex(), publicId); + archive_->Add(context_.GetIndex(), resource); + } } @@ -830,9 +861,16 @@ void ArchiveJob::Start() { + TemporaryFile* target = NULL; + if (synchronousTarget_.get() == NULL) { - throw OrthancException(ErrorCode_BadSequenceOfCalls); + asynchronousTarget_.reset(new TemporaryFile); + target = asynchronousTarget_.get(); + } + else + { + target = synchronousTarget_.get(); } if (writer_.get() != NULL) @@ -840,19 +878,59 @@ throw OrthancException(ErrorCode_BadSequenceOfCalls); } - writer_.reset(new ZipWriterIterator(*synchronousTarget_, context_, *archive_, + writer_.reset(new ZipWriterIterator(*target, context_, *archive_, isMedia_, enableExtendedSopClass_)); instancesCount_ = writer_->GetInstancesCount(); uncompressedSize_ = writer_->GetUncompressedSize(); } + + + namespace + { + class DynamicTemporaryFile : public IDynamicObject + { + private: + std::auto_ptr<TemporaryFile> file_; + + public: + DynamicTemporaryFile(TemporaryFile* f) : file_(f) + { + if (f == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + } + + const TemporaryFile& GetFile() const + { + assert(file_.get() != NULL); + return *file_; + } + }; + } + + void ArchiveJob::FinalizeTarget() + { + writer_.reset(); // Flush all the results + + if (asynchronousTarget_.get() != NULL) + { + // Asynchronous behavior: Move the resulting file into the media archive + mediaArchiveId_ = context_.GetMediaArchive().Add( + new DynamicTemporaryFile(asynchronousTarget_.release())); + } + } + + JobStepResult ArchiveJob::Step() { assert(writer_.get() != NULL); - if (synchronousTarget_.unique()) + if (synchronousTarget_.get() != NULL && + synchronousTarget_.unique()) { LOG(WARNING) << "A client has disconnected while creating an archive"; return JobStepResult::Failure(ErrorCode_NetworkProtocol); @@ -860,7 +938,7 @@ if (writer_->GetStepsCount() == 0) { - writer_.reset(); // Flush all the results + FinalizeTarget(); return JobStepResult::Success(); } else @@ -871,7 +949,7 @@ if (currentStep_ == writer_->GetStepsCount()) { - writer_.reset(); // Flush all the results + FinalizeTarget(); return JobStepResult::Success(); } else @@ -909,12 +987,41 @@ } } - + void ArchiveJob::GetPublicContent(Json::Value& value) { - value["Description"] = description_; - value["InstancesCount"] = instancesCount_; - value["UncompressedSizeMB"] = + value = Json::objectValue; + value[KEY_DESCRIPTION] = description_; + value[KEY_INSTANCES_COUNT] = instancesCount_; + value[KEY_UNCOMPRESSED_SIZE_MB] = static_cast<unsigned int>(uncompressedSize_ / MEGA_BYTES); } + + + bool ArchiveJob::GetOutput(std::string& output, + MimeType& mime, + const std::string& key) + { + if (key == "archive" && + !mediaArchiveId_.empty()) + { + SharedArchive::Accessor accessor(context_.GetMediaArchive(), mediaArchiveId_); + + if (accessor.IsValid()) + { + const DynamicTemporaryFile& f = dynamic_cast<DynamicTemporaryFile&>(accessor.GetItem()); + f.GetFile().Read(output); + mime = MimeType_Zip; + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } }