Mercurial > hg > orthanc
annotate OrthancServer/ServerJobs/ArchiveJob.cpp @ 3754:ef625518c27c storage-commitment
closing branch storage-commitment
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 16 Mar 2020 12:15:52 +0100 |
parents | 56f2397f027a |
children | 6ddad3e0b569 |
rev | line source |
---|---|
2632 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
3640
94f4a18a79cc
upgrade to year 2020
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3240
diff
changeset
|
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium |
2632 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "../PrecompiledHeadersServer.h" | |
35 #include "ArchiveJob.h" | |
36 | |
3095
beeeb6096f27
removing dependencies upon ServerContext
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
37 #include "../../Core/Cache/SharedArchive.h" |
2632 | 38 #include "../../Core/Compression/HierarchicalZipWriter.h" |
39 #include "../../Core/DicomParsing/DicomDirWriter.h" | |
40 #include "../../Core/Logging.h" | |
41 #include "../../Core/OrthancException.h" | |
3181
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
42 #include "../OrthancConfiguration.h" |
3095
beeeb6096f27
removing dependencies upon ServerContext
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
43 #include "../ServerContext.h" |
2632 | 44 |
45 #include <stdio.h> | |
46 | |
47 #if defined(_MSC_VER) | |
48 #define snprintf _snprintf | |
49 #endif | |
50 | |
51 static const uint64_t MEGA_BYTES = 1024 * 1024; | |
52 static const uint64_t GIGA_BYTES = 1024 * 1024 * 1024; | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
53 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
54 static const char* const MEDIA_IMAGES_FOLDER = "IMAGES"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
55 static const char* const KEY_DESCRIPTION = "Description"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
56 static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
57 static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
58 |
2632 | 59 |
60 namespace Orthanc | |
61 { | |
62 static bool IsZip64Required(uint64_t uncompressedSize, | |
63 unsigned int countInstances) | |
64 { | |
65 static const uint64_t SAFETY_MARGIN = 64 * MEGA_BYTES; // Should be large enough to hold DICOMDIR | |
66 static const unsigned int FILES_MARGIN = 10; | |
67 | |
68 /** | |
69 * Determine whether ZIP64 is required. Original ZIP format can | |
70 * store up to 2GB of data (some implementation supporting up to | |
71 * 4GB of data), and up to 65535 files. | |
72 * https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64 | |
73 **/ | |
74 | |
75 const bool isZip64 = (uncompressedSize >= 2 * GIGA_BYTES - SAFETY_MARGIN || | |
76 countInstances >= 65535 - FILES_MARGIN); | |
77 | |
78 LOG(INFO) << "Creating a ZIP file with " << countInstances << " files of size " | |
79 << (uncompressedSize / MEGA_BYTES) << "MB using the " | |
80 << (isZip64 ? "ZIP64" : "ZIP32") << " file format"; | |
81 | |
82 return isZip64; | |
83 } | |
84 | |
85 | |
86 class ArchiveJob::ResourceIdentifiers : public boost::noncopyable | |
87 { | |
88 private: | |
89 ResourceType level_; | |
90 std::string patient_; | |
91 std::string study_; | |
92 std::string series_; | |
93 std::string instance_; | |
94 | |
95 static void GoToParent(ServerIndex& index, | |
96 std::string& current) | |
97 { | |
98 std::string tmp; | |
99 | |
100 if (index.LookupParent(tmp, current)) | |
101 { | |
102 current = tmp; | |
103 } | |
104 else | |
105 { | |
106 throw OrthancException(ErrorCode_UnknownResource); | |
107 } | |
108 } | |
109 | |
110 | |
111 public: | |
112 ResourceIdentifiers(ServerIndex& index, | |
113 const std::string& publicId) | |
114 { | |
115 if (!index.LookupResourceType(level_, publicId)) | |
116 { | |
117 throw OrthancException(ErrorCode_UnknownResource); | |
118 } | |
119 | |
120 std::string current = publicId;; | |
121 switch (level_) // Do not add "break" below! | |
122 { | |
123 case ResourceType_Instance: | |
124 instance_ = current; | |
125 GoToParent(index, current); | |
126 | |
127 case ResourceType_Series: | |
128 series_ = current; | |
129 GoToParent(index, current); | |
130 | |
131 case ResourceType_Study: | |
132 study_ = current; | |
133 GoToParent(index, current); | |
134 | |
135 case ResourceType_Patient: | |
136 patient_ = current; | |
137 break; | |
138 | |
139 default: | |
140 throw OrthancException(ErrorCode_InternalError); | |
141 } | |
142 } | |
143 | |
144 ResourceType GetLevel() const | |
145 { | |
146 return level_; | |
147 } | |
148 | |
149 const std::string& GetIdentifier(ResourceType level) const | |
150 { | |
151 // Some sanity check to ensure enumerations are not altered | |
152 assert(ResourceType_Patient < ResourceType_Study); | |
153 assert(ResourceType_Study < ResourceType_Series); | |
154 assert(ResourceType_Series < ResourceType_Instance); | |
155 | |
156 if (level > level_) | |
157 { | |
158 throw OrthancException(ErrorCode_InternalError); | |
159 } | |
160 | |
161 switch (level) | |
162 { | |
163 case ResourceType_Patient: | |
164 return patient_; | |
165 | |
166 case ResourceType_Study: | |
167 return study_; | |
168 | |
169 case ResourceType_Series: | |
170 return series_; | |
171 | |
172 case ResourceType_Instance: | |
173 return instance_; | |
174 | |
175 default: | |
176 throw OrthancException(ErrorCode_InternalError); | |
177 } | |
178 } | |
179 }; | |
180 | |
181 | |
182 class ArchiveJob::IArchiveVisitor : public boost::noncopyable | |
183 { | |
184 public: | |
185 virtual ~IArchiveVisitor() | |
186 { | |
187 } | |
188 | |
189 virtual void Open(ResourceType level, | |
190 const std::string& publicId) = 0; | |
191 | |
192 virtual void Close() = 0; | |
193 | |
194 virtual void AddInstance(const std::string& instanceId, | |
195 const FileInfo& dicom) = 0; | |
196 }; | |
197 | |
198 | |
199 class ArchiveJob::ArchiveIndex : public boost::noncopyable | |
200 { | |
201 private: | |
202 struct Instance | |
203 { | |
204 std::string id_; | |
205 FileInfo dicom_; | |
206 | |
207 Instance(const std::string& id, | |
208 const FileInfo& dicom) : | |
209 id_(id), dicom_(dicom) | |
210 { | |
211 } | |
212 }; | |
213 | |
214 // A "NULL" value for ArchiveIndex indicates a non-expanded node | |
215 typedef std::map<std::string, ArchiveIndex*> Resources; | |
216 | |
217 ResourceType level_; | |
218 Resources resources_; // Only at patient/study/series level | |
219 std::list<Instance> instances_; // Only at instance level | |
220 | |
221 | |
222 void AddResourceToExpand(ServerIndex& index, | |
223 const std::string& id) | |
224 { | |
225 if (level_ == ResourceType_Instance) | |
226 { | |
227 FileInfo tmp; | |
228 if (index.LookupAttachment(tmp, id, FileContentType_Dicom)) | |
229 { | |
230 instances_.push_back(Instance(id, tmp)); | |
231 } | |
232 } | |
233 else | |
234 { | |
235 resources_[id] = NULL; | |
236 } | |
237 } | |
238 | |
239 | |
240 public: | |
241 ArchiveIndex(ResourceType level) : | |
242 level_(level) | |
243 { | |
244 } | |
245 | |
246 ~ArchiveIndex() | |
247 { | |
248 for (Resources::iterator it = resources_.begin(); | |
249 it != resources_.end(); ++it) | |
250 { | |
251 delete it->second; | |
252 } | |
253 } | |
254 | |
255 | |
256 void Add(ServerIndex& index, | |
257 const ResourceIdentifiers& resource) | |
258 { | |
259 const std::string& id = resource.GetIdentifier(level_); | |
260 Resources::iterator previous = resources_.find(id); | |
261 | |
262 if (level_ == ResourceType_Instance) | |
263 { | |
264 AddResourceToExpand(index, id); | |
265 } | |
266 else if (resource.GetLevel() == level_) | |
267 { | |
268 // Mark this resource for further expansion | |
269 if (previous != resources_.end()) | |
270 { | |
271 delete previous->second; | |
272 } | |
273 | |
274 resources_[id] = NULL; | |
275 } | |
276 else if (previous == resources_.end()) | |
277 { | |
278 // This is the first time we meet this resource | |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
279 std::unique_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); |
2632 | 280 child->Add(index, resource); |
281 resources_[id] = child.release(); | |
282 } | |
283 else if (previous->second != NULL) | |
284 { | |
285 previous->second->Add(index, resource); | |
286 } | |
287 else | |
288 { | |
289 // Nothing to do: This item is marked for further expansion | |
290 } | |
291 } | |
292 | |
293 | |
294 void Expand(ServerIndex& index) | |
295 { | |
296 if (level_ == ResourceType_Instance) | |
297 { | |
298 // Expanding an instance node makes no sense | |
299 return; | |
300 } | |
301 | |
302 for (Resources::iterator it = resources_.begin(); | |
303 it != resources_.end(); ++it) | |
304 { | |
305 if (it->second == NULL) | |
306 { | |
307 // This is resource is marked for expansion | |
308 std::list<std::string> children; | |
309 index.GetChildren(children, it->first); | |
310 | |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
311 std::unique_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); |
2632 | 312 |
313 for (std::list<std::string>::const_iterator | |
314 it2 = children.begin(); it2 != children.end(); ++it2) | |
315 { | |
316 child->AddResourceToExpand(index, *it2); | |
317 } | |
318 | |
319 it->second = child.release(); | |
320 } | |
321 | |
322 assert(it->second != NULL); | |
323 it->second->Expand(index); | |
324 } | |
325 } | |
326 | |
327 | |
328 void Apply(IArchiveVisitor& visitor) const | |
329 { | |
330 if (level_ == ResourceType_Instance) | |
331 { | |
332 for (std::list<Instance>::const_iterator | |
333 it = instances_.begin(); it != instances_.end(); ++it) | |
334 { | |
335 visitor.AddInstance(it->id_, it->dicom_); | |
336 } | |
337 } | |
338 else | |
339 { | |
340 for (Resources::const_iterator it = resources_.begin(); | |
341 it != resources_.end(); ++it) | |
342 { | |
343 assert(it->second != NULL); // There must have been a call to "Expand()" | |
344 visitor.Open(level_, it->first); | |
345 it->second->Apply(visitor); | |
346 visitor.Close(); | |
347 } | |
348 } | |
349 } | |
350 }; | |
351 | |
352 | |
353 | |
354 class ArchiveJob::ZipCommands : public boost::noncopyable | |
355 { | |
356 private: | |
357 enum Type | |
358 { | |
359 Type_OpenDirectory, | |
360 Type_CloseDirectory, | |
361 Type_WriteInstance | |
362 }; | |
363 | |
364 class Command : public boost::noncopyable | |
365 { | |
366 private: | |
367 Type type_; | |
368 std::string filename_; | |
369 std::string instanceId_; | |
370 FileInfo info_; | |
371 | |
372 public: | |
373 explicit Command(Type type) : | |
374 type_(type) | |
375 { | |
376 assert(type_ == Type_CloseDirectory); | |
377 } | |
378 | |
379 Command(Type type, | |
380 const std::string& filename) : | |
381 type_(type), | |
382 filename_(filename) | |
383 { | |
384 assert(type_ == Type_OpenDirectory); | |
385 } | |
386 | |
387 Command(Type type, | |
388 const std::string& filename, | |
389 const std::string& instanceId, | |
390 const FileInfo& info) : | |
391 type_(type), | |
392 filename_(filename), | |
393 instanceId_(instanceId), | |
394 info_(info) | |
395 { | |
396 assert(type_ == Type_WriteInstance); | |
397 } | |
398 | |
399 void Apply(HierarchicalZipWriter& writer, | |
400 ServerContext& context, | |
401 DicomDirWriter* dicomDir, | |
402 const std::string& dicomDirFolder) const | |
403 { | |
404 switch (type_) | |
405 { | |
406 case Type_OpenDirectory: | |
407 writer.OpenDirectory(filename_.c_str()); | |
408 break; | |
409 | |
410 case Type_CloseDirectory: | |
411 writer.CloseDirectory(); | |
412 break; | |
413 | |
414 case Type_WriteInstance: | |
415 { | |
416 std::string content; | |
417 | |
418 try | |
419 { | |
420 context.ReadAttachment(content, info_); | |
421 } | |
422 catch (OrthancException& e) | |
423 { | |
424 LOG(WARNING) << "An instance was removed after the job was issued: " << instanceId_; | |
425 return; | |
426 } | |
2636 | 427 |
428 //boost::this_thread::sleep(boost::posix_time::milliseconds(300)); | |
2632 | 429 |
430 writer.OpenFile(filename_.c_str()); | |
431 writer.Write(content); | |
432 | |
433 if (dicomDir != NULL) | |
434 { | |
435 ParsedDicomFile parsed(content); | |
436 dicomDir->Add(dicomDirFolder, filename_, parsed); | |
437 } | |
438 | |
439 break; | |
440 } | |
441 | |
442 default: | |
443 throw OrthancException(ErrorCode_InternalError); | |
444 } | |
445 } | |
446 }; | |
447 | |
448 std::deque<Command*> commands_; | |
449 uint64_t uncompressedSize_; | |
450 unsigned int instancesCount_; | |
451 | |
452 | |
453 void ApplyInternal(HierarchicalZipWriter& writer, | |
454 ServerContext& context, | |
455 size_t index, | |
456 DicomDirWriter* dicomDir, | |
457 const std::string& dicomDirFolder) const | |
458 { | |
459 if (index >= commands_.size()) | |
460 { | |
461 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
462 } | |
463 | |
464 commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder); | |
465 } | |
466 | |
467 public: | |
468 ZipCommands() : | |
469 uncompressedSize_(0), | |
470 instancesCount_(0) | |
471 { | |
472 } | |
473 | |
474 ~ZipCommands() | |
475 { | |
476 for (std::deque<Command*>::iterator it = commands_.begin(); | |
477 it != commands_.end(); ++it) | |
478 { | |
479 assert(*it != NULL); | |
480 delete *it; | |
481 } | |
482 } | |
483 | |
484 size_t GetSize() const | |
485 { | |
486 return commands_.size(); | |
487 } | |
488 | |
489 unsigned int GetInstancesCount() const | |
490 { | |
491 return instancesCount_; | |
492 } | |
493 | |
494 uint64_t GetUncompressedSize() const | |
495 { | |
496 return uncompressedSize_; | |
497 } | |
498 | |
499 void Apply(HierarchicalZipWriter& writer, | |
500 ServerContext& context, | |
501 size_t index, | |
502 DicomDirWriter& dicomDir, | |
503 const std::string& dicomDirFolder) const | |
504 { | |
505 ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder); | |
506 } | |
507 | |
508 void Apply(HierarchicalZipWriter& writer, | |
509 ServerContext& context, | |
510 size_t index) const | |
511 { | |
512 ApplyInternal(writer, context, index, NULL, ""); | |
513 } | |
514 | |
515 void AddOpenDirectory(const std::string& filename) | |
516 { | |
517 commands_.push_back(new Command(Type_OpenDirectory, filename)); | |
518 } | |
519 | |
520 void AddCloseDirectory() | |
521 { | |
522 commands_.push_back(new Command(Type_CloseDirectory)); | |
523 } | |
524 | |
525 void AddWriteInstance(const std::string& filename, | |
526 const std::string& instanceId, | |
527 const FileInfo& info) | |
528 { | |
529 commands_.push_back(new Command(Type_WriteInstance, filename, instanceId, info)); | |
530 instancesCount_ ++; | |
531 uncompressedSize_ += info.GetUncompressedSize(); | |
532 } | |
533 | |
534 bool IsZip64() const | |
535 { | |
536 return IsZip64Required(GetUncompressedSize(), GetInstancesCount()); | |
537 } | |
538 }; | |
539 | |
540 | |
541 | |
542 class ArchiveJob::ArchiveIndexVisitor : public IArchiveVisitor | |
543 { | |
544 private: | |
545 ZipCommands& commands_; | |
546 ServerContext& context_; | |
547 char instanceFormat_[24]; | |
548 unsigned int counter_; | |
549 | |
550 static std::string GetTag(const DicomMap& tags, | |
551 const DicomTag& tag) | |
552 { | |
553 const DicomValue* v = tags.TestAndGetValue(tag); | |
554 if (v != NULL && | |
555 !v->IsBinary() && | |
556 !v->IsNull()) | |
557 { | |
558 return v->GetContent(); | |
559 } | |
560 else | |
561 { | |
562 return ""; | |
563 } | |
564 } | |
565 | |
566 public: | |
567 ArchiveIndexVisitor(ZipCommands& commands, | |
568 ServerContext& context) : | |
569 commands_(commands), | |
570 context_(context), | |
571 counter_(0) | |
572 { | |
573 if (commands.GetSize() != 0) | |
574 { | |
575 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
576 } | |
577 | |
578 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); | |
579 } | |
580 | |
581 virtual void Open(ResourceType level, | |
582 const std::string& publicId) | |
583 { | |
584 std::string path; | |
585 | |
586 DicomMap tags; | |
587 if (context_.GetIndex().GetMainDicomTags(tags, publicId, level, level)) | |
588 { | |
589 switch (level) | |
590 { | |
591 case ResourceType_Patient: | |
592 path = GetTag(tags, DICOM_TAG_PATIENT_ID) + " " + GetTag(tags, DICOM_TAG_PATIENT_NAME); | |
593 break; | |
594 | |
595 case ResourceType_Study: | |
596 path = GetTag(tags, DICOM_TAG_ACCESSION_NUMBER) + " " + GetTag(tags, DICOM_TAG_STUDY_DESCRIPTION); | |
597 break; | |
598 | |
599 case ResourceType_Series: | |
600 { | |
601 std::string modality = GetTag(tags, DICOM_TAG_MODALITY); | |
602 path = modality + " " + GetTag(tags, DICOM_TAG_SERIES_DESCRIPTION); | |
603 | |
604 if (modality.size() == 0) | |
605 { | |
606 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); | |
607 } | |
608 else if (modality.size() == 1) | |
609 { | |
610 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%%07d.dcm", | |
611 toupper(modality[0])); | |
612 } | |
613 else if (modality.size() >= 2) | |
614 { | |
615 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%c%%06d.dcm", | |
616 toupper(modality[0]), toupper(modality[1])); | |
617 } | |
618 | |
619 counter_ = 0; | |
620 | |
621 break; | |
622 } | |
623 | |
624 default: | |
625 throw OrthancException(ErrorCode_InternalError); | |
626 } | |
627 } | |
628 | |
629 path = Toolbox::StripSpaces(Toolbox::ConvertToAscii(path)); | |
630 | |
631 if (path.empty()) | |
632 { | |
633 path = std::string("Unknown ") + EnumerationToString(level); | |
634 } | |
635 | |
636 commands_.AddOpenDirectory(path.c_str()); | |
637 } | |
638 | |
639 virtual void Close() | |
640 { | |
641 commands_.AddCloseDirectory(); | |
642 } | |
643 | |
644 virtual void AddInstance(const std::string& instanceId, | |
645 const FileInfo& dicom) | |
646 { | |
647 char filename[24]; | |
648 snprintf(filename, sizeof(filename) - 1, instanceFormat_, counter_); | |
649 counter_ ++; | |
650 | |
651 commands_.AddWriteInstance(filename, instanceId, dicom); | |
652 } | |
653 }; | |
654 | |
655 | |
656 class ArchiveJob::MediaIndexVisitor : public IArchiveVisitor | |
657 { | |
658 private: | |
659 ZipCommands& commands_; | |
660 ServerContext& context_; | |
661 unsigned int counter_; | |
662 | |
663 public: | |
664 MediaIndexVisitor(ZipCommands& commands, | |
665 ServerContext& context) : | |
666 commands_(commands), | |
667 context_(context), | |
668 counter_(0) | |
669 { | |
670 } | |
671 | |
672 virtual void Open(ResourceType level, | |
673 const std::string& publicId) | |
674 { | |
675 } | |
676 | |
677 virtual void Close() | |
678 { | |
679 } | |
680 | |
681 virtual void AddInstance(const std::string& instanceId, | |
682 const FileInfo& dicom) | |
683 { | |
684 // "DICOM restricts the filenames on DICOM media to 8 | |
685 // characters (some systems wrongly use 8.3, but this does not | |
686 // conform to the standard)." | |
687 std::string filename = "IM" + boost::lexical_cast<std::string>(counter_); | |
688 commands_.AddWriteInstance(filename, instanceId, dicom); | |
689 | |
690 counter_ ++; | |
691 } | |
692 }; | |
693 | |
694 | |
695 class ArchiveJob::ZipWriterIterator : public boost::noncopyable | |
696 { | |
697 private: | |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
698 TemporaryFile& target_; |
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
699 ServerContext& context_; |
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
700 ZipCommands commands_; |
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
701 std::unique_ptr<HierarchicalZipWriter> zip_; |
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
702 std::unique_ptr<DicomDirWriter> dicomDir_; |
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
703 bool isMedia_; |
2632 | 704 |
705 public: | |
706 ZipWriterIterator(TemporaryFile& target, | |
707 ServerContext& context, | |
708 ArchiveIndex& archive, | |
709 bool isMedia, | |
710 bool enableExtendedSopClass) : | |
711 target_(target), | |
712 context_(context), | |
713 isMedia_(isMedia) | |
714 { | |
715 if (isMedia) | |
716 { | |
717 MediaIndexVisitor visitor(commands_, context); | |
718 archive.Expand(context.GetIndex()); | |
719 | |
720 commands_.AddOpenDirectory(MEDIA_IMAGES_FOLDER); | |
721 archive.Apply(visitor); | |
722 commands_.AddCloseDirectory(); | |
723 | |
724 dicomDir_.reset(new DicomDirWriter); | |
725 dicomDir_->EnableExtendedSopClass(enableExtendedSopClass); | |
726 } | |
727 else | |
728 { | |
729 ArchiveIndexVisitor visitor(commands_, context); | |
730 archive.Expand(context.GetIndex()); | |
731 archive.Apply(visitor); | |
732 } | |
733 | |
734 zip_.reset(new HierarchicalZipWriter(target.GetPath().c_str())); | |
735 zip_->SetZip64(commands_.IsZip64()); | |
736 } | |
737 | |
738 size_t GetStepsCount() const | |
739 { | |
740 return commands_.GetSize() + 1; | |
741 } | |
742 | |
743 void RunStep(size_t index) | |
744 { | |
745 if (index > commands_.GetSize()) | |
746 { | |
747 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
748 } | |
749 else if (index == commands_.GetSize()) | |
750 { | |
751 // Last step: Add the DICOMDIR | |
752 if (isMedia_) | |
753 { | |
754 assert(dicomDir_.get() != NULL); | |
755 std::string s; | |
756 dicomDir_->Encode(s); | |
757 | |
758 zip_->OpenFile("DICOMDIR"); | |
759 zip_->Write(s); | |
760 } | |
761 } | |
762 else | |
763 { | |
764 if (isMedia_) | |
765 { | |
766 assert(dicomDir_.get() != NULL); | |
767 commands_.Apply(*zip_, context_, index, *dicomDir_, MEDIA_IMAGES_FOLDER); | |
768 } | |
769 else | |
770 { | |
771 assert(dicomDir_.get() == NULL); | |
772 commands_.Apply(*zip_, context_, index); | |
773 } | |
774 } | |
775 } | |
776 | |
777 unsigned int GetInstancesCount() const | |
778 { | |
779 return commands_.GetInstancesCount(); | |
780 } | |
781 | |
782 uint64_t GetUncompressedSize() const | |
783 { | |
784 return commands_.GetUncompressedSize(); | |
785 } | |
786 }; | |
787 | |
788 | |
2966 | 789 ArchiveJob::ArchiveJob(ServerContext& context, |
2632 | 790 bool isMedia, |
791 bool enableExtendedSopClass) : | |
792 context_(context), | |
793 archive_(new ArchiveIndex(ResourceType_Patient)), // root | |
794 isMedia_(isMedia), | |
795 enableExtendedSopClass_(enableExtendedSopClass), | |
796 currentStep_(0), | |
797 instancesCount_(0), | |
798 uncompressedSize_(0) | |
799 { | |
2966 | 800 } |
801 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
802 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
803 ArchiveJob::~ArchiveJob() |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
804 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
805 if (!mediaArchiveId_.empty()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
806 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
807 context_.GetMediaArchive().Remove(mediaArchiveId_); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
808 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
809 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
810 |
2966 | 811 |
812 void ArchiveJob::SetSynchronousTarget(boost::shared_ptr<TemporaryFile>& target) | |
813 { | |
814 if (target.get() == NULL) | |
2632 | 815 { |
816 throw OrthancException(ErrorCode_NullPointer); | |
817 } | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
818 else if (writer_.get() != NULL || // Already started |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
819 synchronousTarget_.get() != NULL || |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
820 asynchronousTarget_.get() != NULL) |
2966 | 821 { |
822 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
823 } | |
824 else | |
825 { | |
826 synchronousTarget_ = target; | |
827 } | |
2632 | 828 } |
829 | |
830 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
831 void ArchiveJob::SetDescription(const std::string& description) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
832 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
833 if (writer_.get() != NULL) // Already started |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
834 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
835 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
836 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
837 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
838 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
839 description_ = description; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
840 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
841 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
842 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
843 |
2632 | 844 void ArchiveJob::AddResource(const std::string& publicId) |
845 { | |
846 if (writer_.get() != NULL) // Already started | |
847 { | |
848 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
849 } | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
850 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
851 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
852 ResourceIdentifiers resource(context_.GetIndex(), publicId); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
853 archive_->Add(context_.GetIndex(), resource); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
854 } |
2632 | 855 } |
856 | |
857 | |
2812
ea7aea6f6a95
improved naming of methods in IJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2730
diff
changeset
|
858 void ArchiveJob::Reset() |
2632 | 859 { |
2955 | 860 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
861 "Cannot resubmit the creation of an archive"); | |
2632 | 862 } |
863 | |
864 | |
865 void ArchiveJob::Start() | |
866 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
867 TemporaryFile* target = NULL; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
868 |
2966 | 869 if (synchronousTarget_.get() == NULL) |
870 { | |
3181
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
871 { |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
872 OrthancConfiguration::ReaderLock lock; |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
873 asynchronousTarget_.reset(lock.GetConfiguration().CreateTemporaryFile()); |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
874 } |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
875 |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
876 target = asynchronousTarget_.get(); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
877 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
878 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
879 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
880 target = synchronousTarget_.get(); |
2966 | 881 } |
3181
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
882 |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
883 assert(target != NULL); |
6fd38327e777
Fix issue #130 (Orthanc failed to start when /tmp partition was full)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3095
diff
changeset
|
884 target->Touch(); // Make sure we can write to the temporary file |
2966 | 885 |
2632 | 886 if (writer_.get() != NULL) |
887 { | |
888 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
889 } | |
890 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
891 writer_.reset(new ZipWriterIterator(*target, context_, *archive_, |
2632 | 892 isMedia_, enableExtendedSopClass_)); |
893 | |
894 instancesCount_ = writer_->GetInstancesCount(); | |
895 uncompressedSize_ = writer_->GetUncompressedSize(); | |
896 } | |
897 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
898 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
899 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
900 namespace |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
901 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
902 class DynamicTemporaryFile : public IDynamicObject |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
903 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
904 private: |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
905 std::unique_ptr<TemporaryFile> file_; |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
906 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
907 public: |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
908 DynamicTemporaryFile(TemporaryFile* f) : file_(f) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
909 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
910 if (f == NULL) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
911 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
912 throw OrthancException(ErrorCode_NullPointer); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
913 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
914 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
915 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
916 const TemporaryFile& GetFile() const |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
917 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
918 assert(file_.get() != NULL); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
919 return *file_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
920 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
921 }; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
922 } |
2632 | 923 |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
924 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
925 void ArchiveJob::FinalizeTarget() |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
926 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
927 writer_.reset(); // Flush all the results |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
928 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
929 if (asynchronousTarget_.get() != NULL) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
930 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
931 // Asynchronous behavior: Move the resulting file into the media archive |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
932 mediaArchiveId_ = context_.GetMediaArchive().Add( |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
933 new DynamicTemporaryFile(asynchronousTarget_.release())); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
934 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
935 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
936 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
937 |
3658
2d90dd30858c
providing job ID to the IJob::Step() methods
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
938 JobStepResult ArchiveJob::Step(const std::string& jobId) |
2632 | 939 { |
940 assert(writer_.get() != NULL); | |
941 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
942 if (synchronousTarget_.get() != NULL && |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
943 synchronousTarget_.unique()) |
2632 | 944 { |
945 LOG(WARNING) << "A client has disconnected while creating an archive"; | |
3240
e44e0127e553
Fix issue #134 (/patient/modify gives 500, should really be 400)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3181
diff
changeset
|
946 return JobStepResult::Failure(ErrorCode_NetworkProtocol, |
e44e0127e553
Fix issue #134 (/patient/modify gives 500, should really be 400)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3181
diff
changeset
|
947 "A client has disconnected while creating an archive"); |
2632 | 948 } |
949 | |
950 if (writer_->GetStepsCount() == 0) | |
951 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
952 FinalizeTarget(); |
2632 | 953 return JobStepResult::Success(); |
954 } | |
955 else | |
956 { | |
957 writer_->RunStep(currentStep_); | |
958 | |
959 currentStep_ ++; | |
960 | |
961 if (currentStep_ == writer_->GetStepsCount()) | |
962 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
963 FinalizeTarget(); |
2632 | 964 return JobStepResult::Success(); |
965 } | |
966 else | |
967 { | |
968 return JobStepResult::Continue(); | |
969 } | |
970 } | |
971 } | |
972 | |
973 | |
974 float ArchiveJob::GetProgress() | |
975 { | |
976 if (writer_.get() == NULL || | |
977 writer_->GetStepsCount() == 0) | |
978 { | |
979 return 1; | |
980 } | |
981 else | |
982 { | |
983 return (static_cast<float>(currentStep_) / | |
984 static_cast<float>(writer_->GetStepsCount() - 1)); | |
985 } | |
986 } | |
987 | |
988 | |
989 void ArchiveJob::GetJobType(std::string& target) | |
990 { | |
991 if (isMedia_) | |
992 { | |
993 target = "Media"; | |
994 } | |
995 else | |
996 { | |
997 target = "Archive"; | |
998 } | |
999 } | |
1000 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1001 |
2632 | 1002 void ArchiveJob::GetPublicContent(Json::Value& value) |
1003 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1004 value = Json::objectValue; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1005 value[KEY_DESCRIPTION] = description_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1006 value[KEY_INSTANCES_COUNT] = instancesCount_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1007 value[KEY_UNCOMPRESSED_SIZE_MB] = |
2643 | 1008 static_cast<unsigned int>(uncompressedSize_ / MEGA_BYTES); |
2632 | 1009 } |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1010 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1011 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1012 bool ArchiveJob::GetOutput(std::string& output, |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1013 MimeType& mime, |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1014 const std::string& key) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1015 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1016 if (key == "archive" && |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1017 !mediaArchiveId_.empty()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1018 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1019 SharedArchive::Accessor accessor(context_.GetMediaArchive(), mediaArchiveId_); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1020 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1021 if (accessor.IsValid()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1022 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1023 const DynamicTemporaryFile& f = dynamic_cast<DynamicTemporaryFile&>(accessor.GetItem()); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1024 f.GetFile().Read(output); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1025 mime = MimeType_Zip; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1026 return true; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1027 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1028 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1029 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1030 return false; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1031 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1032 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1033 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1034 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1035 return false; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1036 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1037 } |
2632 | 1038 } |