comparison OrthancServer/Sources/main.cpp @ 4231:290ffcb0a147

publishing the DICOM hierarchy as WebDAV bucket
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 06 Oct 2020 20:55:16 +0200
parents b313a0001893
children 688435755466
comparison
equal deleted inserted replaced
4230:b313a0001893 4231:290ffcb0a147
56 #include "ServerJobs/StorageCommitmentScpJob.h" 56 #include "ServerJobs/StorageCommitmentScpJob.h"
57 #include "ServerToolbox.h" 57 #include "ServerToolbox.h"
58 #include "StorageCommitmentReports.h" 58 #include "StorageCommitmentReports.h"
59 59
60 #include "../../OrthancFramework/Sources/HttpServer/WebDavStorage.h" // TODO 60 #include "../../OrthancFramework/Sources/HttpServer/WebDavStorage.h" // TODO
61 #include "Search/DatabaseLookup.h" // TODO
61 62
62 63
63 using namespace Orthanc; 64 using namespace Orthanc;
64 65
65 66
761 } 762 }
762 763
763 virtual void Stop() ORTHANC_OVERRIDE 764 virtual void Stop() ORTHANC_OVERRIDE
764 { 765 {
765 LOG(WARNING) << "Stopping WebDAV"; 766 LOG(WARNING) << "Stopping WebDAV";
767 }
768 };
769
770
771
772
773
774 static const char* const DICOM_IDENTIFIERS = "DicomIdentifiers";
775
776 class DummyBucket2 : public IWebDavBucket // TODO
777 {
778 private:
779 ServerContext& context_;
780
781 class DicomIdentifiersVisitor : public ServerContext::ILookupVisitor
782 {
783 private:
784 ServerContext& context_;
785 bool isComplete_;
786 Collection& target_;
787 ResourceType level_;
788
789 public:
790 DicomIdentifiersVisitor(ServerContext& context,
791 Collection& target,
792 ResourceType level) :
793 context_(context),
794 isComplete_(false),
795 target_(target),
796 level_(level)
797 {
798 }
799
800 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
801 {
802 return false; // (*)
803 }
804
805 virtual void MarkAsComplete() ORTHANC_OVERRIDE
806 {
807 isComplete_ = true; // TODO
808 }
809
810 virtual void Visit(const std::string& publicId,
811 const std::string& instanceId /* unused */,
812 const DicomMap& mainDicomTags,
813 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE
814 {
815 DicomTag tag(0, 0);
816 switch (level_)
817 {
818 case ResourceType_Study:
819 tag = DICOM_TAG_STUDY_INSTANCE_UID;
820 break;
821
822 case ResourceType_Series:
823 tag = DICOM_TAG_SERIES_INSTANCE_UID;
824 break;
825
826 case ResourceType_Instance:
827 tag = DICOM_TAG_SOP_INSTANCE_UID;
828 break;
829
830 default:
831 throw OrthancException(ErrorCode_InternalError);
832 }
833
834 std::string s;
835 if (mainDicomTags.LookupStringValue(s, tag, false) &&
836 !s.empty())
837 {
838 if (level_ == ResourceType_Instance)
839 {
840 FileInfo info;
841 if (context_.GetIndex().LookupAttachment(info, publicId, FileContentType_Dicom))
842 {
843 std::unique_ptr<File> f(new File(s + ".dcm"));
844 f->SetMimeType(MimeType_Dicom);
845 f->SetContentLength(info.GetUncompressedSize());
846 target_.AddResource(f.release());
847 }
848 }
849 else
850 {
851 target_.AddResource(new Folder(s));
852 }
853 }
854 }
855 };
856
857 class DicomFileVisitor : public ServerContext::ILookupVisitor
858 {
859 private:
860 ServerContext& context_;
861 bool success_;
862 std::string& target_;
863
864 public:
865 DicomFileVisitor(ServerContext& context,
866 std::string& target) :
867 context_(context),
868 success_(false),
869 target_(target)
870 {
871 }
872
873 bool IsSuccess() const
874 {
875 return success_;
876 }
877
878 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
879 {
880 return false; // (*)
881 }
882
883 virtual void MarkAsComplete() ORTHANC_OVERRIDE
884 {
885 }
886
887 virtual void Visit(const std::string& publicId,
888 const std::string& instanceId /* unused */,
889 const DicomMap& mainDicomTags,
890 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE
891 {
892 context_.ReadDicom(target_, publicId);
893 success_ = true;
894 }
895 };
896
897 public:
898 DummyBucket2(ServerContext& context) :
899 context_(context)
900 {
901 }
902
903 virtual bool IsExistingFolder(const UriComponents& path) ORTHANC_OVERRIDE
904 {
905 if (path.empty())
906 {
907 return true;
908 }
909 else if (path.front() == DICOM_IDENTIFIERS &&
910 path.size() <= 3)
911 {
912 return true;
913 }
914 else
915 {
916 return false;
917 }
918 }
919
920 virtual bool ListCollection(Collection& collection,
921 const UriComponents& path) ORTHANC_OVERRIDE
922 {
923 if (path.empty())
924 {
925 collection.AddResource(new Folder(DICOM_IDENTIFIERS));
926 return true;
927 }
928 else if (path.front() == DICOM_IDENTIFIERS)
929 {
930 DatabaseLookup query;
931 ResourceType level;
932
933 if (path.size() == 1)
934 {
935 level = ResourceType_Study;
936 }
937 else if (path.size() == 2)
938 {
939 level = ResourceType_Series;
940 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1],
941 true /* case sensitive */, true /* mandatory tag */);
942 }
943 else if (path.size() == 3)
944 {
945 level = ResourceType_Instance;
946 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1],
947 true /* case sensitive */, true /* mandatory tag */);
948 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2],
949 true /* case sensitive */, true /* mandatory tag */);
950 }
951 else
952 {
953 return false;
954 }
955
956 DicomIdentifiersVisitor visitor(context_, collection, level);
957 context_.Apply(visitor, query, level, 0 /* since */, 100 /* limit */);
958
959 return true;
960 }
961 else
962 {
963 return false;
964 }
965 }
966
967 virtual bool GetFileContent(MimeType& mime,
968 std::string& content,
969 boost::posix_time::ptime& modificationTime,
970 const UriComponents& path) ORTHANC_OVERRIDE
971 {
972 if (path.size() == 4 &&
973 path[0] == DICOM_IDENTIFIERS &&
974 boost::ends_with(path[3], ".dcm"))
975 {
976 std::string sopInstanceUid = path[3];
977 sopInstanceUid.resize(sopInstanceUid.size() - 4);
978
979 mime = MimeType_Dicom;
980
981 DatabaseLookup query;
982 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1],
983 true /* case sensitive */, true /* mandatory tag */);
984 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2],
985 true /* case sensitive */, true /* mandatory tag */);
986 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid,
987 true /* case sensitive */, true /* mandatory tag */);
988
989 DicomFileVisitor visitor(context_, content);
990 context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 100 /* limit */);
991
992 return visitor.IsSuccess();
993 }
994 else
995 {
996 return false;
997 }
998 }
999
1000
1001 virtual bool StoreFile(const std::string& content,
1002 const UriComponents& path) ORTHANC_OVERRIDE
1003 {
1004 return false;
1005 }
1006
1007
1008 virtual bool CreateFolder(const UriComponents& path)
1009 {
1010 return false;
1011 }
1012
1013 virtual void Start() ORTHANC_OVERRIDE
1014 {
1015 }
1016
1017 virtual void Stop() ORTHANC_OVERRIDE
1018 {
766 } 1019 }
767 }; 1020 };
768 1021
769 1022
770 1023
1208 { 1461 {
1209 UriComponents root; // TODO 1462 UriComponents root; // TODO
1210 root.push_back("a"); 1463 root.push_back("a");
1211 root.push_back("b"); 1464 root.push_back("b");
1212 //httpServer.Register(root, new WebDavStorage(true)); 1465 //httpServer.Register(root, new WebDavStorage(true));
1213 httpServer.Register(root, new DummyBucket(context, true)); 1466 //httpServer.Register(root, new DummyBucket(context, true));
1467 httpServer.Register(root, new DummyBucket2(context));
1214 } 1468 }
1215 1469
1216 if (httpServer.GetPortNumber() < 1024) 1470 if (httpServer.GetPortNumber() < 1024)
1217 { 1471 {
1218 LOG(WARNING) << "The HTTP port is privileged (" 1472 LOG(WARNING) << "The HTTP port is privileged ("