Mercurial > hg > orthanc-transfers
annotate Framework/TransferBucket.cpp @ 77:1e396fb509ca default
updated copyright, as Orthanc Team now replaces Osimis
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 30 May 2024 22:44:10 +0200 |
parents | 44a0430d7899 |
children |
rev | line source |
---|---|
0 | 1 /** |
2 * Transfers accelerator plugin for Orthanc | |
77
1e396fb509ca
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
33
diff
changeset
|
3 * Copyright (C) 2018-2023 Osimis S.A., Belgium |
1e396fb509ca
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
33
diff
changeset
|
4 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
1e396fb509ca
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
33
diff
changeset
|
5 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "TransferBucket.h" | |
23 | |
20 | 24 #include <Logging.h> |
25 #include <OrthancException.h> | |
0 | 26 |
27 | |
28 namespace OrthancPlugins | |
29 { | |
30 TransferBucket::TransferBucket() : | |
31 totalSize_(0), | |
32 extensible_(true) | |
33 { | |
34 } | |
35 | |
36 | |
37 TransferBucket::TransferBucket(const Json::Value& serialized) : | |
38 totalSize_(0), | |
39 extensible_(false) | |
40 { | |
41 if (serialized.type() != Json::arrayValue) | |
42 { | |
43 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
44 } | |
45 | |
46 chunks_.reserve(serialized.size()); | |
47 | |
48 for (Json::Value::ArrayIndex i = 0; i < serialized.size(); i++) | |
49 { | |
50 if (serialized[i].type() != Json::objectValue || | |
51 !serialized[i].isMember(KEY_ID) || | |
52 !serialized[i].isMember(KEY_OFFSET) || | |
53 !serialized[i].isMember(KEY_SIZE) || | |
54 serialized[i][KEY_ID].type() != Json::stringValue || | |
55 serialized[i][KEY_OFFSET].type() != Json::stringValue || | |
56 serialized[i][KEY_SIZE].type() != Json::stringValue) | |
57 { | |
58 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
59 } | |
60 else | |
61 { | |
62 try | |
63 { | |
64 Chunk chunk; | |
65 chunk.instanceId_ = serialized[i][KEY_ID].asString(); | |
66 chunk.offset_ = boost::lexical_cast<size_t>(serialized[i][KEY_OFFSET].asString()); | |
67 chunk.size_ = boost::lexical_cast<size_t>(serialized[i][KEY_SIZE].asString()); | |
68 | |
69 chunks_.push_back(chunk); | |
70 totalSize_ += chunk.size_; | |
71 } | |
72 catch (boost::bad_lexical_cast&) | |
73 { | |
74 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
75 } | |
76 } | |
77 } | |
78 } | |
79 | |
80 | |
81 void TransferBucket::Serialize(Json::Value& target) const | |
82 { | |
83 target = Json::arrayValue; | |
84 | |
85 for (size_t i = 0; i < chunks_.size(); i++) | |
86 { | |
87 Json::Value item = Json::objectValue; | |
88 item[KEY_ID] = chunks_[i].instanceId_; | |
89 item[KEY_OFFSET] = boost::lexical_cast<std::string>(chunks_[i].offset_); | |
90 item[KEY_SIZE] = boost::lexical_cast<std::string>(chunks_[i].size_); | |
91 target.append(item); | |
92 } | |
93 } | |
94 | |
95 void TransferBucket::Clear() | |
96 { | |
97 chunks_.clear(); | |
98 totalSize_ = 0; | |
99 extensible_ = true; | |
100 } | |
101 | |
102 | |
103 void TransferBucket::AddChunk(const DicomInstanceInfo& instance, | |
104 size_t chunkOffset, | |
105 size_t chunkSize) | |
106 { | |
107 if (chunkOffset + chunkSize > instance.GetSize()) | |
108 { | |
109 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
110 } | |
111 | |
112 if (!extensible_) | |
113 { | |
114 LOG(ERROR) << "Cannot add a new chunk after a truncated instance"; | |
115 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
116 } | |
117 | |
118 if (!chunks_.empty() && | |
119 chunkOffset != 0) | |
120 { | |
121 LOG(ERROR) << "Only the first chunk can have non-zero offset in a transfer bucket"; | |
122 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
123 } | |
124 | |
125 if (chunkSize == 0) | |
126 { | |
127 // Ignore empty chunks | |
128 return; | |
129 } | |
130 | |
131 if (!chunks_.empty() && | |
132 chunkSize != instance.GetSize()) | |
133 { | |
134 // Prevents adding new chunk after an incomplete instance | |
135 extensible_ = false; | |
136 } | |
137 | |
138 Chunk chunk; | |
139 chunk.instanceId_ = instance.GetId(); | |
140 chunk.offset_ = chunkOffset; | |
141 chunk.size_ = chunkSize; | |
142 | |
143 chunks_.push_back(chunk); | |
144 totalSize_ += chunkSize; | |
145 } | |
146 | |
147 | |
148 const std::string& TransferBucket::GetChunkInstanceId(size_t index) const | |
149 { | |
150 if (index >= chunks_.size()) | |
151 { | |
152 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
153 } | |
154 else | |
155 { | |
156 return chunks_[index].instanceId_; | |
157 } | |
158 } | |
159 | |
160 | |
161 size_t TransferBucket::GetChunkOffset(size_t index) const | |
162 { | |
163 if (index >= chunks_.size()) | |
164 { | |
165 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
166 } | |
167 else | |
168 { | |
169 return chunks_[index].offset_; | |
170 } | |
171 } | |
172 | |
173 | |
174 size_t TransferBucket::GetChunkSize(size_t index) const | |
175 { | |
176 if (index >= chunks_.size()) | |
177 { | |
178 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
179 } | |
180 else | |
181 { | |
182 return chunks_[index].size_; | |
183 } | |
184 } | |
185 | |
186 | |
187 void TransferBucket::ComputePullUri(std::string& uri, | |
188 BucketCompression compression) const | |
189 { | |
190 if (chunks_.empty()) | |
191 { | |
192 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
193 } | |
194 | |
195 bool first = true; | |
196 uri = std::string(URI_CHUNKS) + "/"; | |
197 | |
198 for (size_t i = 0; i < chunks_.size(); i++) | |
199 { | |
200 if (first) | |
201 { | |
202 first = false; | |
203 } | |
204 else | |
205 { | |
206 uri += "."; | |
207 } | |
208 | |
209 uri += chunks_[i].instanceId_; | |
210 | |
211 assert(i == 0 || chunks_[i].offset_ == 0); | |
212 } | |
213 | |
214 uri += ("?offset=" + boost::lexical_cast<std::string>(chunks_[0].offset_) + | |
215 "&size=" + boost::lexical_cast<std::string>(totalSize_)); | |
216 | |
217 switch (compression) | |
218 { | |
219 case BucketCompression_None: | |
220 uri += "&compression=none"; | |
221 break; | |
222 | |
223 case BucketCompression_Gzip: | |
224 uri += "&compression=gzip"; | |
225 break; | |
226 | |
227 default: | |
228 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
229 } | |
230 } | |
231 } |