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 }