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