Mercurial > hg > orthanc-transfers
annotate Plugin/Plugin.cpp @ 78:0898578d5708 OrthancTransfers-1.3 tip
closing OrthancTransfers-1.3
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 30 May 2024 22:45:33 +0200 |
parents | f4e828607f02 |
children | b09adb6aa199 |
rev | line source |
---|---|
0 | 1 /** |
2 * Transfers accelerator plugin for Orthanc | |
33
44a0430d7899
upgrade to year 2021
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
31
diff
changeset
|
3 * Copyright (C) 2018-2021 Osimis S.A., Belgium |
0 | 4 * |
5 * This program is free software: you can redistribute it and/or | |
6 * modify it under the terms of the GNU Affero General Public License | |
7 * as published by the Free Software Foundation, either version 3 of | |
8 * the License, or (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, but | |
11 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Affero General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Affero General Public License | |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 **/ | |
18 | |
19 #include "PluginContext.h" | |
20 #include "../Framework/HttpQueries/DetectTransferPlugin.h" | |
21 #include "../Framework/PullMode/PullJob.h" | |
22 #include "../Framework/PushMode/PushJob.h" | |
23 #include "../Framework/TransferScheduler.h" | |
24 | |
25 #include <EmbeddedResources.h> | |
26 | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
21
diff
changeset
|
27 #include <Compatibility.h> // For std::unique_ptr |
20 | 28 #include <ChunkedBuffer.h> |
29 #include <Compression/GzipCompressor.h> | |
30 #include <Logging.h> | |
31
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
31 #include <Toolbox.h> |
0 | 32 |
33 | |
34 static bool DisplayPerformanceWarning() | |
35 { | |
36 (void) DisplayPerformanceWarning; // Disable warning about unused function | |
37 LOG(WARNING) << "Performance warning in transfers accelerator: " | |
38 << "Non-release build, runtime debug assertions are turned on"; | |
39 return true; | |
40 } | |
41 | |
42 | |
43 static size_t ReadSizeArgument(const OrthancPluginHttpRequest* request, | |
44 uint32_t index) | |
45 { | |
46 std::string value(request->getValues[index]); | |
47 | |
48 try | |
49 { | |
50 int tmp = boost::lexical_cast<int>(value); | |
51 if (tmp >= 0) | |
52 { | |
53 return static_cast<size_t>(tmp); | |
54 } | |
55 } | |
56 catch (boost::bad_lexical_cast&) | |
57 { | |
58 } | |
59 | |
60 LOG(ERROR) << "The \"" << request->getKeys[index] | |
61 << "\" GET argument must be a positive integer: " << value; | |
62 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); | |
63 } | |
64 | |
65 | |
66 void ServeChunks(OrthancPluginRestOutput* output, | |
67 const char* url, | |
68 const OrthancPluginHttpRequest* request) | |
69 { | |
70 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
71 | |
72 if (request->method != OrthancPluginHttpMethod_Get) | |
73 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
74 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET"); |
0 | 75 return; |
76 } | |
77 | |
78 assert(request->groupsCount == 1); | |
79 | |
80 std::vector<std::string> instances; | |
81 Orthanc::Toolbox::TokenizeString(instances, std::string(request->groups[0]), '.'); | |
82 | |
83 size_t offset = 0; | |
84 size_t requestedSize = 0; | |
85 OrthancPlugins::BucketCompression compression = OrthancPlugins::BucketCompression_None; | |
86 | |
87 for (uint32_t i = 0; i < request->getCount; i++) | |
88 { | |
89 std::string key(request->getKeys[i]); | |
90 | |
91 if (key == "offset") | |
92 { | |
93 offset = ReadSizeArgument(request, i); | |
94 } | |
95 else if (key == "size") | |
96 { | |
97 requestedSize = ReadSizeArgument(request, i); | |
98 } | |
99 else if (key == "compression") | |
100 { | |
101 compression = OrthancPlugins::StringToBucketCompression(request->getValues[i]); | |
102 } | |
103 else | |
104 { | |
105 LOG(INFO) << "Ignored GET argument: " << key; | |
106 } | |
107 } | |
108 | |
109 | |
110 // Limit the number of clients | |
111 Orthanc::Semaphore::Locker lock(context.GetSemaphore()); | |
112 | |
113 Orthanc::ChunkedBuffer buffer; | |
114 | |
115 for (size_t i = 0; i < instances.size() && (requestedSize == 0 || | |
116 buffer.GetNumBytes() < requestedSize); i++) | |
117 { | |
118 size_t instanceSize; | |
119 std::string md5; // Ignored | |
120 context.GetCache().GetInstanceInfo(instanceSize, md5, instances[i]); | |
121 | |
122 if (offset >= instanceSize) | |
123 { | |
124 offset -= instanceSize; | |
125 } | |
126 else | |
127 { | |
128 size_t toRead; | |
129 | |
130 if (requestedSize == 0) | |
131 { | |
132 toRead = instanceSize - offset; | |
133 } | |
134 else | |
135 { | |
136 toRead = requestedSize - buffer.GetNumBytes(); | |
137 | |
138 if (toRead > instanceSize - offset) | |
139 { | |
140 toRead = instanceSize - offset; | |
141 } | |
142 } | |
143 | |
144 std::string chunk; | |
145 std::string md5; // Ignored | |
146 context.GetCache().GetChunk(chunk, md5, instances[i], offset, toRead); | |
147 | |
148 buffer.AddChunk(chunk); | |
149 offset = 0; | |
150 | |
151 assert(requestedSize == 0 || | |
152 buffer.GetNumBytes() <= requestedSize); | |
153 } | |
154 } | |
155 | |
156 std::string chunk; | |
157 buffer.Flatten(chunk); | |
158 | |
159 | |
160 switch (compression) | |
161 { | |
162 case OrthancPlugins::BucketCompression_None: | |
163 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
164 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, chunk.c_str(), |
0 | 165 chunk.size(), "application/octet-stream"); |
166 break; | |
167 } | |
168 | |
169 case OrthancPlugins::BucketCompression_Gzip: | |
170 { | |
171 std::string compressed; | |
172 Orthanc::GzipCompressor gzip; | |
173 //gzip.SetCompressionLevel(9); | |
174 Orthanc::IBufferCompressor::Compress(compressed, gzip, chunk); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
175 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, compressed.c_str(), |
0 | 176 compressed.size(), "application/gzip"); |
177 break; | |
178 } | |
179 | |
180 default: | |
181 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
182 } | |
183 } | |
184 | |
185 | |
186 | |
187 static bool ParsePostBody(Json::Value& body, | |
188 OrthancPluginRestOutput* output, | |
189 const OrthancPluginHttpRequest* request) | |
190 { | |
191 if (request->method != OrthancPluginHttpMethod_Post) | |
192 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
193 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "POST"); |
0 | 194 return false; |
195 } | |
31
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
196 else if (Orthanc::Toolbox::ReadJson(body, request->body, request->bodySize)) |
0 | 197 { |
198 return true; | |
199 } | |
200 else | |
201 { | |
202 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
203 } | |
204 } | |
205 | |
206 | |
207 void LookupInstances(OrthancPluginRestOutput* output, | |
208 const char* url, | |
209 const OrthancPluginHttpRequest* request) | |
210 { | |
211 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
212 | |
213 Json::Value resources; | |
214 if (!ParsePostBody(resources, output, request)) | |
215 { | |
216 return; | |
217 } | |
218 | |
219 OrthancPlugins::TransferScheduler scheduler; | |
220 scheduler.ParseListOfResources(context.GetCache(), resources); | |
221 | |
222 Json::Value answer = Json::objectValue; | |
223 answer[KEY_INSTANCES] = Json::arrayValue; | |
224 answer[KEY_ORIGINATOR_UUID] = context.GetPluginUuid(); | |
225 answer["CountInstances"] = static_cast<uint32_t>(scheduler.GetInstancesCount()); | |
226 answer["TotalSize"] = boost::lexical_cast<std::string>(scheduler.GetTotalSize()); | |
227 answer["TotalSizeMB"] = OrthancPlugins::ConvertToMegabytes(scheduler.GetTotalSize()); | |
228 | |
229 std::vector<OrthancPlugins::DicomInstanceInfo> instances; | |
230 scheduler.ListInstances(instances); | |
231 | |
232 for (size_t i = 0; i < instances.size(); i++) | |
233 { | |
234 Json::Value instance; | |
235 instances[i].Serialize(instance); | |
236 answer[KEY_INSTANCES].append(instance); | |
237 } | |
238 | |
31
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
239 std::string s; |
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
240 Orthanc::Toolbox::WriteFastJson(s, answer); |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
241 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 242 } |
243 | |
244 | |
245 | |
246 static void SubmitJob(OrthancPluginRestOutput* output, | |
247 OrthancPlugins::OrthancJob* job, | |
248 int priority) | |
249 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
250 std::string id = OrthancPlugins::OrthancJob::Submit(job, priority); |
0 | 251 |
252 Json::Value result = Json::objectValue; | |
253 result[KEY_ID] = id; | |
254 result[KEY_PATH] = std::string(URI_JOBS) + "/" + id; | |
255 | |
256 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
257 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 258 } |
259 | |
260 | |
261 | |
262 void SchedulePull(OrthancPluginRestOutput* output, | |
263 const char* url, | |
264 const OrthancPluginHttpRequest* request) | |
265 { | |
266 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
267 | |
268 Json::Value body; | |
269 if (!ParsePostBody(body, output, request)) | |
270 { | |
271 return; | |
272 } | |
273 | |
274 OrthancPlugins::TransferQuery query(body); | |
275 | |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
276 SubmitJob(output, new OrthancPlugins::PullJob(query, context.GetThreadsCount(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
277 context.GetTargetBucketSize(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
278 context.GetMaxHttpRetries()), |
0 | 279 query.GetPriority()); |
280 } | |
281 | |
282 | |
283 | |
284 void CreatePush(OrthancPluginRestOutput* output, | |
285 const char* url, | |
286 const OrthancPluginHttpRequest* request) | |
287 { | |
288 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
289 | |
290 Json::Value query; | |
291 if (!ParsePostBody(query, output, request)) | |
292 { | |
293 return; | |
294 } | |
295 | |
296 if (query.type() != Json::objectValue || | |
297 !query.isMember(KEY_BUCKETS) || | |
298 !query.isMember(KEY_COMPRESSION) || | |
299 !query.isMember(KEY_INSTANCES) || | |
300 query[KEY_BUCKETS].type() != Json::arrayValue || | |
301 query[KEY_COMPRESSION].type() != Json::stringValue || | |
302 query[KEY_INSTANCES].type() != Json::arrayValue) | |
303 { | |
304 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
305 } | |
306 | |
307 std::vector<OrthancPlugins::DicomInstanceInfo> instances; | |
308 instances.reserve(query[KEY_INSTANCES].size()); | |
309 | |
310 for (Json::Value::ArrayIndex i = 0; i < query[KEY_INSTANCES].size(); i++) | |
311 { | |
312 OrthancPlugins::DicomInstanceInfo instance(query[KEY_INSTANCES][i]); | |
313 instances.push_back(instance); | |
314 } | |
315 | |
316 std::vector<OrthancPlugins::TransferBucket> buckets; | |
317 buckets.reserve(query[KEY_BUCKETS].size()); | |
318 | |
319 for (Json::Value::ArrayIndex i = 0; i < query[KEY_BUCKETS].size(); i++) | |
320 { | |
321 OrthancPlugins::TransferBucket bucket(query[KEY_BUCKETS][i]); | |
322 buckets.push_back(bucket); | |
323 } | |
324 | |
325 OrthancPlugins::BucketCompression compression = | |
326 OrthancPlugins::StringToBucketCompression(query[KEY_COMPRESSION].asString()); | |
327 | |
328 std::string id = context.GetActivePushTransactions().CreateTransaction | |
329 (instances, buckets, compression); | |
330 | |
331 Json::Value result = Json::objectValue; | |
332 result[KEY_ID] = id; | |
333 result[KEY_PATH] = std::string(URI_PUSH) + "/" + id; | |
334 | |
335 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
336 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 337 } |
338 | |
339 | |
340 void StorePush(OrthancPluginRestOutput* output, | |
341 const char* url, | |
342 const OrthancPluginHttpRequest* request) | |
343 { | |
344 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
345 | |
346 if (request->method != OrthancPluginHttpMethod_Put) | |
347 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
348 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "PUT"); |
0 | 349 return; |
350 } | |
351 | |
352 assert(request->groupsCount == 2); | |
353 std::string transaction(request->groups[0]); | |
354 std::string chunk(request->groups[1]); | |
355 | |
356 size_t chunkIndex; | |
357 | |
358 try | |
359 { | |
360 chunkIndex = boost::lexical_cast<size_t>(chunk); | |
361 } | |
362 catch (boost::bad_lexical_cast&) | |
363 { | |
364 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); | |
365 } | |
366 | |
367 context.GetActivePushTransactions().Store | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
368 (transaction, chunkIndex, request->body, request->bodySize); |
0 | 369 |
370 std::string s = "{}"; | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
371 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 372 } |
373 | |
374 | |
375 void CommitPush(OrthancPluginRestOutput* output, | |
376 const char* url, | |
377 const OrthancPluginHttpRequest* request) | |
378 { | |
379 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
380 | |
381 if (request->method != OrthancPluginHttpMethod_Post) | |
382 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
383 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "POST"); |
0 | 384 return; |
385 } | |
386 | |
387 assert(request->groupsCount == 1); | |
388 std::string transaction(request->groups[0]); | |
389 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
390 context.GetActivePushTransactions().Commit(transaction); |
0 | 391 |
392 std::string s = "{}"; | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
393 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 394 } |
395 | |
396 | |
397 void DiscardPush(OrthancPluginRestOutput* output, | |
398 const char* url, | |
399 const OrthancPluginHttpRequest* request) | |
400 { | |
401 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
402 | |
403 if (request->method != OrthancPluginHttpMethod_Delete) | |
404 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
405 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "DELETE"); |
0 | 406 return; |
407 } | |
408 | |
409 assert(request->groupsCount == 1); | |
410 std::string transaction(request->groups[0]); | |
411 | |
412 context. | |
413 GetActivePushTransactions().Discard(transaction); | |
414 | |
415 std::string s = "{}"; | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
416 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 417 } |
418 | |
419 | |
420 | |
421 void ScheduleSend(OrthancPluginRestOutput* output, | |
422 const char* url, | |
423 const OrthancPluginHttpRequest* request) | |
424 { | |
425 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
426 | |
427 Json::Value body; | |
428 if (!ParsePostBody(body, output, request)) | |
429 { | |
430 return; | |
431 } | |
432 | |
433 OrthancPlugins::TransferQuery query(body); | |
434 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
435 OrthancPlugins::OrthancPeers peers; |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
436 |
0 | 437 std::string remoteSelf; // For pull mode |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
438 bool pullMode = peers.LookupUserProperty(remoteSelf, query.GetPeer(), KEY_REMOTE_SELF); |
0 | 439 |
440 LOG(INFO) << "Sending resources to peer \"" << query.GetPeer() << "\" using " | |
441 << (pullMode ? "pull" : "push") << " mode"; | |
442 | |
443 if (pullMode) | |
444 { | |
445 Json::Value lookup = Json::objectValue; | |
446 lookup[KEY_RESOURCES] = query.GetResources(); | |
447 lookup[KEY_COMPRESSION] = OrthancPlugins::EnumerationToString(query.GetCompression()); | |
448 lookup[KEY_ORIGINATOR_UUID] = context.GetPluginUuid(); | |
449 lookup[KEY_PEER] = remoteSelf; | |
450 | |
31
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
451 std::string s; |
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
452 Orthanc::Toolbox::WriteFastJson(s, lookup); |
0 | 453 |
454 Json::Value answer; | |
44
f4e828607f02
Added 'SenderTransferID' option that is added as an HTTP header in outgoing requests in PushMode
Alain Mazy <am@osimis.io>
parents:
33
diff
changeset
|
455 std::map<std::string, std::string> headers; |
f4e828607f02
Added 'SenderTransferID' option that is added as an HTTP header in outgoing requests in PushMode
Alain Mazy <am@osimis.io>
parents:
33
diff
changeset
|
456 query.GetHttpHeaders(headers); |
f4e828607f02
Added 'SenderTransferID' option that is added as an HTTP header in outgoing requests in PushMode
Alain Mazy <am@osimis.io>
parents:
33
diff
changeset
|
457 |
f4e828607f02
Added 'SenderTransferID' option that is added as an HTTP header in outgoing requests in PushMode
Alain Mazy <am@osimis.io>
parents:
33
diff
changeset
|
458 if (DoPostPeer(answer, peers, query.GetPeer(), URI_PULL, s, context.GetMaxHttpRetries(), headers) && |
0 | 459 answer.type() == Json::objectValue && |
460 answer.isMember(KEY_ID) && | |
461 answer.isMember(KEY_PATH) && | |
462 answer[KEY_ID].type() == Json::stringValue && | |
463 answer[KEY_PATH].type() == Json::stringValue) | |
464 { | |
465 const std::string url = peers.GetPeerUrl(query.GetPeer()); | |
466 | |
467 Json::Value result = Json::objectValue; | |
468 result[KEY_PEER] = query.GetPeer(); | |
469 result[KEY_REMOTE_JOB] = answer[KEY_ID].asString(); | |
470 result[KEY_URL] = url + answer[KEY_PATH].asString(); | |
471 | |
472 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
473 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 474 } |
475 else | |
476 { | |
477 LOG(ERROR) << "Cannot trigger send DICOM instances using pull mode to peer: " << query.GetPeer() | |
478 << " (check out remote logs, and that transfer plugin is installed)"; | |
479 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
480 } | |
481 } | |
482 else | |
483 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
484 SubmitJob(output, new OrthancPlugins::PushJob(query, context.GetCache(), |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
485 context.GetThreadsCount(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
486 context.GetTargetBucketSize(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
487 context.GetMaxHttpRetries()), |
0 | 488 query.GetPriority()); |
489 } | |
490 } | |
491 | |
492 | |
493 OrthancPluginJob* Unserializer(const char* jobType, | |
494 const char* serialized) | |
495 { | |
496 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
497 | |
498 if (jobType == NULL || | |
499 serialized == NULL) | |
500 { | |
501 return NULL; | |
502 } | |
503 | |
504 std::string type(jobType); | |
505 | |
506 if (type != JOB_TYPE_PULL && | |
507 type != JOB_TYPE_PUSH) | |
508 { | |
509 return NULL; | |
510 } | |
511 | |
512 try | |
513 { | |
514 std::string tmp(serialized); | |
515 | |
516 Json::Value source; | |
31
cfeda58d0c8e
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
29
diff
changeset
|
517 if (Orthanc::Toolbox::ReadJson(source, tmp)) |
0 | 518 { |
519 OrthancPlugins::TransferQuery query(source); | |
520 | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
21
diff
changeset
|
521 std::unique_ptr<OrthancPlugins::OrthancJob> job; |
0 | 522 |
523 if (type == JOB_TYPE_PULL) | |
524 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
525 job.reset(new OrthancPlugins::PullJob(query, |
0 | 526 context.GetThreadsCount(), |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
527 context.GetTargetBucketSize(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
528 context.GetMaxHttpRetries())); |
0 | 529 } |
530 else if (type == JOB_TYPE_PUSH) | |
531 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
532 job.reset(new OrthancPlugins::PushJob(query, |
0 | 533 context.GetCache(), |
534 context.GetThreadsCount(), | |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
535 context.GetTargetBucketSize(), |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
536 context.GetMaxHttpRetries())); |
0 | 537 } |
538 | |
539 if (job.get() == NULL) | |
540 { | |
541 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
542 } | |
543 else | |
544 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
545 return OrthancPlugins::OrthancJob::Create(job.release()); |
0 | 546 } |
547 } | |
548 else | |
549 { | |
550 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
551 } | |
552 } | |
553 catch (Orthanc::OrthancException& e) | |
554 { | |
555 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin: " | |
556 << e.What(); | |
557 return NULL; | |
558 } | |
559 catch (...) | |
560 { | |
561 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin"; | |
562 return NULL; | |
563 } | |
564 } | |
565 | |
566 | |
567 | |
568 void ServePeers(OrthancPluginRestOutput* output, | |
569 const char* url, | |
570 const OrthancPluginHttpRequest* request) | |
571 { | |
572 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
573 | |
574 if (request->method != OrthancPluginHttpMethod_Get) | |
575 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
576 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET"); |
0 | 577 return; |
578 } | |
579 | |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
580 OrthancPlugins::DetectTransferPlugin::Result detection; |
0 | 581 OrthancPlugins::DetectTransferPlugin::Apply |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
582 (detection, context.GetThreadsCount(), 2 /* timeout */); |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
583 |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
584 Json::Value result = Json::objectValue; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
585 |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
586 OrthancPlugins::OrthancPeers peers; |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
587 |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
588 for (OrthancPlugins::DetectTransferPlugin::Result::const_iterator |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
589 it = detection.begin(); it != detection.end(); ++it) |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
590 { |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
591 if (it->second) |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
592 { |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
593 std::string remoteSelf; |
0 | 594 |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
595 if (peers.LookupUserProperty(remoteSelf, it->first, KEY_REMOTE_SELF)) |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
596 { |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
597 result[it->first] = "bidirectional"; |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
598 } |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
599 else |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
600 { |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
601 result[it->first] = "installed"; |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
602 } |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
603 } |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
604 else |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
605 { |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
606 result[it->first] = "disabled"; |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
607 } |
0 | 608 } |
609 | |
610 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
611 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 612 } |
613 | |
614 | |
615 | |
616 extern "C" | |
617 { | |
618 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
619 { | |
29
a0af5a8182a8
sync, removed old patch for Orthanc framework 1.5.6
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
620 #if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 7, 2) |
20 | 621 Orthanc::Logging::InitializePluginContext(context); |
21
7c8dfa752242
improved Orthanc::Logging::Initialize()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
20
diff
changeset
|
622 #else |
7c8dfa752242
improved Orthanc::Logging::Initialize()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
20
diff
changeset
|
623 Orthanc::Logging::Initialize(context); |
7c8dfa752242
improved Orthanc::Logging::Initialize()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
20
diff
changeset
|
624 #endif |
7c8dfa752242
improved Orthanc::Logging::Initialize()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
20
diff
changeset
|
625 |
0 | 626 assert(DisplayPerformanceWarning()); |
627 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
628 OrthancPlugins::SetGlobalContext(context); |
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
629 |
0 | 630 /* Check the version of the Orthanc core */ |
631 if (OrthancPluginCheckVersion(context) == 0) | |
632 { | |
633 LOG(ERROR) << "Your version of Orthanc (" | |
634 << context->orthancVersion << ") must be above " | |
635 << ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER << "." | |
636 << ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER << "." | |
637 << ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER | |
638 << " to run this plugin"; | |
639 return -1; | |
640 } | |
641 | |
642 OrthancPluginSetDescription(context, "Accelerates transfers and provides " | |
643 "storage commitment between Orthanc peers"); | |
644 | |
645 try | |
646 { | |
647 size_t threadsCount = 4; | |
648 size_t targetBucketSize = 4096; // In KB | |
649 size_t maxPushTransactions = 4; | |
650 size_t memoryCacheSize = 512; // In MB | |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
651 unsigned int maxHttpRetries = 0; |
0 | 652 |
653 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
654 OrthancPlugins::OrthancConfiguration config; |
0 | 655 |
656 if (config.IsSection(KEY_PLUGIN_CONFIGURATION)) | |
657 { | |
658 OrthancPlugins::OrthancConfiguration plugin; | |
659 config.GetSection(plugin, KEY_PLUGIN_CONFIGURATION); | |
660 | |
661 threadsCount = plugin.GetUnsignedIntegerValue("Threads", threadsCount); | |
662 targetBucketSize = plugin.GetUnsignedIntegerValue("BucketSize", targetBucketSize); | |
663 memoryCacheSize = plugin.GetUnsignedIntegerValue("CacheSize", memoryCacheSize); | |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
664 maxPushTransactions = plugin.GetUnsignedIntegerValue("MaxPushTransactions", maxPushTransactions); |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
665 maxHttpRetries = plugin.GetUnsignedIntegerValue("MaxHttpRetries", maxHttpRetries); |
0 | 666 } |
667 } | |
668 | |
10
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
669 OrthancPlugins::PluginContext::Initialize(threadsCount, targetBucketSize * KB, maxPushTransactions, |
c9e28e31262e
new option: MaxHttpRetries
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
9
diff
changeset
|
670 memoryCacheSize * MB, maxHttpRetries); |
0 | 671 |
672 OrthancPlugins::RegisterRestCallback<ServeChunks> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
673 (std::string(URI_CHUNKS) + "/([.0-9a-f-]+)", true); |
0 | 674 |
675 OrthancPlugins::RegisterRestCallback<LookupInstances> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
676 (URI_LOOKUP, true); |
0 | 677 |
678 OrthancPlugins::RegisterRestCallback<SchedulePull> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
679 (URI_PULL, true); |
0 | 680 |
681 OrthancPlugins::RegisterRestCallback<ScheduleSend> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
682 (URI_SEND, true); |
0 | 683 |
684 OrthancPlugins::RegisterRestCallback<ServePeers> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
685 (URI_PEERS, true); |
0 | 686 |
687 if (maxPushTransactions != 0) | |
688 { | |
689 // If no push transaction is allowed, their URIs are disabled | |
690 OrthancPlugins::RegisterRestCallback<CreatePush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
691 (URI_PUSH, true); |
0 | 692 |
693 OrthancPlugins::RegisterRestCallback<StorePush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
694 (std::string(URI_PUSH) + "/([.0-9a-f-]+)/([0-9]+)", true); |
0 | 695 |
696 OrthancPlugins::RegisterRestCallback<CommitPush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
697 (std::string(URI_PUSH) + "/([.0-9a-f-]+)/commit", true); |
0 | 698 |
699 OrthancPlugins::RegisterRestCallback<DiscardPush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
700 (std::string(URI_PUSH) + "/([.0-9a-f-]+)", true); |
0 | 701 } |
702 | |
703 OrthancPluginRegisterJobsUnserializer(context, Unserializer); | |
704 | |
705 /* Extend the default Orthanc Explorer with custom JavaScript */ | |
706 std::string explorer; | |
707 Orthanc::EmbeddedResources::GetFileResource | |
708 (explorer, Orthanc::EmbeddedResources::ORTHANC_EXPLORER); | |
709 OrthancPluginExtendOrthancExplorer(context, explorer.c_str()); | |
710 } | |
711 catch (Orthanc::OrthancException& e) | |
712 { | |
713 LOG(ERROR) << "Cannot initialize transfers accelerator plugin: " << e.What(); | |
714 return -1; | |
715 } | |
716 | |
717 return 0; | |
718 } | |
719 | |
720 | |
721 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
722 { | |
723 LOG(WARNING) << "Transfers accelerator plugin is finalizing"; | |
724 | |
725 try | |
726 { | |
727 OrthancPlugins::PluginContext::Finalize(); | |
728 } | |
729 catch (Orthanc::OrthancException& e) | |
730 { | |
731 LOG(ERROR) << "Error while finalizing the transfers accelerator plugin: " << e.What(); | |
732 } | |
733 } | |
734 | |
735 | |
736 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
737 { | |
738 return PLUGIN_NAME; | |
739 } | |
740 | |
741 | |
742 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
743 { | |
744 return ORTHANC_PLUGIN_VERSION; | |
745 } | |
746 } |