blob: d8f1fe85d6ad737d351e2016693463490254e00b [file] [log] [blame]
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Shuo Chenba793e92014-03-17 17:17:16 -07002/**
Alexander Afanasyev42290b22017-03-09 12:58:29 -08003 * Copyright (c) 2014-2017, Regents of the University of California.
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07004 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Shuo Chenba793e92014-03-17 17:17:16 -070018 */
19
Alexander Afanasyev39d98072014-05-04 12:46:29 -070020#ifndef REPO_REPO_COMMAND_RESPONSE_HPP
21#define REPO_REPO_COMMAND_RESPONSE_HPP
Shuo Chenba793e92014-03-17 17:17:16 -070022
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070023#include <ndn-cxx/encoding/block.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070024#include <ndn-cxx/encoding/block-helpers.hpp>
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070025#include <ndn-cxx/encoding/encoding-buffer.hpp>
26#include <ndn-cxx/encoding/tlv-nfd.hpp>
Shuo Chenba793e92014-03-17 17:17:16 -070027#include "repo-tlv.hpp"
28
29namespace repo {
30
31using ndn::Block;
32using ndn::EncodingImpl;
33using ndn::EncodingEstimator;
34using ndn::EncodingBuffer;
35
36/**
37* @brief Class defining abstraction of Response for NDN Repo Protocol
Alexander Afanasyev42290b22017-03-09 12:58:29 -080038* @sa link https://redmine.named-data.net/projects/repo-ng/wiki/Repo_Protocol_Specification#Repo-Command-Response
Shuo Chenba793e92014-03-17 17:17:16 -070039*/
40class RepoCommandResponse
41{
42public:
Junxiao Shica188d72014-10-19 09:49:40 -070043 class Error : public ndn::tlv::Error
Shuo Chenba793e92014-03-17 17:17:16 -070044 {
45 public:
46 explicit
47 Error(const std::string& what)
Junxiao Shica188d72014-10-19 09:49:40 -070048 : ndn::tlv::Error(what)
Shuo Chenba793e92014-03-17 17:17:16 -070049 {
50 }
51 };
52
53 RepoCommandResponse()
54 : m_hasStartBlockId(false)
55 , m_hasEndBlockId(false)
56 , m_hasProcessId(false)
57 , m_hasInsertNum(false)
58 , m_hasDeleteNum(false)
59 , m_hasStatusCode(false)
60 {
61 }
62
63 explicit
64 RepoCommandResponse(const Block& block)
65 {
66 wireDecode(block);
67 }
68
69 uint64_t
70 getStartBlockId() const
71 {
72 return m_startBlockId;
73 }
74
75 RepoCommandResponse&
76 setStartBlockId(uint64_t startBlockId)
77 {
78 m_startBlockId = startBlockId;
79 m_hasStartBlockId = true;
80 m_wire.reset();
81 return *this;
82 }
83
84 bool
85 hasStartBlockId() const
86 {
87 return m_hasStartBlockId;
88 }
89
90 uint64_t
91 getEndBlockId() const
92 {
93 assert(hasEndBlockId());
94 return m_endBlockId;
95 }
96
97 RepoCommandResponse&
98 setEndBlockId(uint64_t endBlockId)
99 {
100 m_endBlockId = endBlockId;
101 m_hasEndBlockId = true;
102 m_wire.reset();
103 return *this;
104 }
105
106 bool
107 hasEndBlockId() const
108 {
109 return m_hasEndBlockId;
110 }
111
112
113 uint64_t
114 getProcessId() const
115 {
116 return m_processId;
117 }
118
119 RepoCommandResponse&
120 setProcessId(uint64_t processId)
121 {
122 m_processId = processId;
123 m_hasProcessId = true;
124 m_wire.reset();
125 return *this;
126 }
127
128 bool
129 hasProcessId() const
130 {
131 return m_hasProcessId;
132 }
133
134 uint64_t
135 getStatusCode() const
136 {
137 return m_statusCode;
138 }
139
140 RepoCommandResponse&
141 setStatusCode(uint64_t statusCode)
142 {
143 m_statusCode = statusCode;
144 m_hasStatusCode = true;
145 m_wire.reset();
146 return *this;
147 }
148
149 bool
150 hasStatusCode() const
151 {
152 return m_hasStatusCode;
153 }
154
155 uint64_t
156 getInsertNum() const
157 {
158 return m_insertNum;
159 }
160
161 RepoCommandResponse&
162 setInsertNum(uint64_t insertNum)
163 {
164 m_insertNum = insertNum;
165 m_hasInsertNum = true;
166 m_wire.reset();
167 return *this;
168 }
169
170 bool
171 hasInsertNum() const
172 {
173 return m_hasInsertNum;
174 }
175
176 uint64_t
177 getDeleteNum() const
178 {
179 return m_deleteNum;
180 }
181
182 RepoCommandResponse&
183 setDeleteNum(uint64_t deleteNum)
184 {
185 m_deleteNum = deleteNum;
186 m_hasDeleteNum = true;
187 m_wire.reset();
188 return *this;
189 }
190
191 bool
192 hasDeleteNum() const
193 {
194 return m_hasDeleteNum;
195 }
196
197 template<bool T>
198 size_t
199 wireEncode(EncodingImpl<T>& block) const;
200
201 const Block&
202 wireEncode() const;
203
204 void
205 wireDecode(const Block& wire);
206
207private:
208 uint64_t m_statusCode;
209 uint64_t m_startBlockId;
210 uint64_t m_endBlockId;
211 uint64_t m_processId;
212 uint64_t m_insertNum;
213 uint64_t m_deleteNum;
214
215 bool m_hasStartBlockId;
216 bool m_hasEndBlockId;
217 bool m_hasProcessId;
218 bool m_hasInsertNum;
219 bool m_hasDeleteNum;
220 bool m_hasStatusCode;
221
222 mutable Block m_wire;
223};
224
225template<bool T>
226inline size_t
227RepoCommandResponse::wireEncode(EncodingImpl<T>& encoder) const
228{
229 size_t totalLength = 0;
230 size_t variableLength = 0;
231
232 if (m_hasDeleteNum) {
233 variableLength = encoder.prependNonNegativeInteger(m_deleteNum);
234 totalLength += variableLength;
235 totalLength += encoder.prependVarNumber(variableLength);
236 totalLength += encoder.prependVarNumber(tlv::DeleteNum);
237 }
238
239 if (m_hasInsertNum) {
240 variableLength = encoder.prependNonNegativeInteger(m_insertNum);
241 totalLength += variableLength;
242 totalLength += encoder.prependVarNumber(variableLength);
243 totalLength += encoder.prependVarNumber(tlv::InsertNum);
244 }
245
246 if (m_hasEndBlockId) {
247 variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
248 totalLength += variableLength;
249 totalLength += encoder.prependVarNumber(variableLength);
250 totalLength += encoder.prependVarNumber(tlv::EndBlockId);
251 }
252
253 if (m_hasStartBlockId) {
254 variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
255 totalLength += variableLength;
256 totalLength += encoder.prependVarNumber(variableLength);
257 totalLength += encoder.prependVarNumber(repo::tlv::StartBlockId);
258 }
259
260 if (m_hasStatusCode) {
261 variableLength = encoder.prependNonNegativeInteger(m_statusCode);
262 totalLength += variableLength;
263 totalLength += encoder.prependVarNumber(variableLength);
264 totalLength += encoder.prependVarNumber(tlv::StatusCode);
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800265 }
266 else {
267 BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
Shuo Chenba793e92014-03-17 17:17:16 -0700268 }
269
270 if (m_hasProcessId) {
271 variableLength = encoder.prependNonNegativeInteger(m_processId);
272 totalLength += variableLength;
273 totalLength += encoder.prependVarNumber(variableLength);
274 totalLength += encoder.prependVarNumber(tlv::ProcessId);
275 }
276
277 totalLength += encoder.prependVarNumber(totalLength);
278 totalLength += encoder.prependVarNumber(tlv::RepoCommandResponse);
279 return totalLength;
280}
281
282inline const Block&
283RepoCommandResponse::wireEncode() const
284{
285 if (m_wire.hasWire())
286 return m_wire;
287
288 EncodingEstimator estimator;
289 size_t estimatedSize = wireEncode(estimator);
290
291 EncodingBuffer buffer(estimatedSize, 0);
292 wireEncode(buffer);
293
294 m_wire = buffer.block();
295 return m_wire;
296}
297
298inline void
299RepoCommandResponse::wireDecode(const Block& wire)
300{
301 m_hasStartBlockId = false;
302 m_hasEndBlockId = false;
303 m_hasProcessId = false;
304 m_hasStatusCode = false;
305 m_hasInsertNum = false;
306 m_hasDeleteNum = false;
307
308 m_wire = wire;
309
310 m_wire.parse();
311
312 Block::element_const_iterator val;
313
314 if (m_wire.type() != tlv::RepoCommandResponse)
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800315 BOOST_THROW_EXCEPTION(Error("RepoCommandResponse malformed"));
Shuo Chenba793e92014-03-17 17:17:16 -0700316
317 // StartBlockId
318 val = m_wire.find(tlv::StartBlockId);
319 if (val != m_wire.elements_end())
320 {
321 m_hasStartBlockId = true;
322 m_startBlockId = readNonNegativeInteger(*val);
323 }
324
325 // EndBlockId
326 val = m_wire.find(tlv::EndBlockId);
327 if (val != m_wire.elements_end())
328 {
329 m_hasEndBlockId = true;
330 m_endBlockId = readNonNegativeInteger(*val);
331 }
332
333 // ProcessId
334 val = m_wire.find(tlv::ProcessId);
335 if (val != m_wire.elements_end())
336 {
337 m_hasProcessId = true;
338 m_processId = readNonNegativeInteger(*val);
339 }
340
341 // StatusCode
342 val = m_wire.find(tlv::StatusCode);
343 if (val != m_wire.elements_end())
344 {
345 m_hasStatusCode = true;
346 m_statusCode = readNonNegativeInteger(*val);
347
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800348 }
349 else {
350 BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
Shuo Chenba793e92014-03-17 17:17:16 -0700351 }
352
353 // InsertNum
354 val = m_wire.find(tlv::InsertNum);
355 if (val != m_wire.elements_end())
356 {
357 m_hasInsertNum = true;
358 m_insertNum = readNonNegativeInteger(*val);
359 }
360
361 // DeleteNum
362 val = m_wire.find(tlv::DeleteNum);
363 if (val != m_wire.elements_end())
364 {
365 m_hasDeleteNum = true;
366 m_deleteNum = readNonNegativeInteger(*val);
367 }
368}
369
370inline std::ostream&
371operator<<(std::ostream& os, const RepoCommandResponse& repoCommandResponse)
372{
373 os << "RepoCommandResponse(";
374
375 if (repoCommandResponse.hasProcessId()) {
376 os << " ProcessId: " << repoCommandResponse.getProcessId();
377 }
378 if (repoCommandResponse.hasStatusCode()) {
379 os << " StatusCode: " << repoCommandResponse.getStatusCode();
380 }
381 if (repoCommandResponse.hasStartBlockId()) {
382 os << " StartBlockId: " << repoCommandResponse.getStartBlockId();
383 }
384 if (repoCommandResponse.hasEndBlockId()) {
385 os << " EndBlockId: " << repoCommandResponse.getEndBlockId();
386 }
387 if (repoCommandResponse.hasInsertNum()) {
388 os << " InsertNum: " << repoCommandResponse.getInsertNum();
389 }
390 if (repoCommandResponse.hasDeleteNum()) {
391 os << " DeleteNum: " << repoCommandResponse.getDeleteNum();
392
393 }
394 os << " )";
395 return os;
396}
Alexander Afanasyev39d98072014-05-04 12:46:29 -0700397
398} // namespace repo
399
400#endif // REPO_REPO_COMMAND_RESPONSE_HPP