Mercurial > hg > orthanc-transfers
annotate Plugin/Plugin.cpp @ 4:1ed03945c057
showing unavailable peers
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 17 Sep 2018 14:42:57 +0200 |
parents | 95226b754d9e |
children | 5e6de82bb10f |
rev | line source |
---|---|
0 | 1 /** |
2 * Transfers accelerator plugin for Orthanc | |
3 * Copyright (C) 2018 Osimis, Belgium | |
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 { | |
72 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "GET"); | |
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 { | |
162 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, chunk.c_str(), | |
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); | |
173 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, compressed.c_str(), | |
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 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
190 | |
191 Json::Reader reader; | |
192 | |
193 if (request->method != OrthancPluginHttpMethod_Post) | |
194 { | |
195 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "POST"); | |
196 return false; | |
197 } | |
198 else if (reader.parse(request->body, request->body + request->bodySize, body)) | |
199 { | |
200 return true; | |
201 } | |
202 else | |
203 { | |
204 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
205 } | |
206 } | |
207 | |
208 | |
209 void LookupInstances(OrthancPluginRestOutput* output, | |
210 const char* url, | |
211 const OrthancPluginHttpRequest* request) | |
212 { | |
213 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
214 | |
215 Json::Value resources; | |
216 if (!ParsePostBody(resources, output, request)) | |
217 { | |
218 return; | |
219 } | |
220 | |
221 OrthancPlugins::TransferScheduler scheduler; | |
222 scheduler.ParseListOfResources(context.GetCache(), resources); | |
223 | |
224 Json::Value answer = Json::objectValue; | |
225 answer[KEY_INSTANCES] = Json::arrayValue; | |
226 answer[KEY_ORIGINATOR_UUID] = context.GetPluginUuid(); | |
227 answer["CountInstances"] = static_cast<uint32_t>(scheduler.GetInstancesCount()); | |
228 answer["TotalSize"] = boost::lexical_cast<std::string>(scheduler.GetTotalSize()); | |
229 answer["TotalSizeMB"] = OrthancPlugins::ConvertToMegabytes(scheduler.GetTotalSize()); | |
230 | |
231 std::vector<OrthancPlugins::DicomInstanceInfo> instances; | |
232 scheduler.ListInstances(instances); | |
233 | |
234 for (size_t i = 0; i < instances.size(); i++) | |
235 { | |
236 Json::Value instance; | |
237 instances[i].Serialize(instance); | |
238 answer[KEY_INSTANCES].append(instance); | |
239 } | |
240 | |
241 Json::FastWriter writer; | |
242 std::string s = writer.write(answer); | |
243 | |
244 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
245 } | |
246 | |
247 | |
248 | |
249 static void SubmitJob(OrthancPluginRestOutput* output, | |
250 OrthancPlugins::OrthancJob* job, | |
251 int priority) | |
252 { | |
253 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
254 | |
255 std::string id = OrthancPlugins::OrthancJob::Submit(context.GetOrthanc(), job, priority); | |
256 | |
257 Json::Value result = Json::objectValue; | |
258 result[KEY_ID] = id; | |
259 result[KEY_PATH] = std::string(URI_JOBS) + "/" + id; | |
260 | |
261 std::string s = result.toStyledString(); | |
262 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
263 } | |
264 | |
265 | |
266 | |
267 void SchedulePull(OrthancPluginRestOutput* output, | |
268 const char* url, | |
269 const OrthancPluginHttpRequest* request) | |
270 { | |
271 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
272 | |
273 Json::Value body; | |
274 if (!ParsePostBody(body, output, request)) | |
275 { | |
276 return; | |
277 } | |
278 | |
279 OrthancPlugins::TransferQuery query(body); | |
280 | |
281 SubmitJob(output, new OrthancPlugins::PullJob(context.GetOrthanc(), query, | |
282 context.GetThreadsCount(), | |
283 context.GetTargetBucketSize()), | |
284 query.GetPriority()); | |
285 } | |
286 | |
287 | |
288 | |
289 void CreatePush(OrthancPluginRestOutput* output, | |
290 const char* url, | |
291 const OrthancPluginHttpRequest* request) | |
292 { | |
293 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
294 | |
295 Json::Value query; | |
296 if (!ParsePostBody(query, output, request)) | |
297 { | |
298 return; | |
299 } | |
300 | |
301 if (query.type() != Json::objectValue || | |
302 !query.isMember(KEY_BUCKETS) || | |
303 !query.isMember(KEY_COMPRESSION) || | |
304 !query.isMember(KEY_INSTANCES) || | |
305 query[KEY_BUCKETS].type() != Json::arrayValue || | |
306 query[KEY_COMPRESSION].type() != Json::stringValue || | |
307 query[KEY_INSTANCES].type() != Json::arrayValue) | |
308 { | |
309 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
310 } | |
311 | |
312 std::vector<OrthancPlugins::DicomInstanceInfo> instances; | |
313 instances.reserve(query[KEY_INSTANCES].size()); | |
314 | |
315 for (Json::Value::ArrayIndex i = 0; i < query[KEY_INSTANCES].size(); i++) | |
316 { | |
317 OrthancPlugins::DicomInstanceInfo instance(query[KEY_INSTANCES][i]); | |
318 instances.push_back(instance); | |
319 } | |
320 | |
321 std::vector<OrthancPlugins::TransferBucket> buckets; | |
322 buckets.reserve(query[KEY_BUCKETS].size()); | |
323 | |
324 for (Json::Value::ArrayIndex i = 0; i < query[KEY_BUCKETS].size(); i++) | |
325 { | |
326 OrthancPlugins::TransferBucket bucket(query[KEY_BUCKETS][i]); | |
327 buckets.push_back(bucket); | |
328 } | |
329 | |
330 OrthancPlugins::BucketCompression compression = | |
331 OrthancPlugins::StringToBucketCompression(query[KEY_COMPRESSION].asString()); | |
332 | |
333 std::string id = context.GetActivePushTransactions().CreateTransaction | |
334 (instances, buckets, compression); | |
335 | |
336 Json::Value result = Json::objectValue; | |
337 result[KEY_ID] = id; | |
338 result[KEY_PATH] = std::string(URI_PUSH) + "/" + id; | |
339 | |
340 std::string s = result.toStyledString(); | |
341 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
342 } | |
343 | |
344 | |
345 void StorePush(OrthancPluginRestOutput* output, | |
346 const char* url, | |
347 const OrthancPluginHttpRequest* request) | |
348 { | |
349 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
350 | |
351 if (request->method != OrthancPluginHttpMethod_Put) | |
352 { | |
353 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "PUT"); | |
354 return; | |
355 } | |
356 | |
357 assert(request->groupsCount == 2); | |
358 std::string transaction(request->groups[0]); | |
359 std::string chunk(request->groups[1]); | |
360 | |
361 size_t chunkIndex; | |
362 | |
363 try | |
364 { | |
365 chunkIndex = boost::lexical_cast<size_t>(chunk); | |
366 } | |
367 catch (boost::bad_lexical_cast&) | |
368 { | |
369 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); | |
370 } | |
371 | |
372 context.GetActivePushTransactions().Store | |
373 (context.GetOrthanc(), transaction, chunkIndex, request->body, request->bodySize); | |
374 | |
375 std::string s = "{}"; | |
376 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
377 } | |
378 | |
379 | |
380 void CommitPush(OrthancPluginRestOutput* output, | |
381 const char* url, | |
382 const OrthancPluginHttpRequest* request) | |
383 { | |
384 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
385 | |
386 if (request->method != OrthancPluginHttpMethod_Post) | |
387 { | |
388 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "POST"); | |
389 return; | |
390 } | |
391 | |
392 assert(request->groupsCount == 1); | |
393 std::string transaction(request->groups[0]); | |
394 | |
395 context. | |
396 GetActivePushTransactions().Commit(context.GetOrthanc(), transaction); | |
397 | |
398 std::string s = "{}"; | |
399 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
400 } | |
401 | |
402 | |
403 void DiscardPush(OrthancPluginRestOutput* output, | |
404 const char* url, | |
405 const OrthancPluginHttpRequest* request) | |
406 { | |
407 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
408 | |
409 if (request->method != OrthancPluginHttpMethod_Delete) | |
410 { | |
411 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "DELETE"); | |
412 return; | |
413 } | |
414 | |
415 assert(request->groupsCount == 1); | |
416 std::string transaction(request->groups[0]); | |
417 | |
418 context. | |
419 GetActivePushTransactions().Discard(transaction); | |
420 | |
421 std::string s = "{}"; | |
422 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
423 } | |
424 | |
425 | |
426 | |
427 void ScheduleSend(OrthancPluginRestOutput* output, | |
428 const char* url, | |
429 const OrthancPluginHttpRequest* request) | |
430 { | |
431 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
432 | |
433 Json::Value body; | |
434 if (!ParsePostBody(body, output, request)) | |
435 { | |
436 return; | |
437 } | |
438 | |
439 OrthancPlugins::TransferQuery query(body); | |
440 | |
441 std::string remoteSelf; // For pull mode | |
442 bool pullMode = context.LookupBidirectionalPeer(remoteSelf, query.GetPeer()); | |
443 | |
444 LOG(INFO) << "Sending resources to peer \"" << query.GetPeer() << "\" using " | |
445 << (pullMode ? "pull" : "push") << " mode"; | |
446 | |
447 if (pullMode) | |
448 { | |
449 OrthancPlugins::OrthancPeers peers(context.GetOrthanc()); | |
450 | |
451 Json::Value lookup = Json::objectValue; | |
452 lookup[KEY_RESOURCES] = query.GetResources(); | |
453 lookup[KEY_COMPRESSION] = OrthancPlugins::EnumerationToString(query.GetCompression()); | |
454 lookup[KEY_ORIGINATOR_UUID] = context.GetPluginUuid(); | |
455 lookup[KEY_PEER] = remoteSelf; | |
456 | |
457 Json::FastWriter writer; | |
458 std::string s = writer.write(lookup); | |
459 | |
460 Json::Value answer; | |
461 if (peers.DoPost(answer, query.GetPeer(), URI_PULL, s) && | |
462 answer.type() == Json::objectValue && | |
463 answer.isMember(KEY_ID) && | |
464 answer.isMember(KEY_PATH) && | |
465 answer[KEY_ID].type() == Json::stringValue && | |
466 answer[KEY_PATH].type() == Json::stringValue) | |
467 { | |
468 const std::string url = peers.GetPeerUrl(query.GetPeer()); | |
469 | |
470 Json::Value result = Json::objectValue; | |
471 result[KEY_PEER] = query.GetPeer(); | |
472 result[KEY_REMOTE_JOB] = answer[KEY_ID].asString(); | |
473 result[KEY_URL] = url + answer[KEY_PATH].asString(); | |
474 | |
475 std::string s = result.toStyledString(); | |
476 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
477 } | |
478 else | |
479 { | |
480 LOG(ERROR) << "Cannot trigger send DICOM instances using pull mode to peer: " << query.GetPeer() | |
481 << " (check out remote logs, and that transfer plugin is installed)"; | |
482 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
483 } | |
484 } | |
485 else | |
486 { | |
487 SubmitJob(output, new OrthancPlugins::PushJob(context.GetOrthanc(), query, | |
488 context.GetCache(), | |
489 context.GetThreadsCount(), | |
490 context.GetTargetBucketSize()), | |
491 query.GetPriority()); | |
492 } | |
493 } | |
494 | |
495 | |
496 OrthancPluginJob* Unserializer(const char* jobType, | |
497 const char* serialized) | |
498 { | |
499 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
500 | |
501 if (jobType == NULL || | |
502 serialized == NULL) | |
503 { | |
504 return NULL; | |
505 } | |
506 | |
507 std::string type(jobType); | |
508 | |
509 if (type != JOB_TYPE_PULL && | |
510 type != JOB_TYPE_PUSH) | |
511 { | |
512 return NULL; | |
513 } | |
514 | |
515 try | |
516 { | |
517 std::string tmp(serialized); | |
518 | |
519 Json::Value source; | |
520 Json::Reader reader; | |
521 if (reader.parse(tmp, source)) | |
522 { | |
523 OrthancPlugins::TransferQuery query(source); | |
524 | |
525 std::auto_ptr<OrthancPlugins::OrthancJob> job; | |
526 | |
527 if (type == JOB_TYPE_PULL) | |
528 { | |
529 job.reset(new OrthancPlugins::PullJob(context.GetOrthanc(), query, | |
530 context.GetThreadsCount(), | |
531 context.GetTargetBucketSize())); | |
532 } | |
533 else if (type == JOB_TYPE_PUSH) | |
534 { | |
535 job.reset(new OrthancPlugins::PushJob(context.GetOrthanc(), query, | |
536 context.GetCache(), | |
537 context.GetThreadsCount(), | |
538 context.GetTargetBucketSize())); | |
539 } | |
540 | |
541 if (job.get() == NULL) | |
542 { | |
543 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
544 } | |
545 else | |
546 { | |
547 return OrthancPlugins::OrthancJob::Create(context.GetOrthanc(), job.release()); | |
548 } | |
549 } | |
550 else | |
551 { | |
552 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
553 } | |
554 } | |
555 catch (Orthanc::OrthancException& e) | |
556 { | |
557 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin: " | |
558 << e.What(); | |
559 return NULL; | |
560 } | |
561 catch (...) | |
562 { | |
563 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin"; | |
564 return NULL; | |
565 } | |
566 } | |
567 | |
568 | |
569 | |
570 void ServePeers(OrthancPluginRestOutput* output, | |
571 const char* url, | |
572 const OrthancPluginHttpRequest* request) | |
573 { | |
574 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
575 | |
576 if (request->method != OrthancPluginHttpMethod_Get) | |
577 { | |
578 OrthancPluginSendMethodNotAllowed(context.GetOrthanc(), output, "GET"); | |
579 return; | |
580 } | |
581 | |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
582 OrthancPlugins::DetectTransferPlugin::Peers peers; |
0 | 583 OrthancPlugins::DetectTransferPlugin::Apply |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
584 (peers, context.GetOrthanc(), context.GetThreadsCount(), 2 /* timeout */); |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
585 |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
586 Json::Value result = Json::objectValue; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
587 |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
588 for (OrthancPlugins::DetectTransferPlugin::Peers::const_iterator |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
589 it = peers.begin(); it != peers.end(); ++it) |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
590 { |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
591 switch (it->second) |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
592 { |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
593 case OrthancPlugins::PeerCapabilities_Disabled: |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
594 result[it->first] = "disabled"; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
595 break; |
0 | 596 |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
597 case OrthancPlugins::PeerCapabilities_Installed: |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
598 { |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
599 std::string remoteSelf; |
0 | 600 |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
601 if (context.LookupBidirectionalPeer(remoteSelf, it->first)) |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
602 { |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
603 result[it->first] = "installed"; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
604 } |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
605 else |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
606 { |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
607 result[it->first] = "bidirectional"; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
608 } |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
609 break; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
610 } |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
611 |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
612 default: |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
613 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
614 } |
0 | 615 } |
616 | |
617 std::string s = result.toStyledString(); | |
618 OrthancPluginAnswerBuffer(context.GetOrthanc(), output, s.c_str(), s.size(), "application/json"); | |
619 } | |
620 | |
621 | |
622 | |
623 extern "C" | |
624 { | |
625 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
626 { | |
627 Orthanc::Logging::Initialize(context); | |
628 assert(DisplayPerformanceWarning()); | |
629 | |
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 | |
651 std::map<std::string, std::string> bidirectionalPeers; | |
652 | |
653 { | |
654 OrthancPlugins::OrthancConfiguration config(context); | |
655 | |
656 if (config.IsSection(KEY_PLUGIN_CONFIGURATION)) | |
657 { | |
658 OrthancPlugins::OrthancConfiguration plugin; | |
659 config.GetSection(plugin, KEY_PLUGIN_CONFIGURATION); | |
660 | |
661 plugin.GetDictionary(bidirectionalPeers, KEY_BIDIRECTIONAL_PEERS); | |
662 threadsCount = plugin.GetUnsignedIntegerValue("Threads", threadsCount); | |
663 targetBucketSize = plugin.GetUnsignedIntegerValue("BucketSize", targetBucketSize); | |
664 memoryCacheSize = plugin.GetUnsignedIntegerValue("CacheSize", memoryCacheSize); | |
665 maxPushTransactions = plugin.GetUnsignedIntegerValue | |
666 ("MaxPushTransactions", maxPushTransactions); | |
667 } | |
668 } | |
669 | |
670 OrthancPlugins::PluginContext::Initialize | |
671 (context, threadsCount, targetBucketSize * KB, maxPushTransactions, memoryCacheSize * MB); | |
672 OrthancPlugins::PluginContext::GetInstance().LoadBidirectionalPeers(bidirectionalPeers); | |
673 | |
674 OrthancPlugins::RegisterRestCallback<ServeChunks> | |
675 (context, std::string(URI_CHUNKS) + "/([.0-9a-f-]+)", true); | |
676 | |
677 OrthancPlugins::RegisterRestCallback<LookupInstances> | |
678 (context, URI_LOOKUP, true); | |
679 | |
680 OrthancPlugins::RegisterRestCallback<SchedulePull> | |
681 (context, URI_PULL, true); | |
682 | |
683 OrthancPlugins::RegisterRestCallback<ScheduleSend> | |
684 (context, URI_SEND, true); | |
685 | |
686 OrthancPlugins::RegisterRestCallback<ServePeers> | |
687 (context, URI_PEERS, true); | |
688 | |
689 if (maxPushTransactions != 0) | |
690 { | |
691 // If no push transaction is allowed, their URIs are disabled | |
692 OrthancPlugins::RegisterRestCallback<CreatePush> | |
693 (context, URI_PUSH, true); | |
694 | |
695 OrthancPlugins::RegisterRestCallback<StorePush> | |
696 (context, std::string(URI_PUSH) + "/([.0-9a-f-]+)/([0-9]+)", true); | |
697 | |
698 OrthancPlugins::RegisterRestCallback<CommitPush> | |
699 (context, std::string(URI_PUSH) + "/([.0-9a-f-]+)/commit", true); | |
700 | |
701 OrthancPlugins::RegisterRestCallback<DiscardPush> | |
702 (context, std::string(URI_PUSH) + "/([.0-9a-f-]+)", true); | |
703 } | |
704 | |
705 OrthancPluginRegisterJobsUnserializer(context, Unserializer); | |
706 | |
707 /* Extend the default Orthanc Explorer with custom JavaScript */ | |
708 std::string explorer; | |
709 Orthanc::EmbeddedResources::GetFileResource | |
710 (explorer, Orthanc::EmbeddedResources::ORTHANC_EXPLORER); | |
711 OrthancPluginExtendOrthancExplorer(context, explorer.c_str()); | |
712 } | |
713 catch (Orthanc::OrthancException& e) | |
714 { | |
715 LOG(ERROR) << "Cannot initialize transfers accelerator plugin: " << e.What(); | |
716 return -1; | |
717 } | |
718 | |
719 return 0; | |
720 } | |
721 | |
722 | |
723 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
724 { | |
725 LOG(WARNING) << "Transfers accelerator plugin is finalizing"; | |
726 | |
727 try | |
728 { | |
729 OrthancPlugins::PluginContext::Finalize(); | |
730 } | |
731 catch (Orthanc::OrthancException& e) | |
732 { | |
733 LOG(ERROR) << "Error while finalizing the transfers accelerator plugin: " << e.What(); | |
734 } | |
735 } | |
736 | |
737 | |
738 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
739 { | |
740 return PLUGIN_NAME; | |
741 } | |
742 | |
743 | |
744 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
745 { | |
746 return ORTHANC_PLUGIN_VERSION; | |
747 } | |
748 } |