Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestArchive.cpp @ 2630:00327e989458 jobs
creating archives/medias is now a job
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 25 May 2018 16:09:59 +0200 |
parents | db895b36f4c5 |
children | 2406ae891747 |
comparison
equal
deleted
inserted
replaced
2629:db895b36f4c5 | 2630:00327e989458 |
---|---|
771 commands_.Apply(*zip_, context_, index); | 771 commands_.Apply(*zip_, context_, index); |
772 } | 772 } |
773 } | 773 } |
774 } | 774 } |
775 | 775 |
776 void RunAllSteps() | 776 unsigned int GetInstancesCount() const |
777 { | 777 { |
778 for (size_t i = 0; i < GetStepsCount(); i++) | 778 return commands_.GetInstancesCount(); |
779 { | 779 } |
780 RunStep(i); | 780 |
781 } | 781 uint64_t GetUncompressedSize() const |
782 { | |
783 return commands_.GetUncompressedSize(); | |
782 } | 784 } |
783 }; | 785 }; |
784 | 786 |
785 | 787 |
786 static void CreateArchive(TemporaryFile& tmp, | |
787 ServerContext& context, | |
788 ArchiveIndex& archive) | |
789 { | |
790 ZipWriterIterator writer(tmp, context, archive, false, false); | |
791 writer.RunAllSteps(); | |
792 } | |
793 | |
794 | |
795 static void CreateMedia(TemporaryFile& tmp, | |
796 ServerContext& context, | |
797 ArchiveIndex& archive, | |
798 bool enableExtendedSopClass) | |
799 { | |
800 ZipWriterIterator writer(tmp, context, archive, true, enableExtendedSopClass); | |
801 writer.RunAllSteps(); | |
802 } | |
803 | |
804 | |
805 static void SendTemporaryFile(RestApiOutput& output, | |
806 TemporaryFile& tmp, | |
807 const std::string& filename) | |
808 { | |
809 // Prepare the sending of the ZIP file | |
810 FilesystemHttpSender sender(tmp.GetPath()); | |
811 sender.SetContentType("application/zip"); | |
812 sender.SetContentFilename(filename); | |
813 | |
814 // Send the ZIP | |
815 output.AnswerStream(sender); | |
816 } | |
817 | |
818 | |
819 | |
820 #if 0 | |
821 class ArchiveJob : public IJob | 788 class ArchiveJob : public IJob |
822 { | 789 { |
823 private: | 790 private: |
824 ServerContext& context_; | 791 boost::shared_ptr<TemporaryFile> target_; |
825 ArchiveIndex archive_; | 792 ServerContext& context_; |
826 bool isMedia_; | 793 ArchiveIndex archive_; |
827 std::auto_ptr<TemporaryFile> file_; | 794 bool isMedia_; |
828 std::auto_ptr<HierarchicalZipWriter> writer_; | 795 bool enableExtendedSopClass_; |
829 std::auto_ptr<IArchiveVisitor> visitor_; | 796 std::string description_; |
830 std::string description_; | 797 |
831 bool started_; | 798 std::auto_ptr<ZipWriterIterator> writer_; |
832 unsigned int currentInstance_; | 799 size_t currentStep_; |
800 unsigned int instancesCount_; | |
801 uint64_t uncompressedSize_; | |
833 | 802 |
834 public: | 803 public: |
835 ArchiveJob(ServerContext& context, | 804 ArchiveJob(boost::shared_ptr<TemporaryFile>& target, |
836 ResourceType level, | 805 ServerContext& context, |
837 bool isMedia) : | 806 bool isMedia, |
807 bool enableExtendedSopClass) : | |
808 target_(target), | |
838 context_(context), | 809 context_(context), |
839 archive_(level), | 810 archive_(ResourceType_Patient), // root |
840 isMedia_(isMedia), | 811 isMedia_(isMedia), |
841 started_(false), | 812 enableExtendedSopClass_(enableExtendedSopClass), |
842 currentInstance_(0) | 813 currentStep_(0), |
843 { | 814 instancesCount_(0), |
815 uncompressedSize_(0) | |
816 { | |
817 if (target.get() == NULL) | |
818 { | |
819 throw OrthancException(ErrorCode_NullPointer); | |
820 } | |
821 } | |
822 | |
823 ArchiveIndex& GetIndex() | |
824 { | |
825 if (writer_.get() != NULL) // Already started | |
826 { | |
827 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
828 } | |
829 | |
830 return archive_; | |
844 } | 831 } |
845 | 832 |
846 void SetDescription(const std::string& description) | 833 void SetDescription(const std::string& description) |
847 { | 834 { |
848 description_ = description; | 835 description_ = description; |
853 return description_; | 840 return description_; |
854 } | 841 } |
855 | 842 |
856 void AddResource(const std::string& publicId) | 843 void AddResource(const std::string& publicId) |
857 { | 844 { |
858 if (started_) | 845 if (writer_.get() != NULL) // Already started |
859 { | 846 { |
860 throw OrthancException(ErrorCode_BadSequenceOfCalls); | 847 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
861 } | 848 } |
862 | 849 |
863 ResourceIdentifiers resource(context_.GetIndex(), publicId); | 850 ResourceIdentifiers resource(context_.GetIndex(), publicId); |
870 throw OrthancException(ErrorCode_BadSequenceOfCalls); | 857 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
871 } | 858 } |
872 | 859 |
873 virtual void Start() | 860 virtual void Start() |
874 { | 861 { |
875 if (started_) | 862 if (writer_.get() != NULL) |
876 { | 863 { |
877 throw OrthancException(ErrorCode_BadSequenceOfCalls); | 864 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
878 } | 865 } |
879 | 866 |
880 started_ = true; | 867 writer_.reset(new ZipWriterIterator(*target_, context_, archive_, isMedia_, enableExtendedSopClass_)); |
881 | 868 |
882 archive_.Expand(context_.GetIndex()); | 869 instancesCount_ = writer_->GetInstancesCount(); |
883 | 870 uncompressedSize_ = writer_->GetUncompressedSize(); |
884 const bool isZip64 = IsZip64Required(stats_.GetUncompressedSize(), stats_.GetInstancesCount()); | 871 } |
885 | 872 |
886 file_.reset(new TemporaryFile); | 873 virtual JobStepResult ExecuteStep() |
887 writer_.reset(new HierarchicalZipWriter(file_->GetPath().c_str())); | 874 { |
888 writer_->SetZip64(isZip64); | 875 assert(writer_.get() != NULL); |
889 | 876 |
877 if (target_.unique()) | |
878 { | |
879 LOG(WARNING) << "A client has disconnected while creating an archive"; | |
880 return JobStepResult::Failure(ErrorCode_NetworkProtocol); | |
881 } | |
882 | |
883 if (writer_->GetStepsCount() == 0) | |
884 { | |
885 writer_.reset(NULL); // Flush all the results | |
886 return JobStepResult::Success(); | |
887 } | |
888 else | |
889 { | |
890 writer_->RunStep(currentStep_); | |
891 | |
892 currentStep_ ++; | |
893 | |
894 if (currentStep_ == writer_->GetStepsCount()) | |
895 { | |
896 writer_.reset(NULL); // Flush all the results | |
897 return JobStepResult::Success(); | |
898 } | |
899 else | |
900 { | |
901 return JobStepResult::Continue(); | |
902 } | |
903 } | |
904 } | |
905 | |
906 virtual void ReleaseResources() | |
907 { | |
908 } | |
909 | |
910 virtual float GetProgress() | |
911 { | |
912 if (writer_.get() == NULL || | |
913 writer_->GetStepsCount() == 0) | |
914 { | |
915 return 1; | |
916 } | |
917 else | |
918 { | |
919 return (static_cast<float>(currentStep_) / | |
920 static_cast<float>(writer_->GetStepsCount() - 1)); | |
921 } | |
922 } | |
923 | |
924 virtual void GetJobType(std::string& target) | |
925 { | |
890 if (isMedia_) | 926 if (isMedia_) |
891 { | 927 { |
892 //visitor_.reset(new | 928 target = "Media"; |
893 } | 929 } |
930 else | |
931 { | |
932 target = "Archive"; | |
933 } | |
934 } | |
935 | |
936 virtual void GetPublicContent(Json::Value& value) | |
937 { | |
938 value["Description"] = description_; | |
939 value["InstancesCount"] = instancesCount_; | |
940 value["UncompressedSizeMB"] = static_cast<unsigned int>(uncompressedSize_ / (1024llu * 1024llu)); | |
941 } | |
942 | |
943 virtual void GetInternalContent(Json::Value& value) | |
944 { | |
894 } | 945 } |
895 }; | 946 }; |
896 #endif | |
897 } | 947 } |
898 | 948 |
899 | 949 |
900 static bool AddResourcesOfInterest(ArchiveIndex& archive, | 950 static bool AddResourcesOfInterest(ArchiveIndex& archive, |
901 RestApiPostCall& call) | 951 RestApiPostCall& call) |
924 return false; | 974 return false; |
925 } | 975 } |
926 } | 976 } |
927 | 977 |
928 | 978 |
979 static void SubmitJob(RestApiCall& call, | |
980 boost::shared_ptr<TemporaryFile>& tmp, | |
981 ServerContext& context, | |
982 std::auto_ptr<ArchiveJob>& job, | |
983 const std::string& filename) | |
984 { | |
985 if (job.get() == NULL) | |
986 { | |
987 throw OrthancException(ErrorCode_NullPointer); | |
988 } | |
989 | |
990 job->SetDescription("REST API"); | |
991 | |
992 if (context.GetJobsEngine().GetRegistry().SubmitAndWait(job.release(), 0 /* TODO priority */)) | |
993 { | |
994 // The archive is now created: Prepare the sending of the ZIP file | |
995 FilesystemHttpSender sender(tmp->GetPath()); | |
996 sender.SetContentType("application/zip"); | |
997 sender.SetContentFilename(filename); | |
998 | |
999 // Send the ZIP | |
1000 call.GetOutput().AnswerStream(sender); | |
1001 } | |
1002 else | |
1003 { | |
1004 call.GetOutput().SignalError(HttpStatus_500_InternalServerError); | |
1005 } | |
1006 } | |
1007 | |
1008 | |
929 static void CreateBatchArchive(RestApiPostCall& call) | 1009 static void CreateBatchArchive(RestApiPostCall& call) |
930 { | 1010 { |
931 ArchiveIndex archive(ResourceType_Patient); // root | 1011 ServerContext& context = OrthancRestApi::GetContext(call); |
932 | 1012 |
933 if (AddResourcesOfInterest(archive, call)) | 1013 boost::shared_ptr<TemporaryFile> tmp(new TemporaryFile); |
934 { | 1014 std::auto_ptr<ArchiveJob> job(new ArchiveJob(tmp, context, false, false)); |
935 TemporaryFile tmp; | 1015 |
936 CreateArchive(tmp, OrthancRestApi::GetContext(call), archive); | 1016 if (AddResourcesOfInterest(job->GetIndex(), call)) |
937 SendTemporaryFile(call.GetOutput(), tmp, "Archive.zip"); | 1017 { |
1018 SubmitJob(call, tmp, context, job, "Archive.zip"); | |
938 } | 1019 } |
939 } | 1020 } |
940 | 1021 |
941 | 1022 |
942 template <bool Extended> | 1023 template <bool Extended> |
943 static void CreateBatchMedia(RestApiPostCall& call) | 1024 static void CreateBatchMedia(RestApiPostCall& call) |
944 { | 1025 { |
945 ArchiveIndex archive(ResourceType_Patient); // root | 1026 ServerContext& context = OrthancRestApi::GetContext(call); |
946 | 1027 |
947 if (AddResourcesOfInterest(archive, call)) | 1028 boost::shared_ptr<TemporaryFile> tmp(new TemporaryFile); |
948 { | 1029 std::auto_ptr<ArchiveJob> job(new ArchiveJob(tmp, context, true, Extended)); |
949 TemporaryFile tmp; | 1030 |
950 CreateMedia(tmp, OrthancRestApi::GetContext(call), archive, Extended); | 1031 if (AddResourcesOfInterest(job->GetIndex(), call)) |
951 SendTemporaryFile(call.GetOutput(), tmp, "Archive.zip"); | 1032 { |
1033 SubmitJob(call, tmp, context, job, "Archive.zip"); | |
952 } | 1034 } |
953 } | 1035 } |
954 | 1036 |
955 | 1037 |
956 static void CreateArchive(RestApiGetCall& call) | 1038 static void CreateArchive(RestApiGetCall& call) |
957 { | 1039 { |
958 ServerIndex& index = OrthancRestApi::GetIndex(call); | 1040 ServerContext& context = OrthancRestApi::GetContext(call); |
959 | 1041 |
960 std::string id = call.GetUriComponent("id", ""); | 1042 std::string id = call.GetUriComponent("id", ""); |
961 ResourceIdentifiers resource(index, id); | 1043 ResourceIdentifiers resource(context.GetIndex(), id); |
962 | 1044 |
963 ArchiveIndex archive(ResourceType_Patient); // root | 1045 boost::shared_ptr<TemporaryFile> tmp(new TemporaryFile); |
964 archive.Add(OrthancRestApi::GetIndex(call), resource); | 1046 std::auto_ptr<ArchiveJob> job(new ArchiveJob(tmp, context, false, false)); |
965 | 1047 job->GetIndex().Add(OrthancRestApi::GetIndex(call), resource); |
966 TemporaryFile tmp; | 1048 |
967 CreateArchive(tmp, OrthancRestApi::GetContext(call), archive); | 1049 SubmitJob(call, tmp, context, job, id + ".zip"); |
968 SendTemporaryFile(call.GetOutput(), tmp, id + ".zip"); | |
969 } | 1050 } |
970 | 1051 |
971 | 1052 |
972 static void CreateMedia(RestApiGetCall& call) | 1053 static void CreateMedia(RestApiGetCall& call) |
973 { | 1054 { |
974 ServerIndex& index = OrthancRestApi::GetIndex(call); | 1055 ServerContext& context = OrthancRestApi::GetContext(call); |
975 | 1056 |
976 std::string id = call.GetUriComponent("id", ""); | 1057 std::string id = call.GetUriComponent("id", ""); |
977 ResourceIdentifiers resource(index, id); | 1058 ResourceIdentifiers resource(context.GetIndex(), id); |
978 | 1059 |
979 ArchiveIndex archive(ResourceType_Patient); // root | 1060 boost::shared_ptr<TemporaryFile> tmp(new TemporaryFile); |
980 archive.Add(OrthancRestApi::GetIndex(call), resource); | 1061 std::auto_ptr<ArchiveJob> job(new ArchiveJob(tmp, context, true, call.HasArgument("extended"))); |
981 | 1062 job->GetIndex().Add(OrthancRestApi::GetIndex(call), resource); |
982 TemporaryFile tmp; | 1063 |
983 CreateMedia(tmp, OrthancRestApi::GetContext(call), archive, call.HasArgument("extended")); | 1064 SubmitJob(call, tmp, context, job, id + ".zip"); |
984 SendTemporaryFile(call.GetOutput(), tmp, id + ".zip"); | |
985 } | 1065 } |
986 | 1066 |
987 | 1067 |
988 void OrthancRestApi::RegisterArchive() | 1068 void OrthancRestApi::RegisterArchive() |
989 { | 1069 { |