Mercurial > hg > orthanc-webviewer
annotate Plugin/Plugin.cpp @ 79:abdde1dfb3eb
use sdk 0.9.4
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 25 Sep 2015 12:32:37 +0200 |
parents | e15a59a4b4d4 |
children | c44ab3266343 |
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" | |
32 | |
33 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
34 #if (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER >= 9 && ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= 5) |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
35 # define RETURN_TYPE OrthancPluginErrorCode |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
36 # define RETURN_SUCCESS OrthancPluginErrorCode_Success |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
37 # define RETURN_FAILURE OrthancPluginErrorCode_Plugin |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
38 #else |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
39 # define RETURN_TYPE int32_t |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
40 # define RETURN_SUCCESS 0 |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
41 # define RETURN_FAILURE -1 |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
42 #endif |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
43 |
0 | 44 |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
45 static OrthancPluginContext* context_ = NULL; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
46 |
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 |
0 | 49 class CacheContext |
50 { | |
51 private: | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
52 class DynamicString : public Orthanc::IDynamicObject |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
53 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
54 private: |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
55 std::string 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 public: |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
58 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
|
59 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
60 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
61 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
62 const std::string& GetValue() const |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
63 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
64 return value_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
65 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
66 }; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
67 |
58 | 68 Orthanc::FilesystemStorage storage_; |
69 Orthanc::SQLite::Connection db_; | |
70 | |
0 | 71 std::auto_ptr<OrthancPlugins::CacheManager> cache_; |
72 std::auto_ptr<OrthancPlugins::CacheScheduler> scheduler_; | |
73 | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
74 Orthanc::SharedMessageQueue newInstances_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
75 bool stop_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
76 boost::thread newInstancesThread_; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
77 |
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 static void NewInstancesThread(CacheContext* cache) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
80 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
81 while (!cache->stop_) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
82 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
83 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
|
84 if (obj.get() != NULL) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
85 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
86 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
|
87 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
88 // 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
|
89 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
|
90 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
91 // 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
|
92 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
|
93 Json::Value instance; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
94 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
|
95 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
96 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
|
97 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
|
98 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
99 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
100 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
101 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
102 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
103 |
0 | 104 public: |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
105 CacheContext(const std::string& path) : storage_(path), stop_(false) |
0 | 106 { |
107 boost::filesystem::path p(path); | |
58 | 108 db_.Open((p / "cache.db").string()); |
0 | 109 |
58 | 110 cache_.reset(new OrthancPlugins::CacheManager(db_, storage_)); |
0 | 111 //cache_->SetSanityCheckEnabled(true); // For debug |
112 | |
113 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
|
114 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
115 newInstancesThread_ = boost::thread(NewInstancesThread, this); |
0 | 116 } |
117 | |
58 | 118 ~CacheContext() |
119 { | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
120 stop_ = true; |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
121 if (newInstancesThread_.joinable()) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
122 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
123 newInstancesThread_.join(); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
124 } |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
125 |
58 | 126 scheduler_.reset(NULL); |
127 cache_.reset(NULL); | |
128 } | |
129 | |
0 | 130 OrthancPlugins::CacheScheduler& GetScheduler() |
131 { | |
132 return *scheduler_; | |
133 } | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
134 |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
135 void SignalNewInstance(const char* instanceId) |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
136 { |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
137 newInstances_.Enqueue(new DynamicString(instanceId)); |
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
138 } |
0 | 139 }; |
140 | |
141 | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
142 |
0 | 143 static CacheContext* cache_ = NULL; |
144 | |
145 | |
146 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
147 static RETURN_TYPE OnChangeCallback(OrthancPluginChangeType changeType, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
148 OrthancPluginResourceType resourceType, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
149 const char* resourceId) |
0 | 150 { |
151 try | |
152 { | |
153 if (changeType == OrthancPluginChangeType_NewInstance && | |
154 resourceType == OrthancPluginResourceType_Instance) | |
155 { | |
75
e15a59a4b4d4
Fix possible deadlock with other plugins in OnChangeCallback()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
74
diff
changeset
|
156 cache_->SignalNewInstance(resourceId); |
0 | 157 } |
158 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
159 return RETURN_SUCCESS; |
0 | 160 } |
161 catch (std::runtime_error& e) | |
162 { | |
163 OrthancPluginLogError(context_, e.what()); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
164 return RETURN_SUCCESS; // Ignore error |
0 | 165 } |
166 } | |
167 | |
168 | |
169 | |
170 template <enum OrthancPlugins::CacheBundle bundle> | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
171 static RETURN_TYPE ServeCache(OrthancPluginRestOutput* output, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
172 const char* url, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
173 const OrthancPluginHttpRequest* request) |
0 | 174 { |
175 try | |
176 { | |
177 if (request->method != OrthancPluginHttpMethod_Get) | |
178 { | |
179 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
180 return RETURN_SUCCESS; |
0 | 181 } |
182 | |
183 const std::string id = request->groups[0]; | |
184 std::string content; | |
185 | |
186 if (cache_->GetScheduler().Access(content, bundle, id)) | |
187 { | |
188 OrthancPluginAnswerBuffer(context_, output, content.c_str(), content.size(), "application/json"); | |
189 } | |
190 else | |
191 { | |
192 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
193 } | |
194 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
195 return RETURN_SUCCESS; |
0 | 196 } |
197 catch (Orthanc::OrthancException& e) | |
198 { | |
199 OrthancPluginLogError(context_, e.What()); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
200 return RETURN_FAILURE; |
0 | 201 } |
202 catch (std::runtime_error& e) | |
203 { | |
204 OrthancPluginLogError(context_, e.what()); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
205 return RETURN_FAILURE; |
0 | 206 } |
207 catch (boost::bad_lexical_cast&) | |
208 { | |
209 OrthancPluginLogError(context_, "Bad lexical cast"); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
210 return RETURN_FAILURE; |
0 | 211 } |
212 } | |
213 | |
214 | |
215 | |
216 | |
217 #if ORTHANC_STANDALONE == 0 | |
218 static int32_t ServeWebViewer(OrthancPluginRestOutput* output, | |
219 const char* url, | |
220 const OrthancPluginHttpRequest* request) | |
221 { | |
222 if (request->method != OrthancPluginHttpMethod_Get) | |
223 { | |
224 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
225 return 0; | |
226 } | |
227 | |
228 const std::string path = std::string(WEB_VIEWER_PATH) + std::string(request->groups[0]); | |
229 const char* mime = OrthancPlugins::GetMimeType(path); | |
230 | |
231 std::string s; | |
232 if (OrthancPlugins::ReadFile(s, path)) | |
233 { | |
234 const char* resource = s.size() ? s.c_str() : NULL; | |
235 OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime); | |
236 } | |
237 else | |
238 { | |
239 std::string s = "Inexistent file in served folder: " + path; | |
240 OrthancPluginLogError(context_, s.c_str()); | |
241 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
242 } | |
243 | |
244 return 0; | |
245 } | |
246 #endif | |
247 | |
248 | |
249 | |
31 | 250 template <enum Orthanc::EmbeddedResources::DirectoryResourceId folder> |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
251 static RETURN_TYPE ServeEmbeddedFolder(OrthancPluginRestOutput* output, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
252 const char* url, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
253 const OrthancPluginHttpRequest* request) |
0 | 254 { |
255 if (request->method != OrthancPluginHttpMethod_Get) | |
256 { | |
257 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
258 return RETURN_SUCCESS; |
0 | 259 } |
260 | |
261 std::string path = "/" + std::string(request->groups[0]); | |
262 const char* mime = OrthancPlugins::GetMimeType(path); | |
263 | |
264 try | |
265 { | |
266 std::string s; | |
31 | 267 Orthanc::EmbeddedResources::GetDirectoryResource(s, folder, path.c_str()); |
0 | 268 |
269 const char* resource = s.size() ? s.c_str() : NULL; | |
270 OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime); | |
271 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
272 return RETURN_SUCCESS; |
0 | 273 } |
274 catch (std::runtime_error&) | |
275 { | |
276 std::string s = "Unknown static resource in plugin: " + std::string(request->groups[0]); | |
277 OrthancPluginLogError(context_, s.c_str()); | |
278 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
279 return RETURN_SUCCESS; |
0 | 280 } |
281 } | |
282 | |
283 | |
284 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
285 static RETURN_TYPE IsStableSeries(OrthancPluginRestOutput* output, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
286 const char* url, |
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
287 const OrthancPluginHttpRequest* request) |
19 | 288 { |
289 try | |
290 { | |
291 if (request->method != OrthancPluginHttpMethod_Get) | |
292 { | |
293 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
294 return RETURN_SUCCESS; |
19 | 295 } |
296 | |
297 const std::string id = request->groups[0]; | |
298 Json::Value series; | |
299 | |
300 if (OrthancPlugins::GetJsonFromOrthanc(series, context_, "/series/" + id) && | |
301 series.type() == Json::objectValue) | |
302 { | |
303 bool value = (series["IsStable"].asBool() || | |
304 series["Status"].asString() == "Complete"); | |
305 std::string answer = value ? "true" : "false"; | |
306 OrthancPluginAnswerBuffer(context_, output, answer.c_str(), answer.size(), "application/json"); | |
307 } | |
308 else | |
309 { | |
310 OrthancPluginSendHttpStatusCode(context_, output, 404); | |
311 } | |
312 | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
313 return RETURN_SUCCESS; |
19 | 314 } |
315 catch (Orthanc::OrthancException& e) | |
316 { | |
317 OrthancPluginLogError(context_, e.What()); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
318 return RETURN_FAILURE; |
19 | 319 } |
320 catch (std::runtime_error& e) | |
321 { | |
322 OrthancPluginLogError(context_, e.what()); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
323 return RETURN_FAILURE; |
19 | 324 } |
325 catch (boost::bad_lexical_cast&) | |
326 { | |
327 OrthancPluginLogError(context_, "Bad lexical cast"); | |
74
ab5218c18b7a
compatibility with forthcoming sdk 0.9.5
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
58
diff
changeset
|
328 return RETURN_FAILURE; |
19 | 329 } |
330 } | |
331 | |
0 | 332 |
333 extern "C" | |
334 { | |
335 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
336 { | |
337 using namespace OrthancPlugins; | |
338 | |
339 context_ = context; | |
340 OrthancPluginLogWarning(context_, "Initializing the Web viewer"); | |
341 | |
342 | |
343 /* Check the version of the Orthanc core */ | |
344 if (OrthancPluginCheckVersion(context_) == 0) | |
345 { | |
346 char info[1024]; | |
347 sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", | |
348 context_->orthancVersion, | |
349 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, | |
350 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, | |
351 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); | |
352 OrthancPluginLogError(context_, info); | |
353 return -1; | |
354 } | |
355 | |
356 OrthancPluginSetDescription(context_, "Provides a Web viewer of DICOM series within Orthanc."); | |
357 | |
358 | |
359 /* By default, use half of the available processing cores for the decoding of DICOM images */ | |
360 int decodingThreads = boost::thread::hardware_concurrency() / 2; | |
361 if (decodingThreads == 0) | |
362 { | |
363 decodingThreads = 1; | |
364 } | |
365 | |
366 | |
367 try | |
368 { | |
369 /* Read the configuration of the Web viewer */ | |
370 Json::Value configuration; | |
371 if (!ReadConfiguration(configuration, context)) | |
372 { | |
373 OrthancPluginLogError(context_, "Unable to read the configuration file of Orthanc"); | |
374 return -1; | |
375 } | |
376 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
377 // 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
|
378 // "StorageDirectory" of Orthanc |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
379 boost::filesystem::path cachePath = GetStringValue(configuration, "StorageDirectory", "."); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
380 cachePath /= "WebViewerCache"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
381 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
|
382 |
0 | 383 if (configuration.isMember("WebViewer")) |
384 { | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
385 std::string key = "CachePath"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
386 if (!configuration["WebViewer"].isMember(key)) |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
387 { |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
388 // 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
|
389 key = "Cache"; |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
390 } |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
391 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
392 cachePath = GetStringValue(configuration["WebViewer"], key, cachePath.string()); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
393 cacheSize = GetIntegerValue(configuration["WebViewer"], "CacheSize", cacheSize); |
0 | 394 decodingThreads = GetIntegerValue(configuration["WebViewer"], "Threads", decodingThreads); |
395 } | |
396 | |
397 std::string message = ("Web viewer using " + boost::lexical_cast<std::string>(decodingThreads) + | |
398 " threads for the decoding of the DICOM images"); | |
399 OrthancPluginLogWarning(context_, message.c_str()); | |
400 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
401 if (decodingThreads <= 0 || |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
402 cacheSize <= 0) |
0 | 403 { |
404 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
405 } | |
406 | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
407 message = "Storing the cache of the Web viewer in folder: " + cachePath.string(); |
0 | 408 OrthancPluginLogWarning(context_, message.c_str()); |
409 | |
410 | |
411 /* Create the cache */ | |
4
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
412 cache_ = new CacheContext(cachePath.string()); |
0 | 413 cache_->GetScheduler().RegisterPolicy(new ViewerPrefetchPolicy(context_)); |
414 cache_->GetScheduler().Register(CacheBundle_SeriesInformation, | |
415 new SeriesInformationAdapter(context_, cache_->GetScheduler()), 1); | |
416 cache_->GetScheduler().Register(CacheBundle_InstanceInformation, | |
417 new InstanceInformationAdapter(context_), 1); | |
418 cache_->GetScheduler().Register(CacheBundle_DecodedImage, | |
419 new DecodedImageAdapter(context_), decodingThreads); | |
4
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 /* Set the quotas */ |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
423 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
|
424 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
|
425 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
426 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
|
427 OrthancPluginLogWarning(context_, message.c_str()); |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
428 |
ecefd45026bf
configuration of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
429 cache_->GetScheduler().SetQuota(CacheBundle_DecodedImage, 0, static_cast<uint64_t>(cacheSize) * 1024 * 1024); |
0 | 430 } |
431 catch (std::runtime_error& e) | |
432 { | |
433 OrthancPluginLogError(context_, e.what()); | |
434 return -1; | |
435 } | |
436 catch (Orthanc::OrthancException& e) | |
437 { | |
438 OrthancPluginLogError(context_, e.What()); | |
439 return -1; | |
440 } | |
441 | |
442 | |
443 /* Install the callbacks */ | |
444 OrthancPluginRegisterRestCallback(context_, "/web-viewer/series/(.*)", ServeCache<CacheBundle_SeriesInformation>); | |
19 | 445 OrthancPluginRegisterRestCallback(context_, "/web-viewer/is-stable-series/(.*)", IsStableSeries); |
0 | 446 OrthancPluginRegisterRestCallback(context_, "/web-viewer/instances/(.*)", ServeCache<CacheBundle_DecodedImage>); |
31 | 447 OrthancPluginRegisterRestCallback(context, "/web-viewer/libs/(.*)", ServeEmbeddedFolder<Orthanc::EmbeddedResources::JAVASCRIPT_LIBS>); |
0 | 448 |
449 #if ORTHANC_STANDALONE == 1 | |
31 | 450 OrthancPluginRegisterRestCallback(context, "/web-viewer/app/(.*)", ServeEmbeddedFolder<Orthanc::EmbeddedResources::WEB_VIEWER>); |
0 | 451 #else |
452 OrthancPluginRegisterRestCallback(context, "/web-viewer/app/(.*)", ServeWebViewer); | |
453 #endif | |
454 | |
455 OrthancPluginRegisterOnChangeCallback(context, OnChangeCallback); | |
456 | |
457 | |
458 /* Extend the default Orthanc Explorer with custom JavaScript */ | |
459 std::string explorer; | |
31 | 460 Orthanc::EmbeddedResources::GetFileResource(explorer, Orthanc::EmbeddedResources::ORTHANC_EXPLORER); |
0 | 461 OrthancPluginExtendOrthancExplorer(context_, explorer.c_str()); |
462 | |
463 return 0; | |
464 } | |
465 | |
466 | |
467 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
468 { | |
469 OrthancPluginLogWarning(context_, "Finalizing the Web viewer"); | |
470 | |
471 if (cache_ != NULL) | |
472 { | |
473 delete cache_; | |
474 cache_ = NULL; | |
475 } | |
476 } | |
477 | |
478 | |
479 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
480 { | |
481 return "web-viewer"; | |
482 } | |
483 | |
484 | |
485 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
486 { | |
12 | 487 return ORTHANC_WEBVIEWER_VERSION; |
0 | 488 } |
489 } |