blob: b07d8943e6a341de86fcab3002cae109b2400b94 [file] [log] [blame]
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevc0e26582017-08-13 21:16:49 -04002/*
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 Afanasyevc0e26582017-08-13 21:16:49 -040023#include "repo-tlv.hpp"
24
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070025#include <ndn-cxx/encoding/block.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070026#include <ndn-cxx/encoding/block-helpers.hpp>
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070027#include <ndn-cxx/encoding/encoding-buffer.hpp>
28#include <ndn-cxx/encoding/tlv-nfd.hpp>
Shuo Chenba793e92014-03-17 17:17:16 -070029
30namespace repo {
31
32using ndn::Block;
33using ndn::EncodingImpl;
34using ndn::EncodingEstimator;
35using ndn::EncodingBuffer;
36
37/**
38* @brief Class defining abstraction of Response for NDN Repo Protocol
Alexander Afanasyev42290b22017-03-09 12:58:29 -080039* @sa link https://redmine.named-data.net/projects/repo-ng/wiki/Repo_Protocol_Specification#Repo-Command-Response
Shuo Chenba793e92014-03-17 17:17:16 -070040*/
41class RepoCommandResponse
42{
43public:
Junxiao Shica188d72014-10-19 09:49:40 -070044 class Error : public ndn::tlv::Error
Shuo Chenba793e92014-03-17 17:17:16 -070045 {
46 public:
47 explicit
48 Error(const std::string& what)
Junxiao Shica188d72014-10-19 09:49:40 -070049 : ndn::tlv::Error(what)
Shuo Chenba793e92014-03-17 17:17:16 -070050 {
51 }
52 };
53
54 RepoCommandResponse()
55 : m_hasStartBlockId(false)
56 , m_hasEndBlockId(false)
57 , m_hasProcessId(false)
58 , m_hasInsertNum(false)
59 , m_hasDeleteNum(false)
60 , m_hasStatusCode(false)
61 {
62 }
63
64 explicit
65 RepoCommandResponse(const Block& block)
66 {
67 wireDecode(block);
68 }
69
70 uint64_t
71 getStartBlockId() const
72 {
73 return m_startBlockId;
74 }
75
76 RepoCommandResponse&
77 setStartBlockId(uint64_t startBlockId)
78 {
79 m_startBlockId = startBlockId;
80 m_hasStartBlockId = true;
81 m_wire.reset();
82 return *this;
83 }
84
85 bool
86 hasStartBlockId() const
87 {
88 return m_hasStartBlockId;
89 }
90
91 uint64_t
92 getEndBlockId() const
93 {
94 assert(hasEndBlockId());
95 return m_endBlockId;
96 }
97
98 RepoCommandResponse&
99 setEndBlockId(uint64_t endBlockId)
100 {
101 m_endBlockId = endBlockId;
102 m_hasEndBlockId = true;
103 m_wire.reset();
104 return *this;
105 }
106
107 bool
108 hasEndBlockId() const
109 {
110 return m_hasEndBlockId;
111 }
112
113
114 uint64_t
115 getProcessId() const
116 {
117 return m_processId;
118 }
119
120 RepoCommandResponse&
121 setProcessId(uint64_t processId)
122 {
123 m_processId = processId;
124 m_hasProcessId = true;
125 m_wire.reset();
126 return *this;
127 }
128
129 bool
130 hasProcessId() const
131 {
132 return m_hasProcessId;
133 }
134
135 uint64_t
136 getStatusCode() const
137 {
138 return m_statusCode;
139 }
140
141 RepoCommandResponse&
142 setStatusCode(uint64_t statusCode)
143 {
144 m_statusCode = statusCode;
145 m_hasStatusCode = true;
146 m_wire.reset();
147 return *this;
148 }
149
150 bool
151 hasStatusCode() const
152 {
153 return m_hasStatusCode;
154 }
155
156 uint64_t
157 getInsertNum() const
158 {
159 return m_insertNum;
160 }
161
162 RepoCommandResponse&
163 setInsertNum(uint64_t insertNum)
164 {
165 m_insertNum = insertNum;
166 m_hasInsertNum = true;
167 m_wire.reset();
168 return *this;
169 }
170
171 bool
172 hasInsertNum() const
173 {
174 return m_hasInsertNum;
175 }
176
177 uint64_t
178 getDeleteNum() const
179 {
180 return m_deleteNum;
181 }
182
183 RepoCommandResponse&
184 setDeleteNum(uint64_t deleteNum)
185 {
186 m_deleteNum = deleteNum;
187 m_hasDeleteNum = true;
188 m_wire.reset();
189 return *this;
190 }
191
192 bool
193 hasDeleteNum() const
194 {
195 return m_hasDeleteNum;
196 }
197
Alexander Afanasyevc0e26582017-08-13 21:16:49 -0400198 template<ndn::encoding::Tag T>
Shuo Chenba793e92014-03-17 17:17:16 -0700199 size_t
200 wireEncode(EncodingImpl<T>& block) const;
201
202 const Block&
203 wireEncode() const;
204
205 void
206 wireDecode(const Block& wire);
207
208private:
209 uint64_t m_statusCode;
210 uint64_t m_startBlockId;
211 uint64_t m_endBlockId;
212 uint64_t m_processId;
213 uint64_t m_insertNum;
214 uint64_t m_deleteNum;
215
216 bool m_hasStartBlockId;
217 bool m_hasEndBlockId;
218 bool m_hasProcessId;
219 bool m_hasInsertNum;
220 bool m_hasDeleteNum;
221 bool m_hasStatusCode;
222
223 mutable Block m_wire;
224};
225
Alexander Afanasyevc0e26582017-08-13 21:16:49 -0400226template<ndn::encoding::Tag T>
Shuo Chenba793e92014-03-17 17:17:16 -0700227inline size_t
228RepoCommandResponse::wireEncode(EncodingImpl<T>& encoder) const
229{
230 size_t totalLength = 0;
231 size_t variableLength = 0;
232
233 if (m_hasDeleteNum) {
234 variableLength = encoder.prependNonNegativeInteger(m_deleteNum);
235 totalLength += variableLength;
236 totalLength += encoder.prependVarNumber(variableLength);
237 totalLength += encoder.prependVarNumber(tlv::DeleteNum);
238 }
239
240 if (m_hasInsertNum) {
241 variableLength = encoder.prependNonNegativeInteger(m_insertNum);
242 totalLength += variableLength;
243 totalLength += encoder.prependVarNumber(variableLength);
244 totalLength += encoder.prependVarNumber(tlv::InsertNum);
245 }
246
247 if (m_hasEndBlockId) {
248 variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
249 totalLength += variableLength;
250 totalLength += encoder.prependVarNumber(variableLength);
251 totalLength += encoder.prependVarNumber(tlv::EndBlockId);
252 }
253
254 if (m_hasStartBlockId) {
255 variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
256 totalLength += variableLength;
257 totalLength += encoder.prependVarNumber(variableLength);
258 totalLength += encoder.prependVarNumber(repo::tlv::StartBlockId);
259 }
260
261 if (m_hasStatusCode) {
262 variableLength = encoder.prependNonNegativeInteger(m_statusCode);
263 totalLength += variableLength;
264 totalLength += encoder.prependVarNumber(variableLength);
265 totalLength += encoder.prependVarNumber(tlv::StatusCode);
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800266 }
267 else {
268 BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
Shuo Chenba793e92014-03-17 17:17:16 -0700269 }
270
271 if (m_hasProcessId) {
272 variableLength = encoder.prependNonNegativeInteger(m_processId);
273 totalLength += variableLength;
274 totalLength += encoder.prependVarNumber(variableLength);
275 totalLength += encoder.prependVarNumber(tlv::ProcessId);
276 }
277
278 totalLength += encoder.prependVarNumber(totalLength);
279 totalLength += encoder.prependVarNumber(tlv::RepoCommandResponse);
280 return totalLength;
281}
282
283inline const Block&
284RepoCommandResponse::wireEncode() const
285{
286 if (m_wire.hasWire())
287 return m_wire;
288
289 EncodingEstimator estimator;
290 size_t estimatedSize = wireEncode(estimator);
291
292 EncodingBuffer buffer(estimatedSize, 0);
293 wireEncode(buffer);
294
295 m_wire = buffer.block();
296 return m_wire;
297}
298
299inline void
300RepoCommandResponse::wireDecode(const Block& wire)
301{
302 m_hasStartBlockId = false;
303 m_hasEndBlockId = false;
304 m_hasProcessId = false;
305 m_hasStatusCode = false;
306 m_hasInsertNum = false;
307 m_hasDeleteNum = false;
308
309 m_wire = wire;
310
311 m_wire.parse();
312
313 Block::element_const_iterator val;
314
315 if (m_wire.type() != tlv::RepoCommandResponse)
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800316 BOOST_THROW_EXCEPTION(Error("RepoCommandResponse malformed"));
Shuo Chenba793e92014-03-17 17:17:16 -0700317
318 // StartBlockId
319 val = m_wire.find(tlv::StartBlockId);
320 if (val != m_wire.elements_end())
321 {
322 m_hasStartBlockId = true;
323 m_startBlockId = readNonNegativeInteger(*val);
324 }
325
326 // EndBlockId
327 val = m_wire.find(tlv::EndBlockId);
328 if (val != m_wire.elements_end())
329 {
330 m_hasEndBlockId = true;
331 m_endBlockId = readNonNegativeInteger(*val);
332 }
333
334 // ProcessId
335 val = m_wire.find(tlv::ProcessId);
336 if (val != m_wire.elements_end())
337 {
338 m_hasProcessId = true;
339 m_processId = readNonNegativeInteger(*val);
340 }
341
342 // StatusCode
343 val = m_wire.find(tlv::StatusCode);
344 if (val != m_wire.elements_end())
345 {
346 m_hasStatusCode = true;
347 m_statusCode = readNonNegativeInteger(*val);
348
Alexander Afanasyev42290b22017-03-09 12:58:29 -0800349 }
350 else {
351 BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
Shuo Chenba793e92014-03-17 17:17:16 -0700352 }
353
354 // InsertNum
355 val = m_wire.find(tlv::InsertNum);
356 if (val != m_wire.elements_end())
357 {
358 m_hasInsertNum = true;
359 m_insertNum = readNonNegativeInteger(*val);
360 }
361
362 // DeleteNum
363 val = m_wire.find(tlv::DeleteNum);
364 if (val != m_wire.elements_end())
365 {
366 m_hasDeleteNum = true;
367 m_deleteNum = readNonNegativeInteger(*val);
368 }
369}
370
371inline std::ostream&
372operator<<(std::ostream& os, const RepoCommandResponse& repoCommandResponse)
373{
374 os << "RepoCommandResponse(";
375
376 if (repoCommandResponse.hasProcessId()) {
377 os << " ProcessId: " << repoCommandResponse.getProcessId();
378 }
379 if (repoCommandResponse.hasStatusCode()) {
380 os << " StatusCode: " << repoCommandResponse.getStatusCode();
381 }
382 if (repoCommandResponse.hasStartBlockId()) {
383 os << " StartBlockId: " << repoCommandResponse.getStartBlockId();
384 }
385 if (repoCommandResponse.hasEndBlockId()) {
386 os << " EndBlockId: " << repoCommandResponse.getEndBlockId();
387 }
388 if (repoCommandResponse.hasInsertNum()) {
389 os << " InsertNum: " << repoCommandResponse.getInsertNum();
390 }
391 if (repoCommandResponse.hasDeleteNum()) {
392 os << " DeleteNum: " << repoCommandResponse.getDeleteNum();
393
394 }
395 os << " )";
396 return os;
397}
Alexander Afanasyev39d98072014-05-04 12:46:29 -0700398
399} // namespace repo
400
401#endif // REPO_REPO_COMMAND_RESPONSE_HPP