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