async_mqtt 5.0.0
Loading...
Searching...
No Matches
v5_pubcomp.hpp
1// Copyright Takatoshi Kondo 2022
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#if !defined(ASYNC_MQTT_PACKET_V5_PUBCOMP_HPP)
8#define ASYNC_MQTT_PACKET_V5_PUBCOMP_HPP
9
10#include <utility>
11#include <numeric>
12
13#include <boost/numeric/conversion/cast.hpp>
14
15#include <async_mqtt/exception.hpp>
16#include <async_mqtt/buffer.hpp>
17
18#include <async_mqtt/util/move.hpp>
19#include <async_mqtt/util/static_vector.hpp>
20#include <async_mqtt/util/endian_convert.hpp>
21#include <async_mqtt/util/scope_guard.hpp>
22
23#include <async_mqtt/packet/fixed_header.hpp>
24#include <async_mqtt/packet/packet_id_type.hpp>
25#include <async_mqtt/packet/reason_code.hpp>
26#include <async_mqtt/packet/property_variant.hpp>
27#include <async_mqtt/packet/copy_to_static_vector.hpp>
28
29namespace async_mqtt::v5 {
30
31namespace as = boost::asio;
32
43template <std::size_t PacketIdBytes>
45public:
46 using packet_id_t = typename packet_id_type<PacketIdBytes>::type;
47
57 packet_id_t packet_id,
58 pubcomp_reason_code reason_code,
59 properties props
62 optional<pubcomp_reason_code>(reason_code),
63 force_move(props)
64 }
65 {}
66
72 packet_id_t packet_id
75 nullopt,
76 properties{}
77 }
78 {}
79
87 packet_id_t packet_id,
88 pubcomp_reason_code reason_code
91 optional<pubcomp_reason_code>(reason_code),
92 properties{}
93 }
94 {}
95
97 // fixed_header
98 if (buf.empty()) {
99 throw make_error(
100 errc::bad_message,
101 "v5::pubcomp_packet fixed_header doesn't exist"
102 );
103 }
104 fixed_header_ = static_cast<std::uint8_t>(buf.front());
105 buf.remove_prefix(1);
106
107 // remaining_length
108 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
109 remaining_length_ = *vl_opt;
110 }
111 else {
112 throw make_error(errc::bad_message, "v5::pubcomp_packet remaining length is invalid");
113 }
114
115 // packet_id
116 if (!insert_advance(buf, packet_id_)) {
117 throw make_error(
118 errc::bad_message,
119 "v5::pubcomp_packet packet_id doesn't exist"
120 );
121 }
122
123 if (remaining_length_ == PacketIdBytes) {
124 if (!buf.empty()) {
125 throw make_error(errc::bad_message, "v5::pubcomp_packet remaining length is invalid");
126 }
127 return;
128 }
129
130 // reason_code
131 reason_code_.emplace(static_cast<pubcomp_reason_code>(buf.front()));
132 buf.remove_prefix(1);
133 switch (*reason_code_) {
134 case pubcomp_reason_code::success:
135 case pubcomp_reason_code::packet_identifier_not_found:
136 break;
137 default:
138 throw make_error(
139 errc::bad_message,
140 "v5::pubcomp_packet connect reason_code is invalid"
141 );
142 break;
143 }
144
145 if (remaining_length_ == 3) {
146 if (!buf.empty()) {
147 throw make_error(errc::bad_message, "v5::pubcomp_packet remaining length is invalid");
148 }
149 return;
150 }
151
152 // property
153 auto it = buf.begin();
154 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
155 property_length_ = *pl_opt;
156 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
157 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
158 if (buf.size() < property_length_) {
159 throw make_error(
160 errc::bad_message,
161 "v5::pubcomp_packet properties_don't match its length"
162 );
163 }
164 auto prop_buf = buf.substr(0, property_length_);
165 props_ = make_properties(prop_buf, property_location::pubcomp);
166 buf.remove_prefix(property_length_);
167 }
168 else {
169 throw make_error(
170 errc::bad_message,
171 "v5::pubcomp_packet property_length is invalid"
172 );
173 }
174
175 if (!buf.empty()) {
176 throw make_error(
177 errc::bad_message,
178 "v5::pubcomp_packet properties don't match its length"
179 );
180 }
181 }
182
183 constexpr control_packet_type type() const {
184 return control_packet_type::pubcomp;
185 }
186
192 std::vector<as::const_buffer> const_buffer_sequence() const {
193 std::vector<as::const_buffer> ret;
195 ret.emplace_back(as::buffer(&fixed_header_, 1));
196 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
197
198 ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
199
200 if (reason_code_) {
201 ret.emplace_back(as::buffer(&*reason_code_, 1));
202
203 if (property_length_buf_.size() != 0) {
204 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
205 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
206 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
207 }
208 }
209
210 return ret;
211 }
212
217 std::size_t size() const {
218 return
219 1 + // fixed header
220 remaining_length_buf_.size() +
221 remaining_length_;
222 }
223
228 constexpr std::size_t num_of_const_buffer_sequence() const {
229 return
230 1 + // fixed header
231 1 + // remaining length
232 1 + // packet_id
233 [&] () -> std::size_t {
234 if (reason_code_) {
235 return
236 1 + // reason_code
237 [&] () -> std::size_t {
238 if (property_length_buf_.size() == 0) return 0;
239 return
240 1 + // property length
241 async_mqtt::num_of_const_buffer_sequence(props_);
242 }();
243 }
244 return 0;
245 }();
246 }
247
252 packet_id_t packet_id() const {
253 return endian_load<packet_id_t>(packet_id_.data());
254 }
255
260 pubcomp_reason_code code() const {
261 if (reason_code_) return *reason_code_;
262 return pubcomp_reason_code::success;
263 }
264
269 properties const& props() const {
270 return props_;
271 }
272
273 friend
274 inline std::ostream& operator<<(std::ostream& o, basic_pubcomp_packet<PacketIdBytes> const& v) {
275 o <<
276 "v5::pubcomp{" <<
277 "pid:" << v.packet_id();
278 if (v.reason_code_) {
279 o << ",rc:" << *v.reason_code_;
280 }
281 if (!v.props().empty()) {
282 o << ",ps:" << v.props();
283 };
284 o << "}";
285 return o;
286 }
287
288private:
290 packet_id_t packet_id,
291 optional<pubcomp_reason_code> reason_code,
292 properties props
293 )
294 : fixed_header_{
295 make_fixed_header(control_packet_type::pubcomp, 0b0000)
296 },
297 remaining_length_{
298 PacketIdBytes
299 },
300 packet_id_(packet_id_.capacity()),
301 reason_code_{reason_code},
302 property_length_(async_mqtt::size(props)),
303 props_(force_move(props))
304 {
305 using namespace std::literals;
306 endian_store(packet_id, packet_id_.data());
307
308 auto guard = unique_scope_guard(
309 [&] {
310 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
311 for (auto e : rb) {
312 remaining_length_buf_.push_back(e);
313 }
314 }
315 );
316
317 if (!reason_code_) return;
318 remaining_length_ += 1;
319
320 if (property_length_ == 0) return;
321
322 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
323 for (auto e : pb) {
324 property_length_buf_.push_back(e);
325 }
326
327 for (auto const& prop : props_) {
328 auto id = prop.id();
329 if (!validate_property(property_location::pubcomp, id)) {
330 throw make_error(
331 errc::bad_message,
332 "v5::pubcomp_packet property "s + id_to_str(id) + " is not allowed"
333 );
334 }
335 }
336
337 remaining_length_ += property_length_buf_.size() + property_length_;
338 }
339
340private:
341 std::uint8_t fixed_header_;
342 std::size_t remaining_length_;
343 static_vector<char, 4> remaining_length_buf_;
344 static_vector<char, PacketIdBytes> packet_id_;
345
346 optional<pubcomp_reason_code> reason_code_;
347
348 std::size_t property_length_ = 0;
349 static_vector<char, 4> property_length_buf_;
350 properties props_;
351};
352
353using pubcomp_packet = basic_pubcomp_packet<2>;
354
355} // namespace async_mqtt::v5
356
357#endif // ASYNC_MQTT_PACKET_V5_PUBCOMP_HPP
Definition packet_variant.hpp:49
buffer that has string_view interface This class provides string_view interface. This class hold stri...
Definition buffer.hpp:30
buffer substr(size_type pos=0, size_type count=npos) const &
get substring The returned buffer ragnge is the same as string_view::substr(). In addition the lifeti...
Definition buffer.hpp:201
MQTT PUBCOMP packet (v5)
Definition v5_pubcomp.hpp:44
basic_pubcomp_packet(packet_id_t packet_id)
constructor
Definition v5_pubcomp.hpp:71
pubcomp_reason_code code() const
Definition v5_pubcomp.hpp:260
properties const & props() const
Definition v5_pubcomp.hpp:269
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_pubcomp.hpp:228
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_pubcomp.hpp:192
basic_pubcomp_packet(packet_id_t packet_id, pubcomp_reason_code reason_code, properties props)
constructor
Definition v5_pubcomp.hpp:56
packet_id_t packet_id() const
Get packet_id.
Definition v5_pubcomp.hpp:252
std::size_t size() const
Get packet size.
Definition v5_pubcomp.hpp:217
basic_pubcomp_packet(packet_id_t packet_id, pubcomp_reason_code reason_code)
constructor
Definition v5_pubcomp.hpp:86