comparison OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.cpp @ 4153:a4664f169cd7

"/peers/{id}/store": New option "Compress" to compress DICOM data using gzip
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 23 Aug 2020 12:13:27 +0200
parents 05b8fd21089c
children 6e7c842679ec
comparison
equal deleted inserted replaced
4152:36257d6f348f 4153:a4664f169cd7
32 32
33 33
34 #include "../PrecompiledHeadersServer.h" 34 #include "../PrecompiledHeadersServer.h"
35 #include "OrthancPeerStoreJob.h" 35 #include "OrthancPeerStoreJob.h"
36 36
37 #include "../../../OrthancFramework/Sources/Compression/GzipCompressor.h"
37 #include "../../../OrthancFramework/Sources/Logging.h" 38 #include "../../../OrthancFramework/Sources/Logging.h"
38 #include "../../../OrthancFramework/Sources/SerializationToolbox.h" 39 #include "../../../OrthancFramework/Sources/SerializationToolbox.h"
39 #include "../ServerContext.h" 40 #include "../ServerContext.h"
40 41
41 #include <dcmtk/dcmdata/dcfilefo.h> 42 #include <dcmtk/dcmdata/dcfilefo.h>
49 50
50 if (client_.get() == NULL) 51 if (client_.get() == NULL)
51 { 52 {
52 client_.reset(new HttpClient(peer_, "instances")); 53 client_.reset(new HttpClient(peer_, "instances"));
53 client_->SetMethod(HttpMethod_Post); 54 client_->SetMethod(HttpMethod_Post);
55
56 if (compress_)
57 {
58 client_->AddHeader("Expect", "");
59 client_->AddHeader("Content-Encoding", "gzip");
60 }
54 } 61 }
55 62
56 LOG(INFO) << "Sending instance " << instance << " to peer \"" 63 LOG(INFO) << "Sending instance " << instance << " to peer \""
57 << peer_.GetUrl() << "\""; 64 << peer_.GetUrl() << "\"";
65
66 std::string body;
58 67
59 try 68 try
60 { 69 {
61 if (transcode_) 70 if (transcode_)
62 { 71 {
69 IDicomTranscoder::DicomImage source, transcoded; 78 IDicomTranscoder::DicomImage source, transcoded;
70 source.SetExternalBuffer(dicom); 79 source.SetExternalBuffer(dicom);
71 80
72 if (context_.Transcode(transcoded, source, syntaxes, true)) 81 if (context_.Transcode(transcoded, source, syntaxes, true))
73 { 82 {
74 client_->GetBody().assign(reinterpret_cast<const char*>(transcoded.GetBufferData()), 83 body.assign(reinterpret_cast<const char*>(transcoded.GetBufferData()),
75 transcoded.GetBufferSize()); 84 transcoded.GetBufferSize());
76 } 85 }
77 else 86 else
78 { 87 {
79 client_->GetBody().swap(dicom); 88 body.swap(dicom);
80 } 89 }
81 } 90 }
82 else 91 else
83 { 92 {
84 context_.ReadDicom(client_->GetBody(), instance); 93 context_.ReadDicom(body, instance);
85 } 94 }
86 } 95 }
87 catch (OrthancException& e) 96 catch (OrthancException& e)
88 { 97 {
89 LOG(WARNING) << "An instance was removed after the job was issued: " << instance; 98 LOG(WARNING) << "An instance was removed after the job was issued: " << instance;
90 return false; 99 return false;
91 } 100 }
101
102 if (compress_)
103 {
104 GzipCompressor compressor;
105 compressor.SetCompressionLevel(9); // Max compression level
106 IBufferCompressor::Compress(client_->GetBody(), compressor, body);
107 }
108 else
109 {
110 client_->GetBody().swap(body);
111 }
112
113 size_ += client_->GetBody().size();
92 114
93 std::string answer; 115 std::string answer;
94 if (client_->Apply(answer)) 116 if (client_->Apply(answer))
95 { 117 {
96 return true; 118 return true;
171 } 193 }
172 else 194 else
173 { 195 {
174 transcode_ = false; 196 transcode_ = false;
175 } 197 }
198 }
199
200
201 void OrthancPeerStoreJob::SetCompress(bool compress)
202 {
203 if (IsStarted())
204 {
205 throw OrthancException(ErrorCode_BadSequenceOfCalls);
206 }
207 else
208 {
209 compress_ = compress;
210 }
176 } 211 }
177 212
178 213
179 void OrthancPeerStoreJob::Stop(JobStopReason reason) // For pausing jobs 214 void OrthancPeerStoreJob::Stop(JobStopReason reason) // For pausing jobs
180 { 215 {
189 Json::Value v; 224 Json::Value v;
190 peer_.Serialize(v, 225 peer_.Serialize(v,
191 false /* allow simple format if possible */, 226 false /* allow simple format if possible */,
192 false /* don't include passwords */); 227 false /* don't include passwords */);
193 value["Peer"] = v; 228 value["Peer"] = v;
229 value["Compress"] = compress_;
194 230
195 if (transcode_) 231 if (transcode_)
196 { 232 {
197 value["Transcode"] = GetTransferSyntaxUid(transferSyntax_); 233 value["Transcode"] = GetTransferSyntaxUid(transferSyntax_);
198 } 234 }
235
236 static const uint64_t MEGA_BYTES = 1024 * 1024;
237 value["Size"] = boost::lexical_cast<std::string>(size_);
238 value["SizeMB"] = static_cast<unsigned int>(size_ / MEGA_BYTES);
199 } 239 }
200 240
201 241
202 static const char* PEER = "Peer"; 242 static const char* PEER = "Peer";
203 static const char* TRANSCODE = "Transcode"; 243 static const char* TRANSCODE = "Transcode";
244 static const char* COMPRESS = "Compress";
245 static const char* SIZE = "Size";
204 246
205 OrthancPeerStoreJob::OrthancPeerStoreJob(ServerContext& context, 247 OrthancPeerStoreJob::OrthancPeerStoreJob(ServerContext& context,
206 const Json::Value& serialized) : 248 const Json::Value& serialized) :
207 SetOfInstancesJob(serialized), 249 SetOfInstancesJob(serialized),
208 context_(context) 250 context_(context)
215 SetTranscode(SerializationToolbox::ReadString(serialized, TRANSCODE)); 257 SetTranscode(SerializationToolbox::ReadString(serialized, TRANSCODE));
216 } 258 }
217 else 259 else
218 { 260 {
219 transcode_ = false; 261 transcode_ = false;
262 transferSyntax_ = DicomTransferSyntax_LittleEndianExplicit; // Dummy value
263 }
264
265 if (serialized.isMember(COMPRESS))
266 {
267 SetCompress(SerializationToolbox::ReadBoolean(serialized, COMPRESS));
268 }
269 else
270 {
271 compress_ = false;
272 }
273
274 if (serialized.isMember(SIZE))
275 {
276 size_ = boost::lexical_cast<uint64_t>(SerializationToolbox::ReadString(serialized, SIZE));
277 }
278 else
279 {
280 size_ = 0;
220 } 281 }
221 } 282 }
222 283
223 284
224 bool OrthancPeerStoreJob::Serialize(Json::Value& target) 285 bool OrthancPeerStoreJob::Serialize(Json::Value& target)
236 297
237 if (transcode_) 298 if (transcode_)
238 { 299 {
239 target[TRANSCODE] = GetTransferSyntaxUid(transferSyntax_); 300 target[TRANSCODE] = GetTransferSyntaxUid(transferSyntax_);
240 } 301 }
302
303 target[COMPRESS] = compress_;
304 target[SIZE] = boost::lexical_cast<std::string>(size_);
241 305
242 return true; 306 return true;
243 } 307 }
244 } 308 }
245 } 309 }