Mercurial > hg > orthanc
comparison Plugins/Engine/OrthancPlugins.cpp @ 1199:a843ee8bb903 db-changes
separated thread for change callbacks in plugins
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 23 Oct 2014 14:29:45 +0200 |
parents | 1169528a9a5f |
children | f1c01451a8ee |
comparison
equal
deleted
inserted
replaced
1198:1169528a9a5f | 1199:a843ee8bb903 |
---|---|
37 #include "../../Core/Toolbox.h" | 37 #include "../../Core/Toolbox.h" |
38 #include "../../Core/HttpServer/HttpOutput.h" | 38 #include "../../Core/HttpServer/HttpOutput.h" |
39 #include "../../Core/ImageFormats/PngWriter.h" | 39 #include "../../Core/ImageFormats/PngWriter.h" |
40 #include "../../OrthancServer/ServerToolbox.h" | 40 #include "../../OrthancServer/ServerToolbox.h" |
41 #include "../../OrthancServer/OrthancInitialization.h" | 41 #include "../../OrthancServer/OrthancInitialization.h" |
42 #include "../../Core/MultiThreading/SharedMessageQueue.h" | |
42 | 43 |
43 #include <boost/thread.hpp> | 44 #include <boost/thread.hpp> |
44 #include <boost/regex.hpp> | 45 #include <boost/regex.hpp> |
45 #include <glog/logging.h> | 46 #include <glog/logging.h> |
46 | 47 |
47 namespace Orthanc | 48 namespace Orthanc |
48 { | 49 { |
50 static OrthancPluginResourceType Convert(ResourceType type) | |
51 { | |
52 switch (type) | |
53 { | |
54 case ResourceType_Patient: | |
55 return OrthancPluginResourceType_Patient; | |
56 | |
57 case ResourceType_Study: | |
58 return OrthancPluginResourceType_Study; | |
59 | |
60 case ResourceType_Series: | |
61 return OrthancPluginResourceType_Series; | |
62 | |
63 case ResourceType_Instance: | |
64 return OrthancPluginResourceType_Instance; | |
65 | |
66 default: | |
67 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
68 } | |
69 } | |
70 | |
71 | |
72 static OrthancPluginChangeType Convert(ChangeType type) | |
73 { | |
74 switch (type) | |
75 { | |
76 case ChangeType_CompletedSeries: | |
77 return OrthancPluginChangeType_CompletedSeries; | |
78 | |
79 case ChangeType_Deleted: | |
80 return OrthancPluginChangeType_Deleted; | |
81 | |
82 case ChangeType_NewChildInstance: | |
83 return OrthancPluginChangeType_NewChildInstance; | |
84 | |
85 case ChangeType_NewInstance: | |
86 return OrthancPluginChangeType_NewInstance; | |
87 | |
88 case ChangeType_NewPatient: | |
89 return OrthancPluginChangeType_NewPatient; | |
90 | |
91 case ChangeType_NewSeries: | |
92 return OrthancPluginChangeType_NewSeries; | |
93 | |
94 case ChangeType_NewStudy: | |
95 return OrthancPluginChangeType_NewStudy; | |
96 | |
97 case ChangeType_StablePatient: | |
98 return OrthancPluginChangeType_StablePatient; | |
99 | |
100 case ChangeType_StableSeries: | |
101 return OrthancPluginChangeType_StableSeries; | |
102 | |
103 case ChangeType_StableStudy: | |
104 return OrthancPluginChangeType_StableStudy; | |
105 | |
106 default: | |
107 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
108 } | |
109 } | |
110 | |
111 | |
49 namespace | 112 namespace |
50 { | 113 { |
51 // Anonymous namespace to avoid clashes between compilation modules | 114 // Anonymous namespace to avoid clashes between compilation modules |
52 class StringHttpOutput : public IHttpOutputStream | 115 class StringHttpOutput : public IHttpOutputStream |
53 { | 116 { |
71 virtual void Send(bool isHeader, const void* buffer, size_t length) | 134 virtual void Send(bool isHeader, const void* buffer, size_t length) |
72 { | 135 { |
73 if (!isHeader) | 136 if (!isHeader) |
74 { | 137 { |
75 buffer_.AddChunk(reinterpret_cast<const char*>(buffer), length); | 138 buffer_.AddChunk(reinterpret_cast<const char*>(buffer), length); |
139 } | |
140 } | |
141 }; | |
142 | |
143 | |
144 class PendingChange : public IDynamicObject | |
145 { | |
146 private: | |
147 OrthancPluginChangeType changeType_; | |
148 OrthancPluginResourceType resourceType_; | |
149 std::string publicId_; | |
150 | |
151 public: | |
152 PendingChange(const ServerIndexChange& change) | |
153 { | |
154 changeType_ = Convert(change.GetChangeType()); | |
155 resourceType_ = Convert(change.GetResourceType()); | |
156 publicId_ = change.GetPublicId(); | |
157 } | |
158 | |
159 void Submit(std::list<OrthancPluginOnChangeCallback>& callbacks) | |
160 { | |
161 for (std::list<OrthancPluginOnChangeCallback>::const_iterator | |
162 callback = callbacks.begin(); | |
163 callback != callbacks.end(); ++callback) | |
164 { | |
165 (*callback) (changeType_, resourceType_, publicId_.c_str()); | |
76 } | 166 } |
77 } | 167 } |
78 }; | 168 }; |
79 } | 169 } |
80 | 170 |
93 OnStoredCallbacks onStoredCallbacks_; | 183 OnStoredCallbacks onStoredCallbacks_; |
94 OnChangeCallbacks onChangeCallbacks_; | 184 OnChangeCallbacks onChangeCallbacks_; |
95 bool hasStorageArea_; | 185 bool hasStorageArea_; |
96 _OrthancPluginRegisterStorageArea storageArea_; | 186 _OrthancPluginRegisterStorageArea storageArea_; |
97 boost::mutex callbackMutex_; | 187 boost::mutex callbackMutex_; |
188 SharedMessageQueue pendingChanges_; | |
189 boost::thread changeThread_; | |
190 bool done_; | |
98 | 191 |
99 PImpl(ServerContext& context) : | 192 PImpl(ServerContext& context) : |
100 context_(context), | 193 context_(context), |
101 restApi_(NULL), | 194 restApi_(NULL), |
102 hasStorageArea_(false) | 195 hasStorageArea_(false), |
196 done_(false) | |
103 { | 197 { |
104 memset(&storageArea_, 0, sizeof(storageArea_)); | 198 memset(&storageArea_, 0, sizeof(storageArea_)); |
105 } | 199 } |
200 | |
201 | |
202 static void ChangeThread(PImpl* that) | |
203 { | |
204 while (!that->done_) | |
205 { | |
206 std::auto_ptr<IDynamicObject> obj(that->pendingChanges_.Dequeue(500)); | |
207 | |
208 if (obj.get() != NULL) | |
209 { | |
210 boost::mutex::scoped_lock lock(that->callbackMutex_); | |
211 PendingChange& change = *dynamic_cast<PendingChange*>(obj.get()); | |
212 change.Submit(that->onChangeCallbacks_); | |
213 } | |
214 } | |
215 } | |
106 }; | 216 }; |
107 | 217 |
108 | 218 |
219 | |
109 static char* CopyString(const std::string& str) | 220 static char* CopyString(const std::string& str) |
110 { | 221 { |
111 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); | 222 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); |
112 if (result == NULL) | 223 if (result == NULL) |
113 { | 224 { |
125 | 236 |
126 return result; | 237 return result; |
127 } | 238 } |
128 | 239 |
129 | 240 |
130 static OrthancPluginResourceType Convert(ResourceType type) | |
131 { | |
132 switch (type) | |
133 { | |
134 case ResourceType_Patient: | |
135 return OrthancPluginResourceType_Patient; | |
136 | |
137 case ResourceType_Study: | |
138 return OrthancPluginResourceType_Study; | |
139 | |
140 case ResourceType_Series: | |
141 return OrthancPluginResourceType_Series; | |
142 | |
143 case ResourceType_Instance: | |
144 return OrthancPluginResourceType_Instance; | |
145 | |
146 default: | |
147 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
148 } | |
149 } | |
150 | |
151 | |
152 static OrthancPluginChangeType Convert(ChangeType type) | |
153 { | |
154 switch (type) | |
155 { | |
156 case ChangeType_CompletedSeries: | |
157 return OrthancPluginChangeType_CompletedSeries; | |
158 | |
159 case ChangeType_Deleted: | |
160 return OrthancPluginChangeType_Deleted; | |
161 | |
162 case ChangeType_NewChildInstance: | |
163 return OrthancPluginChangeType_NewChildInstance; | |
164 | |
165 case ChangeType_NewInstance: | |
166 return OrthancPluginChangeType_NewInstance; | |
167 | |
168 case ChangeType_NewPatient: | |
169 return OrthancPluginChangeType_NewPatient; | |
170 | |
171 case ChangeType_NewSeries: | |
172 return OrthancPluginChangeType_NewSeries; | |
173 | |
174 case ChangeType_NewStudy: | |
175 return OrthancPluginChangeType_NewStudy; | |
176 | |
177 case ChangeType_StablePatient: | |
178 return OrthancPluginChangeType_StablePatient; | |
179 | |
180 case ChangeType_StableSeries: | |
181 return OrthancPluginChangeType_StableSeries; | |
182 | |
183 case ChangeType_StableStudy: | |
184 return OrthancPluginChangeType_StableStudy; | |
185 | |
186 default: | |
187 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
188 } | |
189 } | |
190 | |
191 | |
192 OrthancPlugins::OrthancPlugins(ServerContext& context) | 241 OrthancPlugins::OrthancPlugins(ServerContext& context) |
193 { | 242 { |
194 pimpl_.reset(new PImpl(context)); | 243 pimpl_.reset(new PImpl(context)); |
244 pimpl_->changeThread_ = boost::thread(PImpl::ChangeThread, pimpl_.get()); | |
195 } | 245 } |
196 | 246 |
197 | 247 |
198 OrthancPlugins::~OrthancPlugins() | 248 OrthancPlugins::~OrthancPlugins() |
199 { | 249 { |
250 Stop(); | |
251 | |
200 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); | 252 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); |
201 it != pimpl_->restCallbacks_.end(); ++it) | 253 it != pimpl_->restCallbacks_.end(); ++it) |
202 { | 254 { |
203 // Delete the regular expression associated with this callback | 255 // Delete the regular expression associated with this callback |
204 delete it->first; | 256 delete it->first; |
205 } | 257 } |
206 } | 258 } |
259 | |
260 | |
261 void OrthancPlugins::Stop() | |
262 { | |
263 if (!pimpl_->done_) | |
264 { | |
265 pimpl_->done_ = true; | |
266 pimpl_->changeThread_.join(); | |
267 } | |
268 } | |
269 | |
207 | 270 |
208 | 271 |
209 static void ArgumentsToPlugin(std::vector<const char*>& keys, | 272 static void ArgumentsToPlugin(std::vector<const char*>& keys, |
210 std::vector<const char*>& values, | 273 std::vector<const char*>& values, |
211 const HttpHandler::Arguments& arguments) | 274 const HttpHandler::Arguments& arguments) |
365 | 428 |
366 | 429 |
367 | 430 |
368 void OrthancPlugins::SignalChange(const ServerIndexChange& change) | 431 void OrthancPlugins::SignalChange(const ServerIndexChange& change) |
369 { | 432 { |
370 OrthancPluginChangeType c; | |
371 OrthancPluginResourceType r; | |
372 | |
373 try | 433 try |
374 { | 434 { |
375 c = Convert(change.GetChangeType()); | 435 pimpl_->pendingChanges_.Enqueue(new PendingChange(change)); |
376 r = Convert(change.GetResourceType()); | |
377 } | 436 } |
378 catch (OrthancException&) | 437 catch (OrthancException&) |
379 { | 438 { |
380 // This change type or resource type is not supported by the plugin SDK | 439 // This change type or resource type is not supported by the plugin SDK |
381 return; | 440 return; |
382 } | |
383 | |
384 boost::mutex::scoped_lock lock(pimpl_->callbackMutex_); | |
385 | |
386 for (PImpl::OnChangeCallbacks::const_iterator | |
387 callback = pimpl_->onChangeCallbacks_.begin(); | |
388 callback != pimpl_->onChangeCallbacks_.end(); ++callback) | |
389 { | |
390 (*callback) (c, r, change.GetPublicId().c_str()); | |
391 } | 441 } |
392 } | 442 } |
393 | 443 |
394 | 444 |
395 | 445 |
681 } | 731 } |
682 } | 732 } |
683 | 733 |
684 | 734 |
685 void OrthancPlugins::LookupResource(_OrthancPluginService service, | 735 void OrthancPlugins::LookupResource(_OrthancPluginService service, |
686 const void* parameters) | 736 const void* parameters) |
687 { | 737 { |
688 const _OrthancPluginRetrieveDynamicString& p = | 738 const _OrthancPluginRetrieveDynamicString& p = |
689 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters); | 739 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters); |
690 | 740 |
691 /** | 741 /** |