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 {