Mercurial > hg > orthanc-webviewer
annotate Plugin/Plugin.cpp @ 99:46ec13a1177c refactoring
use of ordered-slices
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 27 Nov 2015 21:39:41 +0100 |
parents | a6ba21a083e5 |
children | f5b1a9267da0 |
rev | line source |
---|---|
0 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * | |
6 * This program is free software: you can redistribute it and/or | |
7 * modify it under the terms of the GNU Affero General Public License | |
8 * as published by the Free Software Foundation, either version 3 of | |
9 * the License, or (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, but | |
12 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * Affero General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU Affero General Public License | |
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 **/ | |
19 | |
20 | |
21 #include <boost/thread.hpp> | |
22 #include <boost/lexical_cast.hpp> | |
23 #include <EmbeddedResources.h> | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
24 #include <boost/filesystem.hpp> |
0 | 25 |
26 | 26 #include "../Orthanc/Core/OrthancException.h" |
0 | 27 #include "ViewerToolbox.h" |
28 #include "ViewerPrefetchPolicy.h" | |
29 #include "DecodedImageAdapter.h" | |
30 #include "InstanceInformationAdapter.h" | |
31 #include "SeriesInformationAdapter.h" | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
32 #include "../Orthanc/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h" |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
33 #include "../Orthanc/Core/Toolbox.h" |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
34 |
0 | 35 |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
36 static OrthancPluginContext* context_ = NULL; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
37 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
38 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
39 |
0 | 40 class CacheContext |
41 { | |
42 private: | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
43 class DynamicString : public Orthanc::IDynamicObject |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
44 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
45 private: |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
46 std::string value_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
47 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
48 public: |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
49 DynamicString(const char* value) : value_(value) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
50 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
51 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
52 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
53 const std::string& GetValue() const |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
54 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
55 return value_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
56 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
57 }; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
58 |
58 | 59 Orthanc::FilesystemStorage storage_; |
60 Orthanc::SQLite::Connection db_; | |
61 | |
0 | 62 std::auto_ptr<OrthancPlugins::CacheManager> cache_; |
63 std::auto_ptr<OrthancPlugins::CacheScheduler> scheduler_; | |
64 | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
65 Orthanc::SharedMessageQueue newInstances_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
66 bool stop_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
67 boost::thread newInstancesThread_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
68 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
69 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
70 static void NewInstancesThread(CacheContext* cache) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
71 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
72 while (!cache->stop_) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
73 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
74 std::auto_ptr<Orthanc::IDynamicObject> obj(cache->newInstances_.Dequeue(100)); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
75 if (obj.get() != NULL) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
76 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
77 const std::string& instanceId = dynamic_cast<DynamicString&>(*obj).GetValue(); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
78 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
79 // On the reception of a new instance, precompute its spatial position |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
80 cache->GetScheduler().Prefetch(OrthancPlugins::CacheBundle_InstanceInformation, instanceId); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
81 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
82 // Indalidate the parent series of the instance |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
83 std::string uri = "/instances/" + std::string(instanceId); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
84 Json::Value instance; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
85 if (OrthancPlugins::GetJsonFromOrthanc(instance, context_, uri)) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
86 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
87 std::string seriesId = instance["ParentSeries"].asString(); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
88 cache->GetScheduler().Invalidate(OrthancPlugins::CacheBundle_SeriesInformation, seriesId); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
89 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
90 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
91 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
92 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
93 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
94 |
0 | 95 public: |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
96 CacheContext(const std::string& path) : storage_(path), stop_(false) |
0 | 97 { |
98 boost::filesystem::path p(path); | |
58 | 99 db_.Open((p / "cache.db").string()); |
0 | 100 |
58 | 101 cache_.reset(new OrthancPlugins::CacheManager(db_, storage_)); |
0 | 102 //cache_->SetSanityCheckEnabled(true); // For debug |
103 | |
104 scheduler_.reset(new OrthancPlugins::CacheScheduler(*cache_, 100)); | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
105 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
106 newInstancesThread_ = boost::thread(NewInstancesThread, this); |
0 | 107 } |
108 | |
58 | 109 ~CacheContext() |
110 { | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
111 stop_ = true; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
112 if (newInstancesThread_.joinable()) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
113 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
114 newInstancesThread_.join(); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
115 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
116 |
58 | 117 scheduler_.reset(NULL); |
118 cache_.reset(NULL); | |
119 } | |
120 | |
0 | 121 OrthancPlugins::CacheScheduler& GetScheduler() |
122 { | |
123 return *scheduler_; | |
124 } | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
125 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
126 void SignalNewInstance(const char* instanceId) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
127 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
128 newInstances_.Enqueue(new DynamicString(instanceId)); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
129 } |
0 | 130 }; |
131 | |
132 | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
133 |
0 | 134 static CacheContext* cache_ = NULL; |
135 | |
136 | |
137 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
138 static OrthancPluginErrorCode OnChangeCallback(OrthancPluginChangeType changeType, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
139 OrthancPluginResourceType resourceType, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
140 const char* resourceId) |
0 | 141 { |
142 try | |
143 { | |
144 if (changeType == OrthancPluginChangeType_NewInstance && | |
145 resourceType == OrthancPluginResourceType_Instance) | |
146 { | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
147 cache_->SignalNewInstance(resourceId); |
0 | 148 } |
149 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
150 return OrthancPluginErrorCode_Success; |
0 | 151 } |
152 catch (std::runtime_error& e) | |
153 { | |
154 OrthancPluginLogError(context_, e.what()); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
155 return OrthancPluginErrorCode_Success; // Ignore error |
0 | 156 } |
157 } | |
158 | |
159 | |
160 | |
161 template <enum OrthancPlugins::CacheBundle bundle> | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
162 static OrthancPluginErrorCode ServeCache(OrthancPluginRestOutput* output, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
163 const char* url, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
164 const OrthancPluginHttpRequest* request) |
0 | 165 { |
166 try | |
167 { | |
168 if (request->method != OrthancPluginHttpMethod_Get) | |
169 { | |
170 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
171 return OrthancPluginErrorCode_Success; |
0 | 172 } |
173 | |
174 const std::string id = request->groups[0]; | |
175 std::string content; | |
176 | |
177 if (cache_->GetScheduler().Access(content, bundle, id)) | |
178 { | |
179 OrthancPluginAnswerBuffer(context_, output, content.c_str(), content.size(), "application/json"); | |
180 } | |
181 else | |
182 { | |
183 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
184 } | |
185 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
186 return OrthancPluginErrorCode_Success; |
0 | 187 } |
188 catch (Orthanc::OrthancException& e) | |
189 { | |
190 OrthancPluginLogError(context_, e.What()); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
191 return OrthancPluginErrorCode_Plugin; |
0 | 192 } |
193 catch (std::runtime_error& e) | |
194 { | |
195 OrthancPluginLogError(context_, e.what()); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
196 return OrthancPluginErrorCode_Plugin; |
0 | 197 } |
198 catch (boost::bad_lexical_cast&) | |
199 { | |
200 OrthancPluginLogError(context_, "Bad lexical cast"); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
201 return OrthancPluginErrorCode_Plugin; |
0 | 202 } |
203 } | |
204 | |
205 | |
206 | |
207 | |
208 #if ORTHANC_STANDALONE == 0 | |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
209 static OrthancPluginErrorCode ServeWebViewer(OrthancPluginRestOutput* output, |
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
210 const char* url, |
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
211 const OrthancPluginHttpRequest* request) |
0 | 212 { |
213 if (request->method != OrthancPluginHttpMethod_Get) | |
214 { | |
215 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
216 return OrthancPluginErrorCode_Success; |
0 | 217 } |
218 | |
219 const std::string path = std::string(WEB_VIEWER_PATH) + std::string(request->groups[0]); | |
220 const char* mime = OrthancPlugins::GetMimeType(path); | |
221 | |
222 std::string s; | |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
223 try |
0 | 224 { |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
225 Orthanc::Toolbox::ReadFile(s, path); |
0 | 226 const char* resource = s.size() ? s.c_str() : NULL; |
227 OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime); | |
228 } | |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
229 catch (Orthanc::OrthancException&) |
0 | 230 { |
231 std::string s = "Inexistent file in served folder: " + path; | |
232 OrthancPluginLogError(context_, s.c_str()); | |
233 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
234 } | |
235 | |
99
46ec13a1177c
use of ordered-slices
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
96
diff
changeset
|
236 return OrthancPluginErrorCode_Success; |
0 | 237 } |
238 #endif | |
239 | |
240 | |
241 | |
31 | 242 template <enum Orthanc::EmbeddedResources::DirectoryResourceId folder> |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
243 static OrthancPluginErrorCode ServeEmbeddedFolder(OrthancPluginRestOutput* output, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
244 const char* url, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
245 const OrthancPluginHttpRequest* request) |
0 | 246 { |
247 if (request->method != OrthancPluginHttpMethod_Get) | |
248 { | |
249 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
250 return OrthancPluginErrorCode_Success; |
0 | 251 } |
252 | |
253 std::string path = "/" + std::string(request->groups[0]); | |
254 const char* mime = OrthancPlugins::GetMimeType(path); | |
255 | |
256 try | |
257 { | |
258 std::string s; | |
31 | 259 Orthanc::EmbeddedResources::GetDirectoryResource(s, folder, path.c_str()); |
0 | 260 |
261 const char* resource = s.size() ? s.c_str() : NULL; | |
262 OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime); | |
263 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
264 return OrthancPluginErrorCode_Success; |
0 | 265 } |
266 catch (std::runtime_error&) | |
267 { | |
268 std::string s = "Unknown static resource in plugin: " + std::string(request->groups[0]); | |
269 OrthancPluginLogError(context_, s.c_str()); | |
270 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
271 return OrthancPluginErrorCode_Success; |
0 | 272 } |
273 } | |
274 | |
275 | |
276 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
277 static OrthancPluginErrorCode IsStableSeries(OrthancPluginRestOutput* output, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
278 const char* url, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
279 const OrthancPluginHttpRequest* request) |
19 | 280 { |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
281 try |
19 | 282 { |
283 if (request->method != OrthancPluginHttpMethod_Get) | |
284 { | |
285 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
286 return OrthancPluginErrorCode_Success; |
19 | 287 } |
288 | |
289 const std::string id = request->groups[0]; | |
290 Json::Value series; | |
291 | |
292 if (OrthancPlugins::GetJsonFromOrthanc(series, context_, "/series/" + id) && | |
293 series.type() == Json::objectValue) | |
294 { | |
295 bool value = (series["IsStable"].asBool() || | |
296 series["Status"].asString() == "Complete"); | |
297 std::string answer = value ? "true" : "false"; | |
298 OrthancPluginAnswerBuffer(context_, output, answer.c_str(), answer.size(), "application/json"); | |
299 } | |
300 else | |
301 { | |
302 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
303 } | |
304 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
305 return OrthancPluginErrorCode_Success; |
19 | 306 } |
307 catch (Orthanc::OrthancException& e) | |
308 { | |
309 OrthancPluginLogError(context_, e.What()); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
310 return OrthancPluginErrorCode_Plugin; |
19 | 311 } |
312 catch (std::runtime_error& e) | |
313 { | |
314 OrthancPluginLogError(context_, e.what()); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
315 return OrthancPluginErrorCode_Plugin; |
19 | 316 } |
317 catch (boost::bad_lexical_cast&) | |
318 { | |
319 OrthancPluginLogError(context_, "Bad lexical cast"); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
320 return OrthancPluginErrorCode_Plugin; |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
321 } |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
322 } |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
323 |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
324 |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
325 static OrthancPluginErrorCode DecodeImageCallback(OrthancPluginImage** target, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
326 const void* dicom, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
327 const uint32_t size, |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
328 uint32_t frameIndex) |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
329 { |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
330 try |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
331 { |
96 | 332 std::auto_ptr<OrthancPlugins::OrthancImageWrapper> image; |
333 | |
334 #if 0 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
335 // Do not use the cache |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
336 OrthancPlugins::GdcmImageDecoder decoder(dicom, size); |
96 | 337 image.reset(new OrthancPlugins::OrthancImageWrapper(context_, decoder, frameIndex)); |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
338 #else |
96 | 339 using namespace OrthancPlugins; |
340 ICacheFactory& factory = cache_->GetScheduler().GetFactory(CacheBundle_DecodedImage); | |
341 image.reset(dynamic_cast<DecodedImageAdapter&>(factory).GetDecoderCache().Decode(context_, dicom, size, frameIndex)); | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
342 #endif |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
343 |
96 | 344 *target = image->Release(); |
345 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
346 return OrthancPluginErrorCode_Success; |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
347 } |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
348 catch (std::runtime_error& e) |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
349 { |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
350 *target = NULL; |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
351 |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
352 std::string s = "Cannot decode image using GDCM: " + std::string(e.what()); |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
353 OrthancPluginLogError(context_, s.c_str()); |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
354 return OrthancPluginErrorCode_Plugin; |
19 | 355 } |
356 } | |
357 | |
0 | 358 |
359 extern "C" | |
360 { | |
361 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
362 { | |
363 using namespace OrthancPlugins; | |
364 | |
365 context_ = context; | |
366 OrthancPluginLogWarning(context_, "Initializing the Web viewer"); | |
367 | |
368 | |
369 /* Check the version of the Orthanc core */ | |
370 if (OrthancPluginCheckVersion(context_) == 0) | |
371 { | |
372 char info[1024]; | |
373 sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", | |
374 context_->orthancVersion, | |
375 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, | |
376 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, | |
377 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); | |
378 OrthancPluginLogError(context_, info); | |
379 return -1; | |
380 } | |
381 | |
382 OrthancPluginSetDescription(context_, "Provides a Web viewer of DICOM series within Orthanc."); | |
383 | |
384 | |
95
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
385 // Replace the default decoder of DICOM images that is built in Orthanc |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
386 OrthancPluginRegisterDecodeImageCallback(context_, DecodeImageCallback); |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
387 |
dbe7c97b6b4a
replace built-in decoder
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
86
diff
changeset
|
388 |
0 | 389 /* By default, use half of the available processing cores for the decoding of DICOM images */ |
390 int decodingThreads = boost::thread::hardware_concurrency() / 2; | |
391 if (decodingThreads == 0) | |
392 { | |
393 decodingThreads = 1; | |
394 } | |
395 | |
396 | |
397 try | |
398 { | |
399 /* Read the configuration of the Web viewer */ | |
400 Json::Value configuration; | |
401 if (!ReadConfiguration(configuration, context)) | |
402 { | |
403 OrthancPluginLogError(context_, "Unable to read the configuration file of Orthanc"); | |
404 return -1; | |
405 } | |
406 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
407 // By default, the cache of the Web viewer is located inside the |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
408 // "StorageDirectory" of Orthanc |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
409 boost::filesystem::path cachePath = GetStringValue(configuration, "StorageDirectory", "."); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
410 cachePath /= "WebViewerCache"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
411 int cacheSize = 100; // By default, a cache of 100 MB is used |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
412 |
0 | 413 if (configuration.isMember("WebViewer")) |
414 { | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
415 std::string key = "CachePath"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
416 if (!configuration["WebViewer"].isMember(key)) |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
417 { |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
418 // For backward compatibility with the initial release of the Web viewer |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
419 key = "Cache"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
420 } |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
421 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
422 cachePath = GetStringValue(configuration["WebViewer"], key, cachePath.string()); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
423 cacheSize = GetIntegerValue(configuration["WebViewer"], "CacheSize", cacheSize); |
0 | 424 decodingThreads = GetIntegerValue(configuration["WebViewer"], "Threads", decodingThreads); |
425 } | |
426 | |
427 std::string message = ("Web viewer using " + boost::lexical_cast<std::string>(decodingThreads) + | |
428 " threads for the decoding of the DICOM images"); | |
429 OrthancPluginLogWarning(context_, message.c_str()); | |
430 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
431 if (decodingThreads <= 0 || |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
432 cacheSize <= 0) |
0 | 433 { |
434 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
435 } | |
436 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
437 message = "Storing the cache of the Web viewer in folder: " + cachePath.string(); |
0 | 438 OrthancPluginLogWarning(context_, message.c_str()); |
439 | |
440 | |
441 /* Create the cache */ | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
442 cache_ = new CacheContext(cachePath.string()); |
0 | 443 cache_->GetScheduler().RegisterPolicy(new ViewerPrefetchPolicy(context_)); |
444 cache_->GetScheduler().Register(CacheBundle_SeriesInformation, | |
445 new SeriesInformationAdapter(context_, cache_->GetScheduler()), 1); | |
446 cache_->GetScheduler().Register(CacheBundle_InstanceInformation, | |
447 new InstanceInformationAdapter(context_), 1); | |
448 cache_->GetScheduler().Register(CacheBundle_DecodedImage, | |
449 new DecodedImageAdapter(context_), decodingThreads); | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
450 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
451 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
452 /* Set the quotas */ |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
453 cache_->GetScheduler().SetQuota(CacheBundle_SeriesInformation, 1000, 0); // Keep info about 1000 series |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
454 cache_->GetScheduler().SetQuota(CacheBundle_InstanceInformation, 10000, 0); // Keep info about 10,000 instances |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
455 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
456 message = "Web viewer using a cache of " + boost::lexical_cast<std::string>(cacheSize) + " MB"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
457 OrthancPluginLogWarning(context_, message.c_str()); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
458 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
459 cache_->GetScheduler().SetQuota(CacheBundle_DecodedImage, 0, static_cast<uint64_t>(cacheSize) * 1024 * 1024); |
0 | 460 } |
461 catch (std::runtime_error& e) | |
462 { | |
463 OrthancPluginLogError(context_, e.what()); | |
464 return -1; | |
465 } | |
466 catch (Orthanc::OrthancException& e) | |
467 { | |
468 OrthancPluginLogError(context_, e.What()); | |
469 return -1; | |
470 } | |
471 | |
472 | |
473 /* Install the callbacks */ | |
474 OrthancPluginRegisterRestCallback(context_, "/web-viewer/series/(.*)", ServeCache<CacheBundle_SeriesInformation>); | |
19 | 475 OrthancPluginRegisterRestCallback(context_, "/web-viewer/is-stable-series/(.*)", IsStableSeries); |
0 | 476 OrthancPluginRegisterRestCallback(context_, "/web-viewer/instances/(.*)", ServeCache<CacheBundle_DecodedImage>); |
31 | 477 OrthancPluginRegisterRestCallback(context, "/web-viewer/libs/(.*)", ServeEmbeddedFolder<Orthanc::EmbeddedResources::JAVASCRIPT_LIBS>); |
0 | 478 |
479 #if ORTHANC_STANDALONE == 1 | |
31 | 480 OrthancPluginRegisterRestCallback(context, "/web-viewer/app/(.*)", ServeEmbeddedFolder<Orthanc::EmbeddedResources::WEB_VIEWER>); |
0 | 481 #else |
482 OrthancPluginRegisterRestCallback(context, "/web-viewer/app/(.*)", ServeWebViewer); | |
483 #endif | |
484 | |
485 OrthancPluginRegisterOnChangeCallback(context, OnChangeCallback); | |
486 | |
487 | |
488 /* Extend the default Orthanc Explorer with custom JavaScript */ | |
489 std::string explorer; | |
31 | 490 Orthanc::EmbeddedResources::GetFileResource(explorer, Orthanc::EmbeddedResources::ORTHANC_EXPLORER); |
0 | 491 OrthancPluginExtendOrthancExplorer(context_, explorer.c_str()); |
492 | |
493 return 0; | |
494 } | |
495 | |
496 | |
497 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
498 { | |
499 OrthancPluginLogWarning(context_, "Finalizing the Web viewer"); | |
500 | |
501 if (cache_ != NULL) | |
502 { | |
503 delete cache_; | |
504 cache_ = NULL; | |
505 } | |
506 } | |
507 | |
508 | |
509 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
510 { | |
511 return "web-viewer"; | |
512 } | |
513 | |
514 | |
515 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
516 { | |
12 | 517 return ORTHANC_WEBVIEWER_VERSION; |
0 | 518 } |
519 } |