comparison StoneWebViewer/Resources/Orthanc/OrthancPluginCppWrapper.h @ 1504:d8af188ab545

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 30 Jun 2020 20:35:16 +0200
parents
children
comparison
equal deleted inserted replaced
1503:553084468225 1504:d8af188ab545
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #pragma once
35
36 #include "OrthancPluginException.h"
37
38 #include <orthanc/OrthancCPlugin.h>
39 #include <boost/noncopyable.hpp>
40 #include <boost/lexical_cast.hpp>
41 #include <boost/date_time/posix_time/posix_time.hpp>
42 #include <json/value.h>
43 #include <vector>
44 #include <list>
45 #include <set>
46 #include <map>
47
48
49
50 /**
51 * The definition of ORTHANC_PLUGINS_VERSION_IS_ABOVE below is for
52 * backward compatibility with Orthanc SDK <= 1.3.0.
53 *
54 * $ hg diff -r Orthanc-1.3.0:Orthanc-1.3.1 ../../../Plugins/Include/orthanc/OrthancCPlugin.h
55 *
56 **/
57 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
58 #define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \
59 (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \
60 (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \
61 (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \
62 (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \
63 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision))))
64 #endif
65
66
67 #if !defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE)
68 #define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision) \
69 (ORTHANC_VERSION_MAJOR > major || \
70 (ORTHANC_VERSION_MAJOR == major && \
71 (ORTHANC_VERSION_MINOR > minor || \
72 (ORTHANC_VERSION_MINOR == minor && \
73 ORTHANC_VERSION_REVISION >= revision))))
74 #endif
75
76
77 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
78 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
79 # define HAS_ORTHANC_PLUGIN_FIND_MATCHER 1
80 #else
81 # define HAS_ORTHANC_PLUGIN_FIND_MATCHER 0
82 #endif
83
84
85 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2)
86 # define HAS_ORTHANC_PLUGIN_PEERS 1
87 # define HAS_ORTHANC_PLUGIN_JOB 1
88 #else
89 # define HAS_ORTHANC_PLUGIN_PEERS 0
90 # define HAS_ORTHANC_PLUGIN_JOB 0
91 #endif
92
93 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
94 # define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 1
95 #else
96 # define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 0
97 #endif
98
99 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
100 # define HAS_ORTHANC_PLUGIN_METRICS 1
101 #else
102 # define HAS_ORTHANC_PLUGIN_METRICS 0
103 #endif
104
105 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0)
106 # define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 1
107 #else
108 # define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 0
109 #endif
110
111 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
112 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 1
113 #else
114 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 0
115 #endif
116
117 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
118 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 1
119 #else
120 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 0
121 #endif
122
123 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0)
124 # define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 1
125 #else
126 # define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 0
127 #endif
128
129
130
131 namespace OrthancPlugins
132 {
133 typedef void (*RestCallback) (OrthancPluginRestOutput* output,
134 const char* url,
135 const OrthancPluginHttpRequest* request);
136
137 void SetGlobalContext(OrthancPluginContext* context);
138
139 bool HasGlobalContext();
140
141 OrthancPluginContext* GetGlobalContext();
142
143
144 class OrthancImage;
145
146
147 class MemoryBuffer : public boost::noncopyable
148 {
149 private:
150 OrthancPluginMemoryBuffer buffer_;
151
152 void Check(OrthancPluginErrorCode code);
153
154 bool CheckHttp(OrthancPluginErrorCode code);
155
156 public:
157 MemoryBuffer();
158
159 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
160 // This constructor makes a copy of the given buffer in the memory
161 // handled by the Orthanc core
162 MemoryBuffer(const void* buffer,
163 size_t size);
164 #endif
165
166 ~MemoryBuffer()
167 {
168 Clear();
169 }
170
171 OrthancPluginMemoryBuffer* operator*()
172 {
173 return &buffer_;
174 }
175
176 // This transfers ownership from "other" to "this"
177 void Assign(OrthancPluginMemoryBuffer& other);
178
179 void Swap(MemoryBuffer& other);
180
181 OrthancPluginMemoryBuffer Release();
182
183 const char* GetData() const
184 {
185 if (buffer_.size > 0)
186 {
187 return reinterpret_cast<const char*>(buffer_.data);
188 }
189 else
190 {
191 return NULL;
192 }
193 }
194
195 size_t GetSize() const
196 {
197 return buffer_.size;
198 }
199
200 bool IsEmpty() const
201 {
202 return GetSize() == 0 || GetData() == NULL;
203 }
204
205 void Clear();
206
207 void ToString(std::string& target) const;
208
209 void ToJson(Json::Value& target) const;
210
211 bool RestApiGet(const std::string& uri,
212 bool applyPlugins);
213
214 bool RestApiGet(const std::string& uri,
215 const std::map<std::string, std::string>& httpHeaders,
216 bool applyPlugins);
217
218 bool RestApiPost(const std::string& uri,
219 const void* body,
220 size_t bodySize,
221 bool applyPlugins);
222
223 bool RestApiPut(const std::string& uri,
224 const void* body,
225 size_t bodySize,
226 bool applyPlugins);
227
228 bool RestApiPost(const std::string& uri,
229 const Json::Value& body,
230 bool applyPlugins);
231
232 bool RestApiPut(const std::string& uri,
233 const Json::Value& body,
234 bool applyPlugins);
235
236 bool RestApiPost(const std::string& uri,
237 const std::string& body,
238 bool applyPlugins)
239 {
240 return RestApiPost(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
241 }
242
243 bool RestApiPut(const std::string& uri,
244 const std::string& body,
245 bool applyPlugins)
246 {
247 return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
248 }
249
250 void CreateDicom(const Json::Value& tags,
251 OrthancPluginCreateDicomFlags flags);
252
253 void CreateDicom(const Json::Value& tags,
254 const OrthancImage& pixelData,
255 OrthancPluginCreateDicomFlags flags);
256
257 void ReadFile(const std::string& path);
258
259 void GetDicomQuery(const OrthancPluginWorklistQuery* query);
260
261 void DicomToJson(Json::Value& target,
262 OrthancPluginDicomToJsonFormat format,
263 OrthancPluginDicomToJsonFlags flags,
264 uint32_t maxStringLength);
265
266 bool HttpGet(const std::string& url,
267 const std::string& username,
268 const std::string& password);
269
270 bool HttpPost(const std::string& url,
271 const std::string& body,
272 const std::string& username,
273 const std::string& password);
274
275 bool HttpPut(const std::string& url,
276 const std::string& body,
277 const std::string& username,
278 const std::string& password);
279
280 void GetDicomInstance(const std::string& instanceId);
281 };
282
283
284 class OrthancString : public boost::noncopyable
285 {
286 private:
287 char* str_;
288
289 void Clear();
290
291 public:
292 OrthancString() :
293 str_(NULL)
294 {
295 }
296
297 ~OrthancString()
298 {
299 Clear();
300 }
301
302 // This transfers ownership, warning: The string must have been
303 // allocated by the Orthanc core
304 void Assign(char* str);
305
306 const char* GetContent() const
307 {
308 return str_;
309 }
310
311 void ToString(std::string& target) const;
312
313 void ToJson(Json::Value& target) const;
314 };
315
316
317 class OrthancConfiguration : public boost::noncopyable
318 {
319 private:
320 Json::Value configuration_; // Necessarily a Json::objectValue
321 std::string path_;
322
323 std::string GetPath(const std::string& key) const;
324
325 void LoadConfiguration();
326
327 public:
328 OrthancConfiguration();
329
330 explicit OrthancConfiguration(bool load);
331
332 const Json::Value& GetJson() const
333 {
334 return configuration_;
335 }
336
337 bool IsSection(const std::string& key) const;
338
339 void GetSection(OrthancConfiguration& target,
340 const std::string& key) const;
341
342 bool LookupStringValue(std::string& target,
343 const std::string& key) const;
344
345 bool LookupIntegerValue(int& target,
346 const std::string& key) const;
347
348 bool LookupUnsignedIntegerValue(unsigned int& target,
349 const std::string& key) const;
350
351 bool LookupBooleanValue(bool& target,
352 const std::string& key) const;
353
354 bool LookupFloatValue(float& target,
355 const std::string& key) const;
356
357 bool LookupListOfStrings(std::list<std::string>& target,
358 const std::string& key,
359 bool allowSingleString) const;
360
361 bool LookupSetOfStrings(std::set<std::string>& target,
362 const std::string& key,
363 bool allowSingleString) const;
364
365 std::string GetStringValue(const std::string& key,
366 const std::string& defaultValue) const;
367
368 int GetIntegerValue(const std::string& key,
369 int defaultValue) const;
370
371 unsigned int GetUnsignedIntegerValue(const std::string& key,
372 unsigned int defaultValue) const;
373
374 bool GetBooleanValue(const std::string& key,
375 bool defaultValue) const;
376
377 float GetFloatValue(const std::string& key,
378 float defaultValue) const;
379
380 void GetDictionary(std::map<std::string, std::string>& target,
381 const std::string& key) const;
382 };
383
384 class OrthancImage : public boost::noncopyable
385 {
386 private:
387 OrthancPluginImage* image_;
388
389 void Clear();
390
391 void CheckImageAvailable() const;
392
393 public:
394 OrthancImage();
395
396 explicit OrthancImage(OrthancPluginImage* image);
397
398 OrthancImage(OrthancPluginPixelFormat format,
399 uint32_t width,
400 uint32_t height);
401
402 OrthancImage(OrthancPluginPixelFormat format,
403 uint32_t width,
404 uint32_t height,
405 uint32_t pitch,
406 void* buffer);
407
408 ~OrthancImage()
409 {
410 Clear();
411 }
412
413 void UncompressPngImage(const void* data,
414 size_t size);
415
416 void UncompressJpegImage(const void* data,
417 size_t size);
418
419 void DecodeDicomImage(const void* data,
420 size_t size,
421 unsigned int frame);
422
423 OrthancPluginPixelFormat GetPixelFormat() const;
424
425 unsigned int GetWidth() const;
426
427 unsigned int GetHeight() const;
428
429 unsigned int GetPitch() const;
430
431 void* GetBuffer() const;
432
433 const OrthancPluginImage* GetObject() const
434 {
435 return image_;
436 }
437
438 void CompressPngImage(MemoryBuffer& target) const;
439
440 void CompressJpegImage(MemoryBuffer& target,
441 uint8_t quality) const;
442
443 void AnswerPngImage(OrthancPluginRestOutput* output) const;
444
445 void AnswerJpegImage(OrthancPluginRestOutput* output,
446 uint8_t quality) const;
447
448 void* GetWriteableBuffer();
449
450 OrthancPluginImage* Release();
451 };
452
453
454 #if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1
455 class FindMatcher : public boost::noncopyable
456 {
457 private:
458 OrthancPluginFindMatcher* matcher_;
459 const OrthancPluginWorklistQuery* worklist_;
460
461 void SetupDicom(const void* query,
462 uint32_t size);
463
464 public:
465 explicit FindMatcher(const OrthancPluginWorklistQuery* worklist);
466
467 FindMatcher(const void* query,
468 uint32_t size)
469 {
470 SetupDicom(query, size);
471 }
472
473 explicit FindMatcher(const MemoryBuffer& dicom)
474 {
475 SetupDicom(dicom.GetData(), dicom.GetSize());
476 }
477
478 ~FindMatcher();
479
480 bool IsMatch(const void* dicom,
481 uint32_t size) const;
482
483 bool IsMatch(const MemoryBuffer& dicom) const
484 {
485 return IsMatch(dicom.GetData(), dicom.GetSize());
486 }
487 };
488 #endif
489
490
491 bool RestApiGet(Json::Value& result,
492 const std::string& uri,
493 bool applyPlugins);
494
495 bool RestApiGetString(std::string& result,
496 const std::string& uri,
497 bool applyPlugins);
498
499 bool RestApiGetString(std::string& result,
500 const std::string& uri,
501 const std::map<std::string, std::string>& httpHeaders,
502 bool applyPlugins);
503
504 bool RestApiPost(std::string& result,
505 const std::string& uri,
506 const void* body,
507 size_t bodySize,
508 bool applyPlugins);
509
510 bool RestApiPost(Json::Value& result,
511 const std::string& uri,
512 const void* body,
513 size_t bodySize,
514 bool applyPlugins);
515
516 bool RestApiPost(Json::Value& result,
517 const std::string& uri,
518 const Json::Value& body,
519 bool applyPlugins);
520
521 inline bool RestApiPost(Json::Value& result,
522 const std::string& uri,
523 const std::string& body,
524 bool applyPlugins)
525 {
526 return RestApiPost(result, uri, body.empty() ? NULL : body.c_str(),
527 body.size(), applyPlugins);
528 }
529
530 inline bool RestApiPost(Json::Value& result,
531 const std::string& uri,
532 const MemoryBuffer& body,
533 bool applyPlugins)
534 {
535 return RestApiPost(result, uri, body.GetData(),
536 body.GetSize(), applyPlugins);
537 }
538
539 bool RestApiPut(Json::Value& result,
540 const std::string& uri,
541 const void* body,
542 size_t bodySize,
543 bool applyPlugins);
544
545 bool RestApiPut(Json::Value& result,
546 const std::string& uri,
547 const Json::Value& body,
548 bool applyPlugins);
549
550 inline bool RestApiPut(Json::Value& result,
551 const std::string& uri,
552 const std::string& body,
553 bool applyPlugins)
554 {
555 return RestApiPut(result, uri, body.empty() ? NULL : body.c_str(),
556 body.size(), applyPlugins);
557 }
558
559 bool RestApiDelete(const std::string& uri,
560 bool applyPlugins);
561
562 bool HttpDelete(const std::string& url,
563 const std::string& username,
564 const std::string& password);
565
566 void AnswerJson(const Json::Value& value,
567 OrthancPluginRestOutput* output);
568
569 void AnswerString(const std::string& answer,
570 const char* mimeType,
571 OrthancPluginRestOutput* output);
572
573 void AnswerHttpError(uint16_t httpError,
574 OrthancPluginRestOutput* output);
575
576 void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods);
577
578 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
579 const char* AutodetectMimeType(const std::string& path);
580 #endif
581
582 void LogError(const std::string& message);
583
584 void LogWarning(const std::string& message);
585
586 void LogInfo(const std::string& message);
587
588 void ReportMinimalOrthancVersion(unsigned int major,
589 unsigned int minor,
590 unsigned int revision);
591
592 bool CheckMinimalOrthancVersion(unsigned int major,
593 unsigned int minor,
594 unsigned int revision);
595
596
597 namespace Internals
598 {
599 template <RestCallback Callback>
600 static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output,
601 const char* url,
602 const OrthancPluginHttpRequest* request)
603 {
604 try
605 {
606 Callback(output, url, request);
607 return OrthancPluginErrorCode_Success;
608 }
609 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
610 {
611 #if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
612 if (HasGlobalContext() &&
613 e.HasDetails())
614 {
615 // The "false" instructs Orthanc not to log the detailed
616 // error message. This is to avoid duplicating the details,
617 // because "OrthancException" already does it on construction.
618 OrthancPluginSetHttpErrorDetails
619 (GetGlobalContext(), output, e.GetDetails(), false);
620 }
621 #endif
622
623 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
624 }
625 catch (boost::bad_lexical_cast&)
626 {
627 return OrthancPluginErrorCode_BadFileFormat;
628 }
629 catch (...)
630 {
631 return OrthancPluginErrorCode_Plugin;
632 }
633 }
634 }
635
636
637 template <RestCallback Callback>
638 void RegisterRestCallback(const std::string& uri,
639 bool isThreadSafe)
640 {
641 if (isThreadSafe)
642 {
643 OrthancPluginRegisterRestCallbackNoLock
644 (GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
645 }
646 else
647 {
648 OrthancPluginRegisterRestCallback
649 (GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
650 }
651 }
652
653
654 #if HAS_ORTHANC_PLUGIN_PEERS == 1
655 class OrthancPeers : public boost::noncopyable
656 {
657 private:
658 typedef std::map<std::string, uint32_t> Index;
659
660 OrthancPluginPeers *peers_;
661 Index index_;
662 uint32_t timeout_;
663
664 size_t GetPeerIndex(const std::string& name) const;
665
666 public:
667 OrthancPeers();
668
669 ~OrthancPeers();
670
671 uint32_t GetTimeout() const
672 {
673 return timeout_;
674 }
675
676 void SetTimeout(uint32_t timeout)
677 {
678 timeout_ = timeout;
679 }
680
681 bool LookupName(size_t& target,
682 const std::string& name) const;
683
684 std::string GetPeerName(size_t index) const;
685
686 std::string GetPeerUrl(size_t index) const;
687
688 std::string GetPeerUrl(const std::string& name) const;
689
690 size_t GetPeersCount() const
691 {
692 return index_.size();
693 }
694
695 bool LookupUserProperty(std::string& value,
696 size_t index,
697 const std::string& key) const;
698
699 bool LookupUserProperty(std::string& value,
700 const std::string& peer,
701 const std::string& key) const;
702
703 bool DoGet(MemoryBuffer& target,
704 size_t index,
705 const std::string& uri) const;
706
707 bool DoGet(MemoryBuffer& target,
708 const std::string& name,
709 const std::string& uri) const;
710
711 bool DoGet(Json::Value& target,
712 size_t index,
713 const std::string& uri) const;
714
715 bool DoGet(Json::Value& target,
716 const std::string& name,
717 const std::string& uri) const;
718
719 bool DoPost(MemoryBuffer& target,
720 size_t index,
721 const std::string& uri,
722 const std::string& body) const;
723
724 bool DoPost(MemoryBuffer& target,
725 const std::string& name,
726 const std::string& uri,
727 const std::string& body) const;
728
729 bool DoPost(Json::Value& target,
730 size_t index,
731 const std::string& uri,
732 const std::string& body) const;
733
734 bool DoPost(Json::Value& target,
735 const std::string& name,
736 const std::string& uri,
737 const std::string& body) const;
738
739 bool DoPut(size_t index,
740 const std::string& uri,
741 const std::string& body) const;
742
743 bool DoPut(const std::string& name,
744 const std::string& uri,
745 const std::string& body) const;
746
747 bool DoDelete(size_t index,
748 const std::string& uri) const;
749
750 bool DoDelete(const std::string& name,
751 const std::string& uri) const;
752 };
753 #endif
754
755
756
757 #if HAS_ORTHANC_PLUGIN_JOB == 1
758 class OrthancJob : public boost::noncopyable
759 {
760 private:
761 std::string jobType_;
762 std::string content_;
763 bool hasSerialized_;
764 std::string serialized_;
765 float progress_;
766
767 static void CallbackFinalize(void* job);
768
769 static float CallbackGetProgress(void* job);
770
771 static const char* CallbackGetContent(void* job);
772
773 static const char* CallbackGetSerialized(void* job);
774
775 static OrthancPluginJobStepStatus CallbackStep(void* job);
776
777 static OrthancPluginErrorCode CallbackStop(void* job,
778 OrthancPluginJobStopReason reason);
779
780 static OrthancPluginErrorCode CallbackReset(void* job);
781
782 protected:
783 void ClearContent();
784
785 void UpdateContent(const Json::Value& content);
786
787 void ClearSerialized();
788
789 void UpdateSerialized(const Json::Value& serialized);
790
791 void UpdateProgress(float progress);
792
793 public:
794 OrthancJob(const std::string& jobType);
795
796 virtual ~OrthancJob()
797 {
798 }
799
800 virtual OrthancPluginJobStepStatus Step() = 0;
801
802 virtual void Stop(OrthancPluginJobStopReason reason) = 0;
803
804 virtual void Reset() = 0;
805
806 static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */);
807
808 static std::string Submit(OrthancJob* job /* takes ownership */,
809 int priority);
810
811 static void SubmitAndWait(Json::Value& result,
812 OrthancJob* job /* takes ownership */,
813 int priority);
814
815 // Submit a job from a POST on the REST API with the same
816 // conventions as in the Orthanc core (according to the
817 // "Synchronous" and "Priority" options)
818 static void SubmitFromRestApiPost(OrthancPluginRestOutput* output,
819 const Json::Value& body,
820 OrthancJob* job);
821 };
822 #endif
823
824
825 #if HAS_ORTHANC_PLUGIN_METRICS == 1
826 inline void SetMetricsValue(char* name,
827 float value)
828 {
829 OrthancPluginSetMetricsValue(GetGlobalContext(), name,
830 value, OrthancPluginMetricsType_Default);
831 }
832
833 class MetricsTimer : public boost::noncopyable
834 {
835 private:
836 std::string name_;
837 boost::posix_time::ptime start_;
838
839 public:
840 explicit MetricsTimer(const char* name);
841
842 ~MetricsTimer();
843 };
844 #endif
845
846
847 #if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1
848 class HttpClient : public boost::noncopyable
849 {
850 public:
851 typedef std::map<std::string, std::string> HttpHeaders;
852
853 class IRequestBody : public boost::noncopyable
854 {
855 public:
856 virtual ~IRequestBody()
857 {
858 }
859
860 virtual bool ReadNextChunk(std::string& chunk) = 0;
861 };
862
863
864 class IAnswer : public boost::noncopyable
865 {
866 public:
867 virtual ~IAnswer()
868 {
869 }
870
871 virtual void AddHeader(const std::string& key,
872 const std::string& value) = 0;
873
874 virtual void AddChunk(const void* data,
875 size_t size) = 0;
876 };
877
878
879 private:
880 class RequestBodyWrapper;
881
882 uint16_t httpStatus_;
883 OrthancPluginHttpMethod method_;
884 std::string url_;
885 HttpHeaders headers_;
886 std::string username_;
887 std::string password_;
888 uint32_t timeout_;
889 std::string certificateFile_;
890 std::string certificateKeyFile_;
891 std::string certificateKeyPassword_;
892 bool pkcs11_;
893 std::string fullBody_;
894 IRequestBody* chunkedBody_;
895 bool allowChunkedTransfers_;
896
897 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
898 void ExecuteWithStream(uint16_t& httpStatus, // out
899 IAnswer& answer, // out
900 IRequestBody& body) const;
901 #endif
902
903 void ExecuteWithoutStream(uint16_t& httpStatus, // out
904 HttpHeaders& answerHeaders, // out
905 std::string& answerBody, // out
906 const std::string& body) const;
907
908 public:
909 HttpClient();
910
911 uint16_t GetHttpStatus() const
912 {
913 return httpStatus_;
914 }
915
916 void SetMethod(OrthancPluginHttpMethod method)
917 {
918 method_ = method;
919 }
920
921 const std::string& GetUrl() const
922 {
923 return url_;
924 }
925
926 void SetUrl(const std::string& url)
927 {
928 url_ = url;
929 }
930
931 void SetHeaders(const HttpHeaders& headers)
932 {
933 headers_ = headers;
934 }
935
936 void AddHeader(const std::string& key,
937 const std::string& value)
938 {
939 headers_[key] = value;
940 }
941
942 void AddHeaders(const HttpHeaders& headers);
943
944 void SetCredentials(const std::string& username,
945 const std::string& password);
946
947 void ClearCredentials();
948
949 void SetTimeout(unsigned int timeout) // 0 for default timeout
950 {
951 timeout_ = timeout;
952 }
953
954 void SetCertificate(const std::string& certificateFile,
955 const std::string& keyFile,
956 const std::string& keyPassword);
957
958 void ClearCertificate();
959
960 void SetPkcs11(bool pkcs11)
961 {
962 pkcs11_ = pkcs11;
963 }
964
965 void ClearBody();
966
967 void SwapBody(std::string& body);
968
969 void SetBody(const std::string& body);
970
971 void SetBody(IRequestBody& body);
972
973 // This function can be used to disable chunked transfers if the
974 // remote server is Orthanc with a version <= 1.5.6.
975 void SetChunkedTransfersAllowed(bool allow)
976 {
977 allowChunkedTransfers_ = allow;
978 }
979
980 bool IsChunkedTransfersAllowed() const
981 {
982 return allowChunkedTransfers_;
983 }
984
985 void Execute(IAnswer& answer);
986
987 void Execute(HttpHeaders& answerHeaders /* out */,
988 std::string& answerBody /* out */);
989
990 void Execute(HttpHeaders& answerHeaders /* out */,
991 Json::Value& answerBody /* out */);
992
993 void Execute();
994 };
995 #endif
996
997
998
999 class IChunkedRequestReader : public boost::noncopyable
1000 {
1001 public:
1002 virtual ~IChunkedRequestReader()
1003 {
1004 }
1005
1006 virtual void AddChunk(const void* data,
1007 size_t size) = 0;
1008
1009 virtual void Execute(OrthancPluginRestOutput* output) = 0;
1010 };
1011
1012
1013 typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url,
1014 const OrthancPluginHttpRequest* request);
1015
1016
1017 namespace Internals
1018 {
1019 void NullRestCallback(OrthancPluginRestOutput* output,
1020 const char* url,
1021 const OrthancPluginHttpRequest* request);
1022
1023 IChunkedRequestReader *NullChunkedRestCallback(const char* url,
1024 const OrthancPluginHttpRequest* request);
1025
1026
1027 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
1028 template <ChunkedRestCallback Callback>
1029 static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader,
1030 const char* url,
1031 const OrthancPluginHttpRequest* request)
1032 {
1033 try
1034 {
1035 if (reader == NULL)
1036 {
1037 return OrthancPluginErrorCode_InternalError;
1038 }
1039 else
1040 {
1041 *reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(url, request));
1042 if (*reader == NULL)
1043 {
1044 return OrthancPluginErrorCode_Plugin;
1045 }
1046 else
1047 {
1048 return OrthancPluginErrorCode_Success;
1049 }
1050 }
1051 }
1052 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
1053 {
1054 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
1055 }
1056 catch (boost::bad_lexical_cast&)
1057 {
1058 return OrthancPluginErrorCode_BadFileFormat;
1059 }
1060 catch (...)
1061 {
1062 return OrthancPluginErrorCode_Plugin;
1063 }
1064 }
1065
1066 OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
1067 OrthancPluginServerChunkedRequestReader* reader,
1068 const void* data,
1069 uint32_t size);
1070
1071 OrthancPluginErrorCode ChunkedRequestReaderExecute(
1072 OrthancPluginServerChunkedRequestReader* reader,
1073 OrthancPluginRestOutput* output);
1074
1075 void ChunkedRequestReaderFinalize(
1076 OrthancPluginServerChunkedRequestReader* reader);
1077
1078 #else
1079
1080 OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
1081 const char* url,
1082 const OrthancPluginHttpRequest* request,
1083 RestCallback GetHandler,
1084 ChunkedRestCallback PostHandler,
1085 RestCallback DeleteHandler,
1086 ChunkedRestCallback PutHandler);
1087
1088 template<
1089 RestCallback GetHandler,
1090 ChunkedRestCallback PostHandler,
1091 RestCallback DeleteHandler,
1092 ChunkedRestCallback PutHandler
1093 >
1094 inline OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
1095 const char* url,
1096 const OrthancPluginHttpRequest* request)
1097 {
1098 return ChunkedRestCompatibility(output, url, request, GetHandler,
1099 PostHandler, DeleteHandler, PutHandler);
1100 }
1101 #endif
1102 }
1103
1104
1105
1106 // NB: We use a templated class instead of a templated function, because
1107 // default values are only available in functions since C++11
1108 template<
1109 RestCallback GetHandler = Internals::NullRestCallback,
1110 ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback,
1111 RestCallback DeleteHandler = Internals::NullRestCallback,
1112 ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback
1113 >
1114 class ChunkedRestRegistration : public boost::noncopyable
1115 {
1116 public:
1117 static void Apply(const std::string& uri)
1118 {
1119 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
1120 OrthancPluginRegisterChunkedRestCallback(
1121 GetGlobalContext(), uri.c_str(),
1122 GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect<GetHandler>,
1123 PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PostHandler>,
1124 DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect<DeleteHandler>,
1125 PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PutHandler>,
1126 Internals::ChunkedRequestReaderAddChunk,
1127 Internals::ChunkedRequestReaderExecute,
1128 Internals::ChunkedRequestReaderFinalize);
1129 #else
1130 OrthancPluginRegisterRestCallbackNoLock(
1131 GetGlobalContext(), uri.c_str(),
1132 Internals::ChunkedRestCompatibility<GetHandler, PostHandler, DeleteHandler, PutHandler>);
1133 #endif
1134 }
1135 };
1136
1137
1138
1139 #if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
1140 class IStorageCommitmentScpHandler : public boost::noncopyable
1141 {
1142 public:
1143 virtual ~IStorageCommitmentScpHandler()
1144 {
1145 }
1146
1147 virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
1148 const std::string& sopInstanceUid) = 0;
1149
1150 static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target,
1151 void* rawHandler,
1152 const char* sopClassUid,
1153 const char* sopInstanceUid);
1154
1155 static void Destructor(void* rawHandler);
1156 };
1157 #endif
1158
1159
1160 class DicomInstance : public boost::noncopyable
1161 {
1162 private:
1163 bool toFree_;
1164
1165 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
1166 const OrthancPluginDicomInstance* instance_;
1167 #else
1168 OrthancPluginDicomInstance* instance_;
1169 #endif
1170
1171 public:
1172 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
1173 DicomInstance(const OrthancPluginDicomInstance* instance);
1174 #else
1175 DicomInstance(OrthancPluginDicomInstance* instance);
1176 #endif
1177
1178 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1179 DicomInstance(const void* buffer,
1180 size_t size);
1181 #endif
1182
1183 ~DicomInstance();
1184
1185 std::string GetRemoteAet() const;
1186
1187 const void* GetBuffer() const
1188 {
1189 return OrthancPluginGetInstanceData(GetGlobalContext(), instance_);
1190 }
1191
1192 size_t GetSize() const
1193 {
1194 return static_cast<size_t>(OrthancPluginGetInstanceSize(GetGlobalContext(), instance_));
1195 }
1196
1197 void GetJson(Json::Value& target) const;
1198
1199 void GetSimplifiedJson(Json::Value& target) const;
1200
1201 OrthancPluginInstanceOrigin GetOrigin() const
1202 {
1203 return OrthancPluginGetInstanceOrigin(GetGlobalContext(), instance_);
1204 }
1205
1206 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
1207 std::string GetTransferSyntaxUid() const;
1208 #endif
1209
1210 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
1211 bool HasPixelData() const;
1212 #endif
1213
1214 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1215 unsigned int GetFramesCount() const
1216 {
1217 return OrthancPluginGetInstanceFramesCount(GetGlobalContext(), instance_);
1218 }
1219 #endif
1220
1221 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1222 void GetRawFrame(std::string& target,
1223 unsigned int frameIndex) const;
1224 #endif
1225
1226 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1227 OrthancImage* GetDecodedFrame(unsigned int frameIndex) const;
1228 #endif
1229
1230 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1231 void Serialize(std::string& target) const;
1232 #endif
1233
1234 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
1235 static DicomInstance* Transcode(const void* buffer,
1236 size_t size,
1237 const std::string& transferSyntax);
1238 #endif
1239 };
1240 }