Mercurial > hg > orthanc
diff OrthancServer/Plugins/Engine/OrthancPlugins.cpp @ 4943:47d734fa30f6
adding function OrthancPluginRegisterWebDavCollection() to the plugin SDK
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 16 Mar 2022 17:21:02 +0100 |
parents | 309fb4f02704 |
children | 964bbf5cb365 |
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Mar 16 10:55:13 2022 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Mar 16 17:21:02 2022 +0100 @@ -39,6 +39,7 @@ #include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" #include "../../../OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h" #include "../../../OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h" +#include "../../../OrthancFramework/Sources/HttpServer/HttpServer.h" #include "../../../OrthancFramework/Sources/HttpServer/HttpToolbox.h" #include "../../../OrthancFramework/Sources/Images/Image.h" #include "../../../OrthancFramework/Sources/Images/ImageProcessing.h" @@ -75,6 +76,344 @@ namespace Orthanc { + class OrthancPlugins::WebDavCollection : public IWebDavBucket + { + private: + PluginsErrorDictionary& errorDictionary_; + std::string uri_; + OrthancPluginWebDavIsExistingFolderCallback isExistingFolder_; + OrthancPluginWebDavListFolderCallback listFolder_; + OrthancPluginWebDavRetrieveFileCallback retrieveFile_; + OrthancPluginWebDavStoreFileCallback storeFile_; + OrthancPluginWebDavCreateFolderCallback createFolder_; + OrthancPluginWebDavDeleteItemCallback deleteItem_; + void* payload_; + + class PathHelper : public boost::noncopyable + { + private: + std::vector<const char*> items_; + + public: + PathHelper(const std::vector<std::string>& path) + { + items_.resize(path.size()); + for (size_t i = 0; i < path.size(); i++) + { + items_[i] = path[i].c_str(); + } + } + + uint32_t GetSize() const + { + return static_cast<uint32_t>(items_.size()); + } + + const char* const* GetItems() const + { + return (items_.empty() ? NULL : &items_[0]); + } + }; + + + static MimeType ParseMimeType(const char* mimeType) + { + MimeType mime; + if (LookupMimeType(mime, mimeType)) + { + return mime; + } + else + { + LOG(WARNING) << "Unknown MIME type in plugin: " << mimeType; + return MimeType_Binary; + } + } + + static OrthancPluginErrorCode AddFile( + OrthancPluginWebDavCollection* collection, + const char* displayName, + uint64_t contentSize, + const char* mimeType, + const char* creationTime) + { + try + { + std::unique_ptr<File> f(new File(displayName)); + f->SetCreationTime(boost::posix_time::from_iso_string(creationTime)); + f->SetContentLength(contentSize); + + if (mimeType == NULL || + std::string(mimeType).empty()) + { + f->SetMimeType(SystemToolbox::AutodetectMimeType(displayName)); + } + else + { + f->SetMimeType(ParseMimeType(mimeType)); + } + + reinterpret_cast<Collection*>(collection)->AddResource(f.release()); + return OrthancPluginErrorCode_Success; + } + catch (OrthancException& e) + { + return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_InternalError; + } + } + + static OrthancPluginErrorCode AddFolder( + OrthancPluginWebDavCollection* collection, + const char* displayName, + const char* creationTime) + { + try + { + std::unique_ptr<Folder> f(new Folder(displayName)); + f->SetCreationTime(boost::posix_time::from_iso_string(creationTime)); + reinterpret_cast<Collection*>(collection)->AddResource(f.release()); + return OrthancPluginErrorCode_Success; + } + catch (OrthancException& e) + { + return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + LOG(ERROR) << "Presumably ill-formed date in the plugin"; + return OrthancPluginErrorCode_ParameterOutOfRange; + } + catch (...) + { + return OrthancPluginErrorCode_InternalError; + } + } + + + class ContentTarget : public boost::noncopyable + { + private: + bool isSent_; + MimeType& mime_; + std::string& content_; + boost::posix_time::ptime& modificationTime_; + + public: + ContentTarget(const std::string& displayName, + MimeType& mime, + std::string& content, + boost::posix_time::ptime& modificationTime) : + isSent_(false), + mime_(mime), + content_(content), + modificationTime_(modificationTime) + { + mime = SystemToolbox::AutodetectMimeType(displayName); + } + + bool IsSent() const + { + return isSent_; + } + + static OrthancPluginErrorCode RetrieveFile( + OrthancPluginWebDavCollection* collection, + const void* data, + uint64_t size, + const char* mimeType, + const char* creationTime) + { + ContentTarget& target = *reinterpret_cast<ContentTarget*>(collection); + + if (target.isSent_) + { + return OrthancPluginErrorCode_BadSequenceOfCalls; + } + else + { + try + { + target.isSent_ = true; + + if (mimeType != NULL && + !std::string(mimeType).empty()) + { + target.mime_ = ParseMimeType(mimeType); + } + + target.content_.assign(reinterpret_cast<const char*>(data), size); + target.modificationTime_ = boost::posix_time::from_iso_string(creationTime); + return OrthancPluginErrorCode_Success; + } + catch (Orthanc::OrthancException& e) + { + return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + LOG(ERROR) << "Presumably ill-formed date in the plugin"; + return OrthancPluginErrorCode_ParameterOutOfRange; + } + catch (...) + { + return OrthancPluginErrorCode_InternalError; + } + } + } + }; + + + public: + WebDavCollection(PluginsErrorDictionary& errorDictionary, + const _OrthancPluginRegisterWebDavCollection& p) : + errorDictionary_(errorDictionary), + uri_(p.uri), + isExistingFolder_(p.isExistingFolder), + listFolder_(p.listFolder), + retrieveFile_(p.retrieveFile), + storeFile_(p.storeFile), + createFolder_(p.createFolder), + deleteItem_(p.deleteItem), + payload_(p.payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + virtual bool IsExistingFolder(const std::vector<std::string>& path) + { + PathHelper helper(path); + + uint8_t isExisting; + OrthancPluginErrorCode code = isExistingFolder_(&isExisting, helper.GetSize(), helper.GetItems(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return (isExisting != 0); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual bool ListCollection(Collection& collection, + const std::vector<std::string>& path) + { + PathHelper helper(path); + + uint8_t isExisting; + OrthancPluginErrorCode code = listFolder_(&isExisting, reinterpret_cast<OrthancPluginWebDavCollection*>(&collection), + AddFile, AddFolder, helper.GetSize(), helper.GetItems(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return (isExisting != 0); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual bool GetFileContent(MimeType& mime, + std::string& content, + boost::posix_time::ptime& modificationTime, + const std::vector<std::string>& path) + { + PathHelper helper(path); + + ContentTarget target(path.back(), mime, content, modificationTime); + OrthancPluginErrorCode code = retrieveFile_( + reinterpret_cast<OrthancPluginWebDavCollection*>(&target), + ContentTarget::RetrieveFile, helper.GetSize(), helper.GetItems(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return target.IsSent(); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual bool StoreFile(const std::string& content, + const std::vector<std::string>& path) + { + PathHelper helper(path); + + uint8_t isReadOnly; + OrthancPluginErrorCode code = storeFile_(&isReadOnly, helper.GetSize(), helper.GetItems(), + content.empty() ? NULL : content.c_str(), content.size(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return (isReadOnly != 0); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual bool CreateFolder(const std::vector<std::string>& path) + { + PathHelper helper(path); + + uint8_t isReadOnly; + OrthancPluginErrorCode code = createFolder_(&isReadOnly, helper.GetSize(), helper.GetItems(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return (isReadOnly != 0); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual bool DeleteItem(const std::vector<std::string>& path) + { + PathHelper helper(path); + + uint8_t isReadOnly; + OrthancPluginErrorCode code = deleteItem_(&isReadOnly, helper.GetSize(), helper.GetItems(), payload_); + + if (code == OrthancPluginErrorCode_Success) + { + return (isReadOnly != 0); + } + else + { + errorDictionary_.LogError(code, true); + throw OrthancException(static_cast<ErrorCode>(code)); + } + } + + virtual void Start() + { + } + + virtual void Stop() + { + } + }; + + static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, const void* data, size_t size) @@ -1164,6 +1503,7 @@ typedef std::list<OrthancPluginRefreshMetricsCallback> RefreshMetricsCallbacks; typedef std::list<StorageCommitmentScp*> StorageCommitmentScpCallbacks; typedef std::map<Property, std::string> Properties; + typedef std::list<WebDavCollection*> WebDavCollections; PluginsManager manager_; @@ -1184,6 +1524,7 @@ OrthancPluginReceivedInstanceCallback receivedInstanceCallback_; // New in Orthanc 1.10.0 RefreshMetricsCallbacks refreshMetricsCallbacks_; StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; + WebDavCollections webDavCollections_; // New in Orthanc 1.10.1 std::unique_ptr<StorageAreaFactory> storageArea_; std::set<std::string> authorizationTokens_; @@ -1768,7 +2109,13 @@ it != pimpl_->storageCommitmentScpCallbacks_.end(); ++it) { delete *it; - } + } + + for (PImpl::WebDavCollections::iterator it = pimpl_->webDavCollections_.begin(); + it != pimpl_->webDavCollections_.end(); ++it) + { + delete *it; + } } @@ -5265,6 +5612,15 @@ return true; } + case _OrthancPluginService_RegisterWebDavCollection: + { + CLOG(INFO, PLUGINS) << "Plugin has registered a WebDAV collection"; + const _OrthancPluginRegisterWebDavCollection& p = + *reinterpret_cast<const _OrthancPluginRegisterWebDavCollection*>(parameters); + pimpl_->webDavCollections_.push_back(new WebDavCollection(GetErrorDictionary(), p)); + return true; + } + default: { // This service is unknown to the Orthanc plugin engine @@ -5862,4 +6218,22 @@ boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); return pimpl_->maxDatabaseRetries_; } + + + void OrthancPlugins::RegisterWebDavCollections(HttpServer& target) + { + boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); + + while (!pimpl_->webDavCollections_.empty()) + { + WebDavCollection* collection = pimpl_->webDavCollections_.front(); + assert(collection != NULL); + + UriComponents components; + Toolbox::SplitUriComponents(components, collection->GetUri()); + target.Register(components, collection); + + pimpl_->webDavCollections_.pop_front(); + } + } }