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