Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
4942:bd7ad1cb40b6 | 4943:47d734fa30f6 |
---|---|
37 #include "../../../OrthancFramework/Sources/DicomFormat/DicomArray.h" | 37 #include "../../../OrthancFramework/Sources/DicomFormat/DicomArray.h" |
38 #include "../../../OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h" | 38 #include "../../../OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h" |
39 #include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" | 39 #include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" |
40 #include "../../../OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h" | 40 #include "../../../OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h" |
41 #include "../../../OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h" | 41 #include "../../../OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h" |
42 #include "../../../OrthancFramework/Sources/HttpServer/HttpServer.h" | |
42 #include "../../../OrthancFramework/Sources/HttpServer/HttpToolbox.h" | 43 #include "../../../OrthancFramework/Sources/HttpServer/HttpToolbox.h" |
43 #include "../../../OrthancFramework/Sources/Images/Image.h" | 44 #include "../../../OrthancFramework/Sources/Images/Image.h" |
44 #include "../../../OrthancFramework/Sources/Images/ImageProcessing.h" | 45 #include "../../../OrthancFramework/Sources/Images/ImageProcessing.h" |
45 #include "../../../OrthancFramework/Sources/Images/JpegReader.h" | 46 #include "../../../OrthancFramework/Sources/Images/JpegReader.h" |
46 #include "../../../OrthancFramework/Sources/Images/JpegWriter.h" | 47 #include "../../../OrthancFramework/Sources/Images/JpegWriter.h" |
73 #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc SDK is necessary to use buffers > 4GB, but is currently not available" | 74 #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc SDK is necessary to use buffers > 4GB, but is currently not available" |
74 | 75 |
75 | 76 |
76 namespace Orthanc | 77 namespace Orthanc |
77 { | 78 { |
79 class OrthancPlugins::WebDavCollection : public IWebDavBucket | |
80 { | |
81 private: | |
82 PluginsErrorDictionary& errorDictionary_; | |
83 std::string uri_; | |
84 OrthancPluginWebDavIsExistingFolderCallback isExistingFolder_; | |
85 OrthancPluginWebDavListFolderCallback listFolder_; | |
86 OrthancPluginWebDavRetrieveFileCallback retrieveFile_; | |
87 OrthancPluginWebDavStoreFileCallback storeFile_; | |
88 OrthancPluginWebDavCreateFolderCallback createFolder_; | |
89 OrthancPluginWebDavDeleteItemCallback deleteItem_; | |
90 void* payload_; | |
91 | |
92 class PathHelper : public boost::noncopyable | |
93 { | |
94 private: | |
95 std::vector<const char*> items_; | |
96 | |
97 public: | |
98 PathHelper(const std::vector<std::string>& path) | |
99 { | |
100 items_.resize(path.size()); | |
101 for (size_t i = 0; i < path.size(); i++) | |
102 { | |
103 items_[i] = path[i].c_str(); | |
104 } | |
105 } | |
106 | |
107 uint32_t GetSize() const | |
108 { | |
109 return static_cast<uint32_t>(items_.size()); | |
110 } | |
111 | |
112 const char* const* GetItems() const | |
113 { | |
114 return (items_.empty() ? NULL : &items_[0]); | |
115 } | |
116 }; | |
117 | |
118 | |
119 static MimeType ParseMimeType(const char* mimeType) | |
120 { | |
121 MimeType mime; | |
122 if (LookupMimeType(mime, mimeType)) | |
123 { | |
124 return mime; | |
125 } | |
126 else | |
127 { | |
128 LOG(WARNING) << "Unknown MIME type in plugin: " << mimeType; | |
129 return MimeType_Binary; | |
130 } | |
131 } | |
132 | |
133 static OrthancPluginErrorCode AddFile( | |
134 OrthancPluginWebDavCollection* collection, | |
135 const char* displayName, | |
136 uint64_t contentSize, | |
137 const char* mimeType, | |
138 const char* creationTime) | |
139 { | |
140 try | |
141 { | |
142 std::unique_ptr<File> f(new File(displayName)); | |
143 f->SetCreationTime(boost::posix_time::from_iso_string(creationTime)); | |
144 f->SetContentLength(contentSize); | |
145 | |
146 if (mimeType == NULL || | |
147 std::string(mimeType).empty()) | |
148 { | |
149 f->SetMimeType(SystemToolbox::AutodetectMimeType(displayName)); | |
150 } | |
151 else | |
152 { | |
153 f->SetMimeType(ParseMimeType(mimeType)); | |
154 } | |
155 | |
156 reinterpret_cast<Collection*>(collection)->AddResource(f.release()); | |
157 return OrthancPluginErrorCode_Success; | |
158 } | |
159 catch (OrthancException& e) | |
160 { | |
161 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
162 } | |
163 catch (...) | |
164 { | |
165 return OrthancPluginErrorCode_InternalError; | |
166 } | |
167 } | |
168 | |
169 static OrthancPluginErrorCode AddFolder( | |
170 OrthancPluginWebDavCollection* collection, | |
171 const char* displayName, | |
172 const char* creationTime) | |
173 { | |
174 try | |
175 { | |
176 std::unique_ptr<Folder> f(new Folder(displayName)); | |
177 f->SetCreationTime(boost::posix_time::from_iso_string(creationTime)); | |
178 reinterpret_cast<Collection*>(collection)->AddResource(f.release()); | |
179 return OrthancPluginErrorCode_Success; | |
180 } | |
181 catch (OrthancException& e) | |
182 { | |
183 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
184 } | |
185 catch (boost::bad_lexical_cast&) | |
186 { | |
187 LOG(ERROR) << "Presumably ill-formed date in the plugin"; | |
188 return OrthancPluginErrorCode_ParameterOutOfRange; | |
189 } | |
190 catch (...) | |
191 { | |
192 return OrthancPluginErrorCode_InternalError; | |
193 } | |
194 } | |
195 | |
196 | |
197 class ContentTarget : public boost::noncopyable | |
198 { | |
199 private: | |
200 bool isSent_; | |
201 MimeType& mime_; | |
202 std::string& content_; | |
203 boost::posix_time::ptime& modificationTime_; | |
204 | |
205 public: | |
206 ContentTarget(const std::string& displayName, | |
207 MimeType& mime, | |
208 std::string& content, | |
209 boost::posix_time::ptime& modificationTime) : | |
210 isSent_(false), | |
211 mime_(mime), | |
212 content_(content), | |
213 modificationTime_(modificationTime) | |
214 { | |
215 mime = SystemToolbox::AutodetectMimeType(displayName); | |
216 } | |
217 | |
218 bool IsSent() const | |
219 { | |
220 return isSent_; | |
221 } | |
222 | |
223 static OrthancPluginErrorCode RetrieveFile( | |
224 OrthancPluginWebDavCollection* collection, | |
225 const void* data, | |
226 uint64_t size, | |
227 const char* mimeType, | |
228 const char* creationTime) | |
229 { | |
230 ContentTarget& target = *reinterpret_cast<ContentTarget*>(collection); | |
231 | |
232 if (target.isSent_) | |
233 { | |
234 return OrthancPluginErrorCode_BadSequenceOfCalls; | |
235 } | |
236 else | |
237 { | |
238 try | |
239 { | |
240 target.isSent_ = true; | |
241 | |
242 if (mimeType != NULL && | |
243 !std::string(mimeType).empty()) | |
244 { | |
245 target.mime_ = ParseMimeType(mimeType); | |
246 } | |
247 | |
248 target.content_.assign(reinterpret_cast<const char*>(data), size); | |
249 target.modificationTime_ = boost::posix_time::from_iso_string(creationTime); | |
250 return OrthancPluginErrorCode_Success; | |
251 } | |
252 catch (Orthanc::OrthancException& e) | |
253 { | |
254 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
255 } | |
256 catch (boost::bad_lexical_cast&) | |
257 { | |
258 LOG(ERROR) << "Presumably ill-formed date in the plugin"; | |
259 return OrthancPluginErrorCode_ParameterOutOfRange; | |
260 } | |
261 catch (...) | |
262 { | |
263 return OrthancPluginErrorCode_InternalError; | |
264 } | |
265 } | |
266 } | |
267 }; | |
268 | |
269 | |
270 public: | |
271 WebDavCollection(PluginsErrorDictionary& errorDictionary, | |
272 const _OrthancPluginRegisterWebDavCollection& p) : | |
273 errorDictionary_(errorDictionary), | |
274 uri_(p.uri), | |
275 isExistingFolder_(p.isExistingFolder), | |
276 listFolder_(p.listFolder), | |
277 retrieveFile_(p.retrieveFile), | |
278 storeFile_(p.storeFile), | |
279 createFolder_(p.createFolder), | |
280 deleteItem_(p.deleteItem), | |
281 payload_(p.payload) | |
282 { | |
283 } | |
284 | |
285 const std::string& GetUri() const | |
286 { | |
287 return uri_; | |
288 } | |
289 | |
290 virtual bool IsExistingFolder(const std::vector<std::string>& path) | |
291 { | |
292 PathHelper helper(path); | |
293 | |
294 uint8_t isExisting; | |
295 OrthancPluginErrorCode code = isExistingFolder_(&isExisting, helper.GetSize(), helper.GetItems(), payload_); | |
296 | |
297 if (code == OrthancPluginErrorCode_Success) | |
298 { | |
299 return (isExisting != 0); | |
300 } | |
301 else | |
302 { | |
303 errorDictionary_.LogError(code, true); | |
304 throw OrthancException(static_cast<ErrorCode>(code)); | |
305 } | |
306 } | |
307 | |
308 virtual bool ListCollection(Collection& collection, | |
309 const std::vector<std::string>& path) | |
310 { | |
311 PathHelper helper(path); | |
312 | |
313 uint8_t isExisting; | |
314 OrthancPluginErrorCode code = listFolder_(&isExisting, reinterpret_cast<OrthancPluginWebDavCollection*>(&collection), | |
315 AddFile, AddFolder, helper.GetSize(), helper.GetItems(), payload_); | |
316 | |
317 if (code == OrthancPluginErrorCode_Success) | |
318 { | |
319 return (isExisting != 0); | |
320 } | |
321 else | |
322 { | |
323 errorDictionary_.LogError(code, true); | |
324 throw OrthancException(static_cast<ErrorCode>(code)); | |
325 } | |
326 } | |
327 | |
328 virtual bool GetFileContent(MimeType& mime, | |
329 std::string& content, | |
330 boost::posix_time::ptime& modificationTime, | |
331 const std::vector<std::string>& path) | |
332 { | |
333 PathHelper helper(path); | |
334 | |
335 ContentTarget target(path.back(), mime, content, modificationTime); | |
336 OrthancPluginErrorCode code = retrieveFile_( | |
337 reinterpret_cast<OrthancPluginWebDavCollection*>(&target), | |
338 ContentTarget::RetrieveFile, helper.GetSize(), helper.GetItems(), payload_); | |
339 | |
340 if (code == OrthancPluginErrorCode_Success) | |
341 { | |
342 return target.IsSent(); | |
343 } | |
344 else | |
345 { | |
346 errorDictionary_.LogError(code, true); | |
347 throw OrthancException(static_cast<ErrorCode>(code)); | |
348 } | |
349 } | |
350 | |
351 virtual bool StoreFile(const std::string& content, | |
352 const std::vector<std::string>& path) | |
353 { | |
354 PathHelper helper(path); | |
355 | |
356 uint8_t isReadOnly; | |
357 OrthancPluginErrorCode code = storeFile_(&isReadOnly, helper.GetSize(), helper.GetItems(), | |
358 content.empty() ? NULL : content.c_str(), content.size(), payload_); | |
359 | |
360 if (code == OrthancPluginErrorCode_Success) | |
361 { | |
362 return (isReadOnly != 0); | |
363 } | |
364 else | |
365 { | |
366 errorDictionary_.LogError(code, true); | |
367 throw OrthancException(static_cast<ErrorCode>(code)); | |
368 } | |
369 } | |
370 | |
371 virtual bool CreateFolder(const std::vector<std::string>& path) | |
372 { | |
373 PathHelper helper(path); | |
374 | |
375 uint8_t isReadOnly; | |
376 OrthancPluginErrorCode code = createFolder_(&isReadOnly, helper.GetSize(), helper.GetItems(), payload_); | |
377 | |
378 if (code == OrthancPluginErrorCode_Success) | |
379 { | |
380 return (isReadOnly != 0); | |
381 } | |
382 else | |
383 { | |
384 errorDictionary_.LogError(code, true); | |
385 throw OrthancException(static_cast<ErrorCode>(code)); | |
386 } | |
387 } | |
388 | |
389 virtual bool DeleteItem(const std::vector<std::string>& path) | |
390 { | |
391 PathHelper helper(path); | |
392 | |
393 uint8_t isReadOnly; | |
394 OrthancPluginErrorCode code = deleteItem_(&isReadOnly, helper.GetSize(), helper.GetItems(), payload_); | |
395 | |
396 if (code == OrthancPluginErrorCode_Success) | |
397 { | |
398 return (isReadOnly != 0); | |
399 } | |
400 else | |
401 { | |
402 errorDictionary_.LogError(code, true); | |
403 throw OrthancException(static_cast<ErrorCode>(code)); | |
404 } | |
405 } | |
406 | |
407 virtual void Start() | |
408 { | |
409 } | |
410 | |
411 virtual void Stop() | |
412 { | |
413 } | |
414 }; | |
415 | |
416 | |
78 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, | 417 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, |
79 const void* data, | 418 const void* data, |
80 size_t size) | 419 size_t size) |
81 { | 420 { |
82 if (static_cast<uint32_t>(size) != size) | 421 if (static_cast<uint32_t>(size) != size) |
1162 typedef std::list<OrthancPluginTranscoderCallback> TranscoderCallbacks; | 1501 typedef std::list<OrthancPluginTranscoderCallback> TranscoderCallbacks; |
1163 typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers; | 1502 typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers; |
1164 typedef std::list<OrthancPluginRefreshMetricsCallback> RefreshMetricsCallbacks; | 1503 typedef std::list<OrthancPluginRefreshMetricsCallback> RefreshMetricsCallbacks; |
1165 typedef std::list<StorageCommitmentScp*> StorageCommitmentScpCallbacks; | 1504 typedef std::list<StorageCommitmentScp*> StorageCommitmentScpCallbacks; |
1166 typedef std::map<Property, std::string> Properties; | 1505 typedef std::map<Property, std::string> Properties; |
1506 typedef std::list<WebDavCollection*> WebDavCollections; | |
1167 | 1507 |
1168 PluginsManager manager_; | 1508 PluginsManager manager_; |
1169 | 1509 |
1170 RestCallbacks restCallbacks_; | 1510 RestCallbacks restCallbacks_; |
1171 ChunkedRestCallbacks chunkedRestCallbacks_; | 1511 ChunkedRestCallbacks chunkedRestCallbacks_; |
1182 IncomingDicomInstanceFilters incomingDicomInstanceFilters_; | 1522 IncomingDicomInstanceFilters incomingDicomInstanceFilters_; |
1183 IncomingCStoreInstanceFilters incomingCStoreInstanceFilters_; // New in Orthanc 1.10.0 | 1523 IncomingCStoreInstanceFilters incomingCStoreInstanceFilters_; // New in Orthanc 1.10.0 |
1184 OrthancPluginReceivedInstanceCallback receivedInstanceCallback_; // New in Orthanc 1.10.0 | 1524 OrthancPluginReceivedInstanceCallback receivedInstanceCallback_; // New in Orthanc 1.10.0 |
1185 RefreshMetricsCallbacks refreshMetricsCallbacks_; | 1525 RefreshMetricsCallbacks refreshMetricsCallbacks_; |
1186 StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; | 1526 StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; |
1527 WebDavCollections webDavCollections_; // New in Orthanc 1.10.1 | |
1187 std::unique_ptr<StorageAreaFactory> storageArea_; | 1528 std::unique_ptr<StorageAreaFactory> storageArea_; |
1188 std::set<std::string> authorizationTokens_; | 1529 std::set<std::string> authorizationTokens_; |
1189 | 1530 |
1190 boost::recursive_mutex restCallbackInvokationMutex_; | 1531 boost::recursive_mutex restCallbackInvokationMutex_; |
1191 boost::shared_mutex restCallbackRegistrationMutex_; // New in Orthanc 1.9.0 | 1532 boost::shared_mutex restCallbackRegistrationMutex_; // New in Orthanc 1.9.0 |
1766 for (PImpl::StorageCommitmentScpCallbacks::iterator | 2107 for (PImpl::StorageCommitmentScpCallbacks::iterator |
1767 it = pimpl_->storageCommitmentScpCallbacks_.begin(); | 2108 it = pimpl_->storageCommitmentScpCallbacks_.begin(); |
1768 it != pimpl_->storageCommitmentScpCallbacks_.end(); ++it) | 2109 it != pimpl_->storageCommitmentScpCallbacks_.end(); ++it) |
1769 { | 2110 { |
1770 delete *it; | 2111 delete *it; |
1771 } | 2112 } |
2113 | |
2114 for (PImpl::WebDavCollections::iterator it = pimpl_->webDavCollections_.begin(); | |
2115 it != pimpl_->webDavCollections_.end(); ++it) | |
2116 { | |
2117 delete *it; | |
2118 } | |
1772 } | 2119 } |
1773 | 2120 |
1774 | 2121 |
1775 static void ArgumentsToPlugin(std::vector<const char*>& keys, | 2122 static void ArgumentsToPlugin(std::vector<const char*>& keys, |
1776 std::vector<const char*>& values, | 2123 std::vector<const char*>& values, |
5263 *p.result = CopyString("Bearer " + token); | 5610 *p.result = CopyString("Bearer " + token); |
5264 | 5611 |
5265 return true; | 5612 return true; |
5266 } | 5613 } |
5267 | 5614 |
5615 case _OrthancPluginService_RegisterWebDavCollection: | |
5616 { | |
5617 CLOG(INFO, PLUGINS) << "Plugin has registered a WebDAV collection"; | |
5618 const _OrthancPluginRegisterWebDavCollection& p = | |
5619 *reinterpret_cast<const _OrthancPluginRegisterWebDavCollection*>(parameters); | |
5620 pimpl_->webDavCollections_.push_back(new WebDavCollection(GetErrorDictionary(), p)); | |
5621 return true; | |
5622 } | |
5623 | |
5268 default: | 5624 default: |
5269 { | 5625 { |
5270 // This service is unknown to the Orthanc plugin engine | 5626 // This service is unknown to the Orthanc plugin engine |
5271 return false; | 5627 return false; |
5272 } | 5628 } |
5860 unsigned int OrthancPlugins::GetMaxDatabaseRetries() const | 6216 unsigned int OrthancPlugins::GetMaxDatabaseRetries() const |
5861 { | 6217 { |
5862 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | 6218 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); |
5863 return pimpl_->maxDatabaseRetries_; | 6219 return pimpl_->maxDatabaseRetries_; |
5864 } | 6220 } |
6221 | |
6222 | |
6223 void OrthancPlugins::RegisterWebDavCollections(HttpServer& target) | |
6224 { | |
6225 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | |
6226 | |
6227 while (!pimpl_->webDavCollections_.empty()) | |
6228 { | |
6229 WebDavCollection* collection = pimpl_->webDavCollections_.front(); | |
6230 assert(collection != NULL); | |
6231 | |
6232 UriComponents components; | |
6233 Toolbox::SplitUriComponents(components, collection->GetUri()); | |
6234 target.Register(components, collection); | |
6235 | |
6236 pimpl_->webDavCollections_.pop_front(); | |
6237 } | |
6238 } | |
5865 } | 6239 } |