Mercurial > hg > orthanc-transfers
annotate Plugin/Plugin.cpp @ 8:4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 05 Dec 2018 09:16:51 +0100 |
parents | 5e6de82bb10f |
children | 7e207ade2f1a |
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 { | |
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 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
277 SubmitJob(output, new OrthancPlugins::PullJob( |
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
278 query, context.GetThreadsCount(), context.GetTargetBucketSize()), |
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 | |
451 Json::FastWriter writer; | |
452 std::string s = writer.write(lookup); | |
453 | |
454 Json::Value answer; | |
455 if (peers.DoPost(answer, query.GetPeer(), URI_PULL, s) && | |
456 answer.type() == Json::objectValue && | |
457 answer.isMember(KEY_ID) && | |
458 answer.isMember(KEY_PATH) && | |
459 answer[KEY_ID].type() == Json::stringValue && | |
460 answer[KEY_PATH].type() == Json::stringValue) | |
461 { | |
462 const std::string url = peers.GetPeerUrl(query.GetPeer()); | |
463 | |
464 Json::Value result = Json::objectValue; | |
465 result[KEY_PEER] = query.GetPeer(); | |
466 result[KEY_REMOTE_JOB] = answer[KEY_ID].asString(); | |
467 result[KEY_URL] = url + answer[KEY_PATH].asString(); | |
468 | |
469 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
470 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 471 } |
472 else | |
473 { | |
474 LOG(ERROR) << "Cannot trigger send DICOM instances using pull mode to peer: " << query.GetPeer() | |
475 << " (check out remote logs, and that transfer plugin is installed)"; | |
476 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
477 } | |
478 } | |
479 else | |
480 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
481 SubmitJob(output, new OrthancPlugins::PushJob(query, context.GetCache(), |
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
482 context.GetThreadsCount(), context.GetTargetBucketSize()), |
0 | 483 query.GetPriority()); |
484 } | |
485 } | |
486 | |
487 | |
488 OrthancPluginJob* Unserializer(const char* jobType, | |
489 const char* serialized) | |
490 { | |
491 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
492 | |
493 if (jobType == NULL || | |
494 serialized == NULL) | |
495 { | |
496 return NULL; | |
497 } | |
498 | |
499 std::string type(jobType); | |
500 | |
501 if (type != JOB_TYPE_PULL && | |
502 type != JOB_TYPE_PUSH) | |
503 { | |
504 return NULL; | |
505 } | |
506 | |
507 try | |
508 { | |
509 std::string tmp(serialized); | |
510 | |
511 Json::Value source; | |
512 Json::Reader reader; | |
513 if (reader.parse(tmp, source)) | |
514 { | |
515 OrthancPlugins::TransferQuery query(source); | |
516 | |
517 std::auto_ptr<OrthancPlugins::OrthancJob> job; | |
518 | |
519 if (type == JOB_TYPE_PULL) | |
520 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
521 job.reset(new OrthancPlugins::PullJob(query, |
0 | 522 context.GetThreadsCount(), |
523 context.GetTargetBucketSize())); | |
524 } | |
525 else if (type == JOB_TYPE_PUSH) | |
526 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
527 job.reset(new OrthancPlugins::PushJob(query, |
0 | 528 context.GetCache(), |
529 context.GetThreadsCount(), | |
530 context.GetTargetBucketSize())); | |
531 } | |
532 | |
533 if (job.get() == NULL) | |
534 { | |
535 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
536 } | |
537 else | |
538 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
539 return OrthancPlugins::OrthancJob::Create(job.release()); |
0 | 540 } |
541 } | |
542 else | |
543 { | |
544 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
545 } | |
546 } | |
547 catch (Orthanc::OrthancException& e) | |
548 { | |
549 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin: " | |
550 << e.What(); | |
551 return NULL; | |
552 } | |
553 catch (...) | |
554 { | |
555 LOG(ERROR) << "Error while unserializing a job from the transfers accelerator plugin"; | |
556 return NULL; | |
557 } | |
558 } | |
559 | |
560 | |
561 | |
562 void ServePeers(OrthancPluginRestOutput* output, | |
563 const char* url, | |
564 const OrthancPluginHttpRequest* request) | |
565 { | |
566 OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance(); | |
567 | |
568 if (request->method != OrthancPluginHttpMethod_Get) | |
569 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
570 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET"); |
0 | 571 return; |
572 } | |
573 | |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
574 OrthancPlugins::DetectTransferPlugin::Result detection; |
0 | 575 OrthancPlugins::DetectTransferPlugin::Apply |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
576 (detection, context.GetThreadsCount(), 2 /* timeout */); |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
577 |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
578 Json::Value result = Json::objectValue; |
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
579 |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
580 OrthancPlugins::OrthancPeers peers; |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
581 |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
582 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
|
583 it = detection.begin(); it != detection.end(); ++it) |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
584 { |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
585 if (it->second) |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
586 { |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
587 std::string remoteSelf; |
0 | 588 |
5
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
589 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
|
590 { |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
591 result[it->first] = "bidirectional"; |
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 else |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
594 { |
5e6de82bb10f
use of user properties instead of BidirectionalPeers option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4
diff
changeset
|
595 result[it->first] = "installed"; |
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 } |
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] = "disabled"; |
4
1ed03945c057
showing unavailable peers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
601 } |
0 | 602 } |
603 | |
604 std::string s = result.toStyledString(); | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
605 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); |
0 | 606 } |
607 | |
608 | |
609 | |
610 extern "C" | |
611 { | |
612 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
613 { | |
614 Orthanc::Logging::Initialize(context); | |
615 assert(DisplayPerformanceWarning()); | |
616 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
617 OrthancPlugins::SetGlobalContext(context); |
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
618 |
0 | 619 /* Check the version of the Orthanc core */ |
620 if (OrthancPluginCheckVersion(context) == 0) | |
621 { | |
622 LOG(ERROR) << "Your version of Orthanc (" | |
623 << context->orthancVersion << ") must be above " | |
624 << ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER << "." | |
625 << ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER << "." | |
626 << ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER | |
627 << " to run this plugin"; | |
628 return -1; | |
629 } | |
630 | |
631 OrthancPluginSetDescription(context, "Accelerates transfers and provides " | |
632 "storage commitment between Orthanc peers"); | |
633 | |
634 try | |
635 { | |
636 size_t threadsCount = 4; | |
637 size_t targetBucketSize = 4096; // In KB | |
638 size_t maxPushTransactions = 4; | |
639 size_t memoryCacheSize = 512; // In MB | |
640 std::map<std::string, std::string> bidirectionalPeers; | |
641 | |
642 { | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
643 OrthancPlugins::OrthancConfiguration config; |
0 | 644 |
645 if (config.IsSection(KEY_PLUGIN_CONFIGURATION)) | |
646 { | |
647 OrthancPlugins::OrthancConfiguration plugin; | |
648 config.GetSection(plugin, KEY_PLUGIN_CONFIGURATION); | |
649 | |
650 threadsCount = plugin.GetUnsignedIntegerValue("Threads", threadsCount); | |
651 targetBucketSize = plugin.GetUnsignedIntegerValue("BucketSize", targetBucketSize); | |
652 memoryCacheSize = plugin.GetUnsignedIntegerValue("CacheSize", memoryCacheSize); | |
653 maxPushTransactions = plugin.GetUnsignedIntegerValue | |
654 ("MaxPushTransactions", maxPushTransactions); | |
655 } | |
656 } | |
657 | |
658 OrthancPlugins::PluginContext::Initialize | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
659 (threadsCount, targetBucketSize * KB, maxPushTransactions, memoryCacheSize * MB); |
0 | 660 |
661 OrthancPlugins::RegisterRestCallback<ServeChunks> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
662 (std::string(URI_CHUNKS) + "/([.0-9a-f-]+)", true); |
0 | 663 |
664 OrthancPlugins::RegisterRestCallback<LookupInstances> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
665 (URI_LOOKUP, true); |
0 | 666 |
667 OrthancPlugins::RegisterRestCallback<SchedulePull> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
668 (URI_PULL, true); |
0 | 669 |
670 OrthancPlugins::RegisterRestCallback<ScheduleSend> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
671 (URI_SEND, true); |
0 | 672 |
673 OrthancPlugins::RegisterRestCallback<ServePeers> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
674 (URI_PEERS, true); |
0 | 675 |
676 if (maxPushTransactions != 0) | |
677 { | |
678 // If no push transaction is allowed, their URIs are disabled | |
679 OrthancPlugins::RegisterRestCallback<CreatePush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
680 (URI_PUSH, true); |
0 | 681 |
682 OrthancPlugins::RegisterRestCallback<StorePush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
683 (std::string(URI_PUSH) + "/([.0-9a-f-]+)/([0-9]+)", true); |
0 | 684 |
685 OrthancPlugins::RegisterRestCallback<CommitPush> | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5
diff
changeset
|
686 (std::string(URI_PUSH) + "/([.0-9a-f-]+)/commit", true); |
0 | 687 |
688 OrthancPlugins::RegisterRestCallback<DiscardPush> | |
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-]+)", true); |
0 | 690 } |
691 | |
692 OrthancPluginRegisterJobsUnserializer(context, Unserializer); | |
693 | |
694 /* Extend the default Orthanc Explorer with custom JavaScript */ | |
695 std::string explorer; | |
696 Orthanc::EmbeddedResources::GetFileResource | |
697 (explorer, Orthanc::EmbeddedResources::ORTHANC_EXPLORER); | |
698 OrthancPluginExtendOrthancExplorer(context, explorer.c_str()); | |
699 } | |
700 catch (Orthanc::OrthancException& e) | |
701 { | |
702 LOG(ERROR) << "Cannot initialize transfers accelerator plugin: " << e.What(); | |
703 return -1; | |
704 } | |
705 | |
706 return 0; | |
707 } | |
708 | |
709 | |
710 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
711 { | |
712 LOG(WARNING) << "Transfers accelerator plugin is finalizing"; | |
713 | |
714 try | |
715 { | |
716 OrthancPlugins::PluginContext::Finalize(); | |
717 } | |
718 catch (Orthanc::OrthancException& e) | |
719 { | |
720 LOG(ERROR) << "Error while finalizing the transfers accelerator plugin: " << e.What(); | |
721 } | |
722 } | |
723 | |
724 | |
725 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
726 { | |
727 return PLUGIN_NAME; | |
728 } | |
729 | |
730 | |
731 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
732 { | |
733 return ORTHANC_PLUGIN_VERSION; | |
734 } | |
735 } |