comparison Framework/TransferBucket.cpp @ 0:95226b754d9e

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