mirror of
				https://github.com/boostorg/mqtt5.git
				synced 2025-11-04 09:51:37 +01:00 
			
		
		
		
	Summary: related to T13242 Reviewers: ivica Reviewed By: ivica Subscribers: miljen, iljazovic Differential Revision: https://repo.mireo.local/D26860
		
			
				
	
	
		
			297 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef ASYNC_MQTT5_MESSAGE_DECODERS_HPP
 | 
						|
#define ASYNC_MQTT5_MESSAGE_DECODERS_HPP
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#include <async_mqtt5/detail/internal_types.hpp>
 | 
						|
#include <async_mqtt5/impl/codecs/base_decoders.hpp>
 | 
						|
 | 
						|
namespace async_mqtt5::decoders {
 | 
						|
 | 
						|
using byte_citer = detail::byte_citer;
 | 
						|
 | 
						|
using fixed_header = std::tuple<
 | 
						|
	uint8_t, // control byte
 | 
						|
	uint32_t // remaining_length
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<fixed_header> decode_fixed_header(
 | 
						|
	byte_citer& it, const byte_citer last
 | 
						|
) {
 | 
						|
	auto fixed_header_ = x3::byte_ >> basic::varint_;
 | 
						|
	return type_parse(it, last, fixed_header_);
 | 
						|
}
 | 
						|
 | 
						|
using packet_id = uint16_t;
 | 
						|
 | 
						|
inline std::optional<packet_id> decode_packet_id(
 | 
						|
	byte_citer& it
 | 
						|
) {
 | 
						|
	auto packet_id_ = x3::big_word;
 | 
						|
	return type_parse(it, it + sizeof(uint16_t), packet_id_);
 | 
						|
}
 | 
						|
 | 
						|
using connect_message = std::tuple<
 | 
						|
	std::string, // client_id,
 | 
						|
	std::optional<std::string>, // user_name,
 | 
						|
	std::optional<std::string>, // password,
 | 
						|
	uint16_t, // keep_alive,
 | 
						|
	bool, // clean_start,
 | 
						|
	connect_props, // props,
 | 
						|
	std::optional<will> // will
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<connect_message> decode_connect(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto var_header_ =
 | 
						|
		basic::utf8_ >> // MQTT
 | 
						|
		x3::byte_ >> // (num 5)
 | 
						|
		x3::byte_ >> // conn_flags_
 | 
						|
		x3::big_word >> // keep_alive
 | 
						|
		prop::props_<connect_props>;
 | 
						|
 | 
						|
	const byte_citer end = it + remain_length;
 | 
						|
	auto vh = type_parse(it, end, var_header_);
 | 
						|
	if (!vh)
 | 
						|
		return std::optional<connect_message>{};
 | 
						|
 | 
						|
	auto& [mqtt_str, version, flags, keep_alive, cprops] = *vh;
 | 
						|
 | 
						|
	if (mqtt_str != "MQTT" || version != 5)
 | 
						|
		return std::optional<connect_message>{};
 | 
						|
 | 
						|
	bool has_will =  (flags & 0b00000100);
 | 
						|
	bool has_uname = (flags & 0b10000000);
 | 
						|
	bool has_pwd =   (flags & 0b01000000);
 | 
						|
 | 
						|
	auto payload_ =
 | 
						|
		basic::utf8_ >> // client_id
 | 
						|
		basic::if_(has_will)[prop::props_<will_props>] >>
 | 
						|
		basic::if_(has_will)[basic::utf8_] >> // will topic
 | 
						|
	 	basic::if_(has_will)[basic::binary_] >>  // will message
 | 
						|
		basic::if_(has_uname)[basic::utf8_] >> // username
 | 
						|
		basic::if_(has_pwd)[basic::utf8_]; // password
 | 
						|
 | 
						|
	auto pload = type_parse(it, end, payload_);
 | 
						|
	if (!pload)
 | 
						|
		return std::optional<connect_message>{};
 | 
						|
 | 
						|
	std::optional<will> w;
 | 
						|
 | 
						|
	if (has_will)
 | 
						|
		w.emplace(
 | 
						|
			std::move(*std::get<2>(*pload)), // will_topic
 | 
						|
			std::move(*std::get<3>(*pload)), // will_message
 | 
						|
			qos_e((flags & 0b00011000) >> 3),
 | 
						|
			retain_e((flags & 0b00100000) >> 5),
 | 
						|
			std::move(*std::get<1>(*pload)) // will props
 | 
						|
		);
 | 
						|
 | 
						|
	connect_message retval = {
 | 
						|
		std::move(std::get<0>(*pload)), // client_id
 | 
						|
		std::move(std::get<4>(*pload)), // user_name
 | 
						|
		std::move(std::get<5>(*pload)), // password
 | 
						|
		keep_alive,
 | 
						|
		flags & 0b00000010, // clean_start
 | 
						|
		std::move(cprops), // connect_props
 | 
						|
		std::move(w) // will
 | 
						|
	};
 | 
						|
 | 
						|
	return std::optional<connect_message> { std::move(retval) };
 | 
						|
}
 | 
						|
 | 
						|
using connack_message = std::tuple<
 | 
						|
	uint8_t, // session_present
 | 
						|
	uint8_t, // connect reason code
 | 
						|
	connack_props // props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<connack_message> decode_connack(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto connack_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> x3::byte_ >> prop::props_<connack_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, connack_);
 | 
						|
}
 | 
						|
 | 
						|
using publish_message = std::tuple<
 | 
						|
	std::string, // topic
 | 
						|
	std::optional<uint16_t>, // packet_id
 | 
						|
	uint8_t, // dup_e, qos_e, retain_e
 | 
						|
	publish_props, // publish props
 | 
						|
	std::string // payload
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<publish_message> decode_publish(
 | 
						|
	uint8_t control_byte, uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	uint8_t flags = control_byte & 0b1111;
 | 
						|
	auto qos = qos_e((flags >> 1) & 0b11);
 | 
						|
 | 
						|
	auto publish_ = basic::scope_limit_(remain_length)[
 | 
						|
		basic::utf8_ >> basic::if_(qos != qos_e::at_most_once)[x3::big_word] >>
 | 
						|
			x3::attr(flags) >> prop::props_<publish_props> >> basic::verbatim_
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, publish_);
 | 
						|
}
 | 
						|
 | 
						|
using puback_message = std::tuple<
 | 
						|
	uint8_t, // puback reason code
 | 
						|
	puback_props // props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<puback_message> decode_puback(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return puback_message {};
 | 
						|
	auto puback_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<puback_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, puback_);
 | 
						|
}
 | 
						|
 | 
						|
using pubrec_message = std::tuple<
 | 
						|
	uint8_t, // puback reason code
 | 
						|
	pubrec_props // props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<pubrec_message> decode_pubrec(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return pubrec_message {};
 | 
						|
	auto pubrec_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<pubrec_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, pubrec_);
 | 
						|
}
 | 
						|
 | 
						|
using pubrel_message = std::tuple<
 | 
						|
	uint8_t, // puback reason code
 | 
						|
	pubrel_props // props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<pubrel_message> decode_pubrel(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return pubrel_message {};
 | 
						|
	auto pubrel_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<pubrel_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, pubrel_);
 | 
						|
}
 | 
						|
 | 
						|
using pubcomp_message = std::tuple<
 | 
						|
	uint8_t, // puback reason code
 | 
						|
	pubcomp_props // props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<pubcomp_message> decode_pubcomp(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return pubcomp_message {};
 | 
						|
	auto pubcomp_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<pubcomp_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, pubcomp_);
 | 
						|
}
 | 
						|
 | 
						|
using subscribe_message = std::tuple<
 | 
						|
	subscribe_props,
 | 
						|
	std::vector<std::tuple<std::string, uint8_t>> // topic filter with opts
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<subscribe_message> decode_subscribe(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto subscribe_ = basic::scope_limit_(remain_length)[
 | 
						|
		prop::props_<subscribe_props> >> +(basic::utf8_ >> x3::byte_)
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, subscribe_);
 | 
						|
}
 | 
						|
 | 
						|
using suback_message = std::tuple<
 | 
						|
	suback_props,
 | 
						|
	std::vector<uint8_t> // reason_codes
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<suback_message> decode_suback(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto suback_ = basic::scope_limit_(remain_length)[
 | 
						|
		prop::props_<suback_props> >> +x3::byte_
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, suback_);
 | 
						|
}
 | 
						|
 | 
						|
using unsubscribe_message = std::tuple<
 | 
						|
	unsubscribe_props,
 | 
						|
	std::vector<std::string> // topics
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<unsubscribe_message> decode_unsubscribe(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto unsubscribe_ = basic::scope_limit_(remain_length)[
 | 
						|
		prop::props_<unsubscribe_props> >> +basic::utf8_
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, unsubscribe_);
 | 
						|
}
 | 
						|
 | 
						|
using unsuback_message = std::tuple<
 | 
						|
	unsuback_props,
 | 
						|
	std::vector<uint8_t> // reason_codes
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<unsuback_message> decode_unsuback(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	auto unsuback_ = basic::scope_limit_(remain_length)[
 | 
						|
		prop::props_<unsuback_props> >>	+x3::byte_
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, unsuback_);
 | 
						|
}
 | 
						|
 | 
						|
using disconnect_message = std::tuple<
 | 
						|
	uint8_t, // reason_code
 | 
						|
	disconnect_props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<disconnect_message> decode_disconnect(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return disconnect_message {};
 | 
						|
	auto disconnect_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<disconnect_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, disconnect_);
 | 
						|
}
 | 
						|
 | 
						|
using auth_message = std::tuple<
 | 
						|
	uint8_t, // reason_code
 | 
						|
	auth_props
 | 
						|
>;
 | 
						|
 | 
						|
inline std::optional<auth_message> decode_auth(
 | 
						|
	uint32_t remain_length, byte_citer& it
 | 
						|
) {
 | 
						|
	if (remain_length == 0)
 | 
						|
		return auth_message {};
 | 
						|
	auto auth_ = basic::scope_limit_(remain_length)[
 | 
						|
		x3::byte_ >> prop::props_<auth_props>
 | 
						|
	];
 | 
						|
	return type_parse(it, it + remain_length, auth_);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
} // end namespace async_mqtt5::decoders
 | 
						|
 | 
						|
#endif // !ASYNC_MQTT5_MESSAGE_DECODERS_HPP
 |