feature(properties): add properties in message header
1. Add MQTT5.0 properties when invoking the hooks. - Add a new key `properties` into the message header: We used to put all of the properties into the `#message.headers`: ```erlang #message{headers = #{'User-Property' => {<<"reason">>,<<"normal">>}, 'Message-Expiry-Interval' => 60, allow_publish => true} ``` I put them instead under a single key: ```erlang #message{headers = #{properties => #{'User-Property' => {<<"reason">>,<<"normal">>}, 'Message-Expiry-Interval' => 60}, allow_publish => true} ``` Note that the column `properties` may contain all the properties for Publish and Will messages. - Add `disconn_props` into the `Channel.conninfo` - Add `puback_props` also into the message header: ```erlang #message{headers = #{puback_props => #{'User-Property' => {<<"reason">>,<<"normal">>}}, allow_publish => true} ``` 2. Change the data type of `#message.headers` and `#message.flags` to map. It used to support `undefined`.
This commit is contained in:
parent
a05c411566
commit
6ad65d587e
|
@ -62,13 +62,15 @@
|
||||||
%% Message from
|
%% Message from
|
||||||
from :: atom() | binary(),
|
from :: atom() | binary(),
|
||||||
%% Message flags
|
%% Message flags
|
||||||
flags :: #{atom() => boolean()},
|
flags = #{} :: emqx_types:flags(),
|
||||||
%% Message headers, or MQTT 5.0 Properties
|
%% Message headers. May contain any metadata. e.g. the
|
||||||
headers :: map(),
|
%% protocol version number, username, peerhost or
|
||||||
|
%% the PUBLISH properties (MQTT 5.0).
|
||||||
|
headers = #{} :: emqx_types:headers(),
|
||||||
%% Topic that the message is published to
|
%% Topic that the message is published to
|
||||||
topic :: binary(),
|
topic :: emqx_types:topic(),
|
||||||
%% Message Payload
|
%% Message Payload
|
||||||
payload :: binary(),
|
payload :: emqx_types:payload(),
|
||||||
%% Timestamp (Unit: millisecond)
|
%% Timestamp (Unit: millisecond)
|
||||||
timestamp :: integer()
|
timestamp :: integer()
|
||||||
}).
|
}).
|
||||||
|
|
|
@ -219,9 +219,9 @@
|
||||||
will_qos = ?QOS_0,
|
will_qos = ?QOS_0,
|
||||||
will_retain = false,
|
will_retain = false,
|
||||||
keepalive = 0,
|
keepalive = 0,
|
||||||
properties = undefined,
|
properties = #{},
|
||||||
clientid = <<>>,
|
clientid = <<>>,
|
||||||
will_props = undefined,
|
will_props = #{},
|
||||||
will_topic = undefined,
|
will_topic = undefined,
|
||||||
will_payload = undefined,
|
will_payload = undefined,
|
||||||
username = undefined,
|
username = undefined,
|
||||||
|
@ -231,53 +231,53 @@
|
||||||
-record(mqtt_packet_connack, {
|
-record(mqtt_packet_connack, {
|
||||||
ack_flags,
|
ack_flags,
|
||||||
reason_code,
|
reason_code,
|
||||||
properties
|
properties = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_publish, {
|
-record(mqtt_packet_publish, {
|
||||||
topic_name,
|
topic_name,
|
||||||
packet_id,
|
packet_id,
|
||||||
properties
|
properties = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_puback, {
|
-record(mqtt_packet_puback, {
|
||||||
packet_id,
|
packet_id,
|
||||||
reason_code,
|
reason_code,
|
||||||
properties
|
properties = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_subscribe, {
|
-record(mqtt_packet_subscribe, {
|
||||||
packet_id,
|
packet_id,
|
||||||
properties,
|
properties = #{},
|
||||||
topic_filters
|
topic_filters
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_suback, {
|
-record(mqtt_packet_suback, {
|
||||||
packet_id,
|
packet_id,
|
||||||
properties,
|
properties = #{},
|
||||||
reason_codes
|
reason_codes
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_unsubscribe, {
|
-record(mqtt_packet_unsubscribe, {
|
||||||
packet_id,
|
packet_id,
|
||||||
properties,
|
properties = #{},
|
||||||
topic_filters
|
topic_filters
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_unsuback, {
|
-record(mqtt_packet_unsuback, {
|
||||||
packet_id,
|
packet_id,
|
||||||
properties,
|
properties = #{},
|
||||||
reason_codes
|
reason_codes
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_disconnect, {
|
-record(mqtt_packet_disconnect, {
|
||||||
reason_code,
|
reason_code,
|
||||||
properties
|
properties = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(mqtt_packet_auth, {
|
-record(mqtt_packet_auth, {
|
||||||
reason_code,
|
reason_code,
|
||||||
properties
|
properties = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -171,9 +171,10 @@ encode_alarm({AlarmId, AlarmDesc}) ->
|
||||||
}).
|
}).
|
||||||
|
|
||||||
alarm_msg(Topic, Payload) ->
|
alarm_msg(Topic, Payload) ->
|
||||||
Msg = emqx_message:make(?MODULE, Topic, Payload),
|
emqx_message:make(?MODULE, 0, Topic, Payload,
|
||||||
emqx_message:set_headers(#{'Content-Type' => <<"application/json">>},
|
#{sys => true},
|
||||||
emqx_message:set_flag(sys, Msg)).
|
#{properties => #{'Content-Type' => <<"application/json">>}}
|
||||||
|
).
|
||||||
|
|
||||||
topic(alert) ->
|
topic(alert) ->
|
||||||
emqx_topic:systop(<<"alarms/alert">>);
|
emqx_topic:systop(<<"alarms/alert">>);
|
||||||
|
|
|
@ -281,14 +281,14 @@ handle_in(Packet = ?PUBLISH_PACKET(_QoS), Channel) ->
|
||||||
handle_out(disconnect, ReasonCode, Channel)
|
handle_out(disconnect, ReasonCode, Channel)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_in(?PUBACK_PACKET(PacketId, _ReasonCode), Channel
|
handle_in(?PUBACK_PACKET(PacketId, _ReasonCode, Properties), Channel
|
||||||
= #channel{clientinfo = ClientInfo, session = Session}) ->
|
= #channel{clientinfo = ClientInfo, session = Session}) ->
|
||||||
case emqx_session:puback(PacketId, Session) of
|
case emqx_session:puback(PacketId, Session) of
|
||||||
{ok, Msg, NSession} ->
|
{ok, Msg, NSession} ->
|
||||||
ok = after_message_acked(ClientInfo, Msg),
|
ok = after_message_acked(ClientInfo, Msg, Properties),
|
||||||
{ok, Channel#channel{session = NSession}};
|
{ok, Channel#channel{session = NSession}};
|
||||||
{ok, Msg, Publishes, NSession} ->
|
{ok, Msg, Publishes, NSession} ->
|
||||||
ok = after_message_acked(ClientInfo, Msg),
|
ok = after_message_acked(ClientInfo, Msg, Properties),
|
||||||
handle_out(publish, Publishes, Channel#channel{session = NSession});
|
handle_out(publish, Publishes, Channel#channel{session = NSession});
|
||||||
{error, ?RC_PACKET_IDENTIFIER_IN_USE} ->
|
{error, ?RC_PACKET_IDENTIFIER_IN_USE} ->
|
||||||
?LOG(warning, "The PUBACK PacketId ~w is inuse.", [PacketId]),
|
?LOG(warning, "The PUBACK PacketId ~w is inuse.", [PacketId]),
|
||||||
|
@ -300,11 +300,11 @@ handle_in(?PUBACK_PACKET(PacketId, _ReasonCode), Channel
|
||||||
{ok, Channel}
|
{ok, Channel}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_in(?PUBREC_PACKET(PacketId, _ReasonCode), Channel
|
handle_in(?PUBREC_PACKET(PacketId, _ReasonCode, Properties), Channel
|
||||||
= #channel{clientinfo = ClientInfo, session = Session}) ->
|
= #channel{clientinfo = ClientInfo, session = Session}) ->
|
||||||
case emqx_session:pubrec(PacketId, Session) of
|
case emqx_session:pubrec(PacketId, Session) of
|
||||||
{ok, Msg, NSession} ->
|
{ok, Msg, NSession} ->
|
||||||
ok = after_message_acked(ClientInfo, Msg),
|
ok = after_message_acked(ClientInfo, Msg, Properties),
|
||||||
NChannel = Channel#channel{session = NSession},
|
NChannel = Channel#channel{session = NSession},
|
||||||
handle_out(pubrel, {PacketId, ?RC_SUCCESS}, NChannel);
|
handle_out(pubrel, {PacketId, ?RC_SUCCESS}, NChannel);
|
||||||
{error, RC = ?RC_PACKET_IDENTIFIER_IN_USE} ->
|
{error, RC = ?RC_PACKET_IDENTIFIER_IN_USE} ->
|
||||||
|
@ -347,12 +347,12 @@ handle_in(Packet = ?SUBSCRIBE_PACKET(PacketId, Properties, TopicFilters),
|
||||||
Channel = #channel{clientinfo = ClientInfo = #{zone := Zone}}) ->
|
Channel = #channel{clientinfo = ClientInfo = #{zone := Zone}}) ->
|
||||||
case emqx_packet:check(Packet) of
|
case emqx_packet:check(Packet) of
|
||||||
ok -> TopicFilters1 = parse_topic_filters(TopicFilters),
|
ok -> TopicFilters1 = parse_topic_filters(TopicFilters),
|
||||||
TopicFilters2 = enrich_subid(Properties, TopicFilters1),
|
TopicFilters2 = put_subid_in_subopts(Properties, TopicFilters1),
|
||||||
TopicFilters3 = run_hooks('client.subscribe',
|
TopicFilters3 = run_hooks('client.subscribe',
|
||||||
[ClientInfo, Properties],
|
[ClientInfo, Properties],
|
||||||
TopicFilters2
|
TopicFilters2
|
||||||
),
|
),
|
||||||
{ReasonCodes, NChannel} = process_subscribe(TopicFilters3, Channel),
|
{ReasonCodes, NChannel} = process_subscribe(TopicFilters3, Properties, Channel),
|
||||||
case emqx_zone:get_env(Zone, acl_deny_action, ignore) =:= disconnect andalso
|
case emqx_zone:get_env(Zone, acl_deny_action, ignore) =:= disconnect andalso
|
||||||
lists:any(fun(ReasonCode) ->
|
lists:any(fun(ReasonCode) ->
|
||||||
ReasonCode =:= ?RC_NOT_AUTHORIZED
|
ReasonCode =:= ?RC_NOT_AUTHORIZED
|
||||||
|
@ -373,7 +373,7 @@ handle_in(Packet = ?UNSUBSCRIBE_PACKET(PacketId, Properties, TopicFilters),
|
||||||
[ClientInfo, Properties],
|
[ClientInfo, Properties],
|
||||||
parse_topic_filters(TopicFilters)
|
parse_topic_filters(TopicFilters)
|
||||||
),
|
),
|
||||||
{ReasonCodes, NChannel} = process_unsubscribe(TopicFilters1, Channel),
|
{ReasonCodes, NChannel} = process_unsubscribe(TopicFilters1, Properties, Channel),
|
||||||
handle_out(unsuback, {PacketId, ReasonCodes}, NChannel);
|
handle_out(unsuback, {PacketId, ReasonCodes}, NChannel);
|
||||||
{error, ReasonCode} ->
|
{error, ReasonCode} ->
|
||||||
handle_out(disconnect, ReasonCode, Channel)
|
handle_out(disconnect, ReasonCode, Channel)
|
||||||
|
@ -382,8 +382,8 @@ handle_in(Packet = ?UNSUBSCRIBE_PACKET(PacketId, Properties, TopicFilters),
|
||||||
handle_in(?PACKET(?PINGREQ), Channel) ->
|
handle_in(?PACKET(?PINGREQ), Channel) ->
|
||||||
{ok, ?PACKET(?PINGRESP), Channel};
|
{ok, ?PACKET(?PINGRESP), Channel};
|
||||||
|
|
||||||
handle_in(?DISCONNECT_PACKET(ReasonCode, Properties), Channel) ->
|
handle_in(?DISCONNECT_PACKET(ReasonCode, Properties), Channel = #channel{conninfo = ConnInfo}) ->
|
||||||
NChannel = maybe_clean_will_msg(ReasonCode, Channel),
|
NChannel = maybe_clean_will_msg(ReasonCode, Channel#channel{conninfo = ConnInfo#{disconn_props => Properties}}),
|
||||||
process_disconnect(ReasonCode, Properties, NChannel);
|
process_disconnect(ReasonCode, Properties, NChannel);
|
||||||
|
|
||||||
handle_in(?AUTH_PACKET(), Channel) ->
|
handle_in(?AUTH_PACKET(), Channel) ->
|
||||||
|
@ -437,7 +437,7 @@ process_connect(AckProps, Channel = #channel{conninfo = #{clean_start := CleanSt
|
||||||
%% Process Publish
|
%% Process Publish
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
process_publish(Packet = ?PUBLISH_PACKET(QoS, Topic, PacketId),
|
process_publish(Packet = ?PUBLISH_PACKET(QoS, Topic, PacketId),
|
||||||
Channel = #channel{clientinfo = #{zone := Zone}}) ->
|
Channel = #channel{clientinfo = #{zone := Zone}}) ->
|
||||||
case pipeline([fun process_alias/2,
|
case pipeline([fun process_alias/2,
|
||||||
fun check_pub_alias/2,
|
fun check_pub_alias/2,
|
||||||
|
@ -466,12 +466,23 @@ process_publish(Packet = ?PUBLISH_PACKET(QoS, Topic, PacketId),
|
||||||
handle_out(disconnect, ReasonCode, NChannel)
|
handle_out(disconnect, ReasonCode, NChannel)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
packet_to_message(Packet, #channel{conninfo = #{proto_ver := ProtoVer},
|
packet_to_message(Packet, #channel{
|
||||||
clientinfo = ClientInfo =
|
conninfo = #{proto_ver := ProtoVer},
|
||||||
#{mountpoint := MountPoint}}) ->
|
clientinfo = #{
|
||||||
emqx_mountpoint:mount(
|
protocol := Protocol,
|
||||||
MountPoint, emqx_packet:to_message(
|
clientid := ClientId,
|
||||||
ClientInfo, #{proto_ver => ProtoVer}, Packet)).
|
username := Username,
|
||||||
|
peerhost := PeerHost,
|
||||||
|
mountpoint := MountPoint
|
||||||
|
}
|
||||||
|
}) ->
|
||||||
|
emqx_mountpoint:mount(MountPoint,
|
||||||
|
emqx_packet:to_message(
|
||||||
|
Packet, ClientId,
|
||||||
|
#{proto_ver => ProtoVer,
|
||||||
|
protocol => Protocol,
|
||||||
|
username => Username,
|
||||||
|
peerhost => PeerHost})).
|
||||||
|
|
||||||
do_publish(_PacketId, Msg = #message{qos = ?QOS_0}, Channel) ->
|
do_publish(_PacketId, Msg = #message{qos = ?QOS_0}, Channel) ->
|
||||||
_ = emqx_broker:publish(Msg),
|
_ = emqx_broker:publish(Msg),
|
||||||
|
@ -504,25 +515,26 @@ do_publish(PacketId, Msg = #message{qos = ?QOS_2},
|
||||||
puback_reason_code([]) -> ?RC_NO_MATCHING_SUBSCRIBERS;
|
puback_reason_code([]) -> ?RC_NO_MATCHING_SUBSCRIBERS;
|
||||||
puback_reason_code([_|_]) -> ?RC_SUCCESS.
|
puback_reason_code([_|_]) -> ?RC_SUCCESS.
|
||||||
|
|
||||||
-compile({inline, [after_message_acked/2]}).
|
-compile({inline, [after_message_acked/3]}).
|
||||||
after_message_acked(ClientInfo, Msg) ->
|
after_message_acked(ClientInfo, Msg, PubAckProps) ->
|
||||||
ok = emqx_metrics:inc('messages.acked'),
|
ok = emqx_metrics:inc('messages.acked'),
|
||||||
emqx_hooks:run('message.acked', [ClientInfo, Msg]).
|
emqx_hooks:run('message.acked', [ClientInfo,
|
||||||
|
emqx_message:set_header(puback_props, PubAckProps, Msg)]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Process Subscribe
|
%% Process Subscribe
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-compile({inline, [process_subscribe/2]}).
|
-compile({inline, [process_subscribe/3]}).
|
||||||
process_subscribe(TopicFilters, Channel) ->
|
process_subscribe(TopicFilters, SubProps, Channel) ->
|
||||||
process_subscribe(TopicFilters, [], Channel).
|
process_subscribe(TopicFilters, SubProps, Channel, []).
|
||||||
|
|
||||||
process_subscribe([], Acc, Channel) ->
|
process_subscribe([], _SubProps, Channel, Acc) ->
|
||||||
{lists:reverse(Acc), Channel};
|
{lists:reverse(Acc), Channel};
|
||||||
|
|
||||||
process_subscribe([{TopicFilter, SubOpts}|More], Acc, Channel) ->
|
process_subscribe([{TopicFilter, SubOpts}|More], SubProps, Channel, Acc) ->
|
||||||
{RC, NChannel} = do_subscribe(TopicFilter, SubOpts, Channel),
|
{RC, NChannel} = do_subscribe(TopicFilter, SubOpts#{sub_props => SubProps}, Channel),
|
||||||
process_subscribe(More, [RC|Acc], NChannel).
|
process_subscribe(More, SubProps, NChannel, [RC|Acc]).
|
||||||
|
|
||||||
do_subscribe(TopicFilter, SubOpts = #{qos := QoS}, Channel =
|
do_subscribe(TopicFilter, SubOpts = #{qos := QoS}, Channel =
|
||||||
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
||||||
|
@ -557,22 +569,22 @@ process_force_subscribe(Subscriptions, Channel =
|
||||||
%% Process Unsubscribe
|
%% Process Unsubscribe
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-compile({inline, [process_unsubscribe/2]}).
|
-compile({inline, [process_unsubscribe/3]}).
|
||||||
process_unsubscribe(TopicFilters, Channel) ->
|
process_unsubscribe(TopicFilters, UnSubProps, Channel) ->
|
||||||
process_unsubscribe(TopicFilters, [], Channel).
|
process_unsubscribe(TopicFilters, UnSubProps, Channel, []).
|
||||||
|
|
||||||
process_unsubscribe([], Acc, Channel) ->
|
process_unsubscribe([], _UnSubProps, Channel, Acc) ->
|
||||||
{lists:reverse(Acc), Channel};
|
{lists:reverse(Acc), Channel};
|
||||||
|
|
||||||
process_unsubscribe([{TopicFilter, SubOpts}|More], Acc, Channel) ->
|
process_unsubscribe([{TopicFilter, SubOpts}|More], UnSubProps, Channel, Acc) ->
|
||||||
{RC, NChannel} = do_unsubscribe(TopicFilter, SubOpts, Channel),
|
{RC, NChannel} = do_unsubscribe(TopicFilter, SubOpts#{unsub_props => UnSubProps}, Channel),
|
||||||
process_unsubscribe(More, [RC|Acc], NChannel).
|
process_unsubscribe(More, UnSubProps, NChannel, [RC|Acc]).
|
||||||
|
|
||||||
do_unsubscribe(TopicFilter, _SubOpts, Channel =
|
do_unsubscribe(TopicFilter, SubOpts, Channel =
|
||||||
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
||||||
session = Session}) ->
|
session = Session}) ->
|
||||||
TopicFilter1 = emqx_mountpoint:mount(MountPoint, TopicFilter),
|
TopicFilter1 = emqx_mountpoint:mount(MountPoint, TopicFilter),
|
||||||
case emqx_session:unsubscribe(ClientInfo, TopicFilter1, Session) of
|
case emqx_session:unsubscribe(ClientInfo, TopicFilter1, SubOpts, Session) of
|
||||||
{ok, NSession} ->
|
{ok, NSession} ->
|
||||||
{?RC_SUCCESS, Channel#channel{session = NSession}};
|
{?RC_SUCCESS, Channel#channel{session = NSession}};
|
||||||
{error, RC} -> {RC, Channel}
|
{error, RC} -> {RC, Channel}
|
||||||
|
@ -582,9 +594,9 @@ do_unsubscribe(TopicFilter, _SubOpts, Channel =
|
||||||
process_force_unsubscribe(Subscriptions, Channel =
|
process_force_unsubscribe(Subscriptions, Channel =
|
||||||
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
#channel{clientinfo = ClientInfo = #{mountpoint := MountPoint},
|
||||||
session = Session}) ->
|
session = Session}) ->
|
||||||
lists:foldl(fun({TopicFilter, _SubOpts}, {ReasonCodes, ChannelAcc}) ->
|
lists:foldl(fun({TopicFilter, SubOpts}, {ReasonCodes, ChannelAcc}) ->
|
||||||
NTopicFilter = emqx_mountpoint:mount(MountPoint, TopicFilter),
|
NTopicFilter = emqx_mountpoint:mount(MountPoint, TopicFilter),
|
||||||
case emqx_session:unsubscribe(ClientInfo, NTopicFilter, Session) of
|
case emqx_session:unsubscribe(ClientInfo, NTopicFilter, SubOpts, Session) of
|
||||||
{ok, NSession} ->
|
{ok, NSession} ->
|
||||||
{ReasonCodes ++ [?RC_SUCCESS], ChannelAcc#channel{session = NSession}};
|
{ReasonCodes ++ [?RC_SUCCESS], ChannelAcc#channel{session = NSession}};
|
||||||
{error, ReasonCode} ->
|
{error, ReasonCode} ->
|
||||||
|
@ -844,7 +856,7 @@ handle_info({subscribe, TopicFilters}, Channel = #channel{clientinfo = ClientInf
|
||||||
[ClientInfo, #{'Internal' => true}],
|
[ClientInfo, #{'Internal' => true}],
|
||||||
parse_topic_filters(TopicFilters)
|
parse_topic_filters(TopicFilters)
|
||||||
),
|
),
|
||||||
{_ReasonCodes, NChannel} = process_subscribe(TopicFilters1, Channel),
|
{_ReasonCodes, NChannel} = process_subscribe(TopicFilters1, #{}, Channel),
|
||||||
{ok, NChannel};
|
{ok, NChannel};
|
||||||
|
|
||||||
handle_info({force_subscribe, TopicFilters}, Channel) ->
|
handle_info({force_subscribe, TopicFilters}, Channel) ->
|
||||||
|
@ -856,7 +868,7 @@ handle_info({unsubscribe, TopicFilters}, Channel = #channel{clientinfo = ClientI
|
||||||
[ClientInfo, #{'Internal' => true}],
|
[ClientInfo, #{'Internal' => true}],
|
||||||
parse_topic_filters(TopicFilters)
|
parse_topic_filters(TopicFilters)
|
||||||
),
|
),
|
||||||
{_ReasonCodes, NChannel} = process_unsubscribe(TopicFilters1, Channel),
|
{_ReasonCodes, NChannel} = process_unsubscribe(TopicFilters1, #{}, Channel),
|
||||||
{ok, NChannel};
|
{ok, NChannel};
|
||||||
|
|
||||||
handle_info({force_unsubscribe, TopicFilters}, Channel) ->
|
handle_info({force_unsubscribe, TopicFilters}, Channel) ->
|
||||||
|
@ -1329,9 +1341,9 @@ check_sub_caps(TopicFilter, SubOpts, #channel{clientinfo = #{zone := Zone}}) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Enrich SubId
|
%% Enrich SubId
|
||||||
|
|
||||||
enrich_subid(#{'Subscription-Identifier' := SubId}, TopicFilters) ->
|
put_subid_in_subopts(#{'Subscription-Identifier' := SubId}, TopicFilters) ->
|
||||||
[{Topic, SubOpts#{subid => SubId}} || {Topic, SubOpts} <- TopicFilters];
|
[{Topic, SubOpts#{subid => SubId}} || {Topic, SubOpts} <- TopicFilters];
|
||||||
enrich_subid(_Properties, TopicFilters) -> TopicFilters.
|
put_subid_in_subopts(_Properties, TopicFilters) -> TopicFilters.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Enrich SubOpts
|
%% Enrich SubOpts
|
||||||
|
@ -1490,7 +1502,7 @@ mabye_publish_will_msg(Channel = #channel{will_msg = WillMsg}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
will_delay_interval(WillMsg) ->
|
will_delay_interval(WillMsg) ->
|
||||||
emqx_message:get_header('Will-Delay-Interval', WillMsg, 0).
|
maps:get('Will-Delay-Interval', emqx_message:get_header(properties, WillMsg), 0).
|
||||||
|
|
||||||
publish_will_msg(Msg) -> emqx_broker:publish(Msg).
|
publish_will_msg(Msg) -> emqx_broker:publish(Msg).
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,7 @@ parse_packet_id(<<PacketId:16/big, Rest/binary>>) ->
|
||||||
{PacketId, Rest}.
|
{PacketId, Rest}.
|
||||||
|
|
||||||
parse_properties(Bin, Ver) when Ver =/= ?MQTT_PROTO_V5 ->
|
parse_properties(Bin, Ver) when Ver =/= ?MQTT_PROTO_V5 ->
|
||||||
{undefined, Bin};
|
{#{}, Bin};
|
||||||
%% TODO: version mess?
|
%% TODO: version mess?
|
||||||
parse_properties(<<>>, ?MQTT_PROTO_V5) ->
|
parse_properties(<<>>, ?MQTT_PROTO_V5) ->
|
||||||
{#{}, <<>>};
|
{#{}, <<>>};
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
-export([ make/2
|
-export([ make/2
|
||||||
, make/3
|
, make/3
|
||||||
, make/4
|
, make/4
|
||||||
|
, make/6
|
||||||
|
, make/7
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Fields
|
%% Fields
|
||||||
|
@ -69,8 +71,6 @@
|
||||||
|
|
||||||
-export([format/1]).
|
-export([format/1]).
|
||||||
|
|
||||||
-type(flag() :: atom()).
|
|
||||||
|
|
||||||
-spec(make(emqx_topic:topic(), emqx_types:payload()) -> emqx_types:message()).
|
-spec(make(emqx_topic:topic(), emqx_types:payload()) -> emqx_types:message()).
|
||||||
make(Topic, Payload) ->
|
make(Topic, Payload) ->
|
||||||
make(undefined, Topic, Payload).
|
make(undefined, Topic, Payload).
|
||||||
|
@ -95,6 +95,47 @@ make(From, QoS, Topic, Payload) when ?QOS_0 =< QoS, QoS =< ?QOS_2 ->
|
||||||
timestamp = Now
|
timestamp = Now
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-spec(make(emqx_types:clientid(),
|
||||||
|
emqx_types:qos(),
|
||||||
|
emqx_topic:topic(),
|
||||||
|
emqx_types:payload(),
|
||||||
|
emqx_types:flags(),
|
||||||
|
emqx_types:headers()) -> emqx_types:message()).
|
||||||
|
make(From, QoS, Topic, Payload, Flags, Headers)
|
||||||
|
when ?QOS_0 =< QoS, QoS =< ?QOS_2,
|
||||||
|
is_map(Flags), is_map(Headers) ->
|
||||||
|
Now = erlang:system_time(millisecond),
|
||||||
|
#message{id = emqx_guid:gen(),
|
||||||
|
qos = QoS,
|
||||||
|
from = From,
|
||||||
|
flags = Flags,
|
||||||
|
headers = Headers,
|
||||||
|
topic = Topic,
|
||||||
|
payload = Payload,
|
||||||
|
timestamp = Now
|
||||||
|
}.
|
||||||
|
|
||||||
|
-spec(make(MsgId :: binary(),
|
||||||
|
emqx_types:clientid(),
|
||||||
|
emqx_types:qos(),
|
||||||
|
emqx_topic:topic(),
|
||||||
|
emqx_types:payload(),
|
||||||
|
emqx_types:flags(),
|
||||||
|
emqx_types:headers()) -> emqx_types:message()).
|
||||||
|
make(MsgId, From, QoS, Topic, Payload, Flags, Headers)
|
||||||
|
when ?QOS_0 =< QoS, QoS =< ?QOS_2,
|
||||||
|
is_map(Flags), is_map(Headers) ->
|
||||||
|
Now = erlang:system_time(millisecond),
|
||||||
|
#message{id = MsgId,
|
||||||
|
qos = QoS,
|
||||||
|
from = From,
|
||||||
|
flags = Flags,
|
||||||
|
headers = Headers,
|
||||||
|
topic = Topic,
|
||||||
|
payload = Payload,
|
||||||
|
timestamp = Now
|
||||||
|
}.
|
||||||
|
|
||||||
-spec(id(emqx_types:message()) -> maybe(binary())).
|
-spec(id(emqx_types:message()) -> maybe(binary())).
|
||||||
id(#message{id = Id}) -> Id.
|
id(#message{id = Id}) -> Id.
|
||||||
|
|
||||||
|
@ -126,39 +167,29 @@ clean_dup(Msg = #message{flags = Flags = #{dup := true}}) ->
|
||||||
clean_dup(Msg) -> Msg.
|
clean_dup(Msg) -> Msg.
|
||||||
|
|
||||||
-spec(set_flags(map(), emqx_types:message()) -> emqx_types:message()).
|
-spec(set_flags(map(), emqx_types:message()) -> emqx_types:message()).
|
||||||
set_flags(Flags, Msg = #message{flags = undefined}) when is_map(Flags) ->
|
|
||||||
Msg#message{flags = Flags};
|
|
||||||
set_flags(New, Msg = #message{flags = Old}) when is_map(New) ->
|
set_flags(New, Msg = #message{flags = Old}) when is_map(New) ->
|
||||||
Msg#message{flags = maps:merge(Old, New)}.
|
Msg#message{flags = maps:merge(Old, New)}.
|
||||||
|
|
||||||
-spec(get_flag(flag(), emqx_types:message()) -> boolean()).
|
-spec(get_flag(emqx_types:flag(), emqx_types:message()) -> boolean()).
|
||||||
get_flag(_Flag, #message{flags = undefined}) ->
|
|
||||||
false;
|
|
||||||
get_flag(Flag, Msg) ->
|
get_flag(Flag, Msg) ->
|
||||||
get_flag(Flag, Msg, false).
|
get_flag(Flag, Msg, false).
|
||||||
|
|
||||||
get_flag(_Flag, #message{flags = undefined}, Default) ->
|
|
||||||
Default;
|
|
||||||
get_flag(Flag, #message{flags = Flags}, Default) ->
|
get_flag(Flag, #message{flags = Flags}, Default) ->
|
||||||
maps:get(Flag, Flags, Default).
|
maps:get(Flag, Flags, Default).
|
||||||
|
|
||||||
-spec(get_flags(emqx_types:message()) -> maybe(map())).
|
-spec(get_flags(emqx_types:message()) -> maybe(map())).
|
||||||
get_flags(#message{flags = Flags}) -> Flags.
|
get_flags(#message{flags = Flags}) -> Flags.
|
||||||
|
|
||||||
-spec(set_flag(flag(), emqx_types:message()) -> emqx_types:message()).
|
-spec(set_flag(emqx_types:flag(), emqx_types:message()) -> emqx_types:message()).
|
||||||
set_flag(Flag, Msg = #message{flags = undefined}) when is_atom(Flag) ->
|
|
||||||
Msg#message{flags = #{Flag => true}};
|
|
||||||
set_flag(Flag, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
set_flag(Flag, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
||||||
Msg#message{flags = maps:put(Flag, true, Flags)}.
|
Msg#message{flags = maps:put(Flag, true, Flags)}.
|
||||||
|
|
||||||
-spec(set_flag(flag(), boolean() | integer(), emqx_types:message())
|
-spec(set_flag(emqx_types:flag(), boolean() | integer(), emqx_types:message())
|
||||||
-> emqx_types:message()).
|
-> emqx_types:message()).
|
||||||
set_flag(Flag, Val, Msg = #message{flags = undefined}) when is_atom(Flag) ->
|
|
||||||
Msg#message{flags = #{Flag => Val}};
|
|
||||||
set_flag(Flag, Val, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
set_flag(Flag, Val, Msg = #message{flags = Flags}) when is_atom(Flag) ->
|
||||||
Msg#message{flags = maps:put(Flag, Val, Flags)}.
|
Msg#message{flags = maps:put(Flag, Val, Flags)}.
|
||||||
|
|
||||||
-spec(unset_flag(flag(), emqx_types:message()) -> emqx_types:message()).
|
-spec(unset_flag(emqx_types:flag(), emqx_types:message()) -> emqx_types:message()).
|
||||||
unset_flag(Flag, Msg = #message{flags = Flags}) ->
|
unset_flag(Flag, Msg = #message{flags = Flags}) ->
|
||||||
case maps:is_key(Flag, Flags) of
|
case maps:is_key(Flag, Flags) of
|
||||||
true -> Msg#message{flags = maps:remove(Flag, Flags)};
|
true -> Msg#message{flags = maps:remove(Flag, Flags)};
|
||||||
|
@ -166,8 +197,6 @@ unset_flag(Flag, Msg = #message{flags = Flags}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(set_headers(map(), emqx_types:message()) -> emqx_types:message()).
|
-spec(set_headers(map(), emqx_types:message()) -> emqx_types:message()).
|
||||||
set_headers(Headers, Msg = #message{headers = undefined}) when is_map(Headers) ->
|
|
||||||
Msg#message{headers = Headers};
|
|
||||||
set_headers(New, Msg = #message{headers = Old}) when is_map(New) ->
|
set_headers(New, Msg = #message{headers = Old}) when is_map(New) ->
|
||||||
Msg#message{headers = maps:merge(Old, New)}.
|
Msg#message{headers = maps:merge(Old, New)}.
|
||||||
|
|
||||||
|
@ -175,25 +204,17 @@ set_headers(New, Msg = #message{headers = Old}) when is_map(New) ->
|
||||||
get_headers(Msg) -> Msg#message.headers.
|
get_headers(Msg) -> Msg#message.headers.
|
||||||
|
|
||||||
-spec(get_header(term(), emqx_types:message()) -> term()).
|
-spec(get_header(term(), emqx_types:message()) -> term()).
|
||||||
get_header(_Hdr, #message{headers = undefined}) ->
|
|
||||||
undefined;
|
|
||||||
get_header(Hdr, Msg) ->
|
get_header(Hdr, Msg) ->
|
||||||
get_header(Hdr, Msg, undefined).
|
get_header(Hdr, Msg, undefined).
|
||||||
-spec(get_header(term(), emqx_types:message(), term()) -> term()).
|
-spec(get_header(term(), emqx_types:message(), term()) -> term()).
|
||||||
get_header(_Hdr, #message{headers = undefined}, Default) ->
|
|
||||||
Default;
|
|
||||||
get_header(Hdr, #message{headers = Headers}, Default) ->
|
get_header(Hdr, #message{headers = Headers}, Default) ->
|
||||||
maps:get(Hdr, Headers, Default).
|
maps:get(Hdr, Headers, Default).
|
||||||
|
|
||||||
-spec(set_header(term(), term(), emqx_types:message()) -> emqx_types:message()).
|
-spec(set_header(term(), term(), emqx_types:message()) -> emqx_types:message()).
|
||||||
set_header(Hdr, Val, Msg = #message{headers = undefined}) ->
|
|
||||||
Msg#message{headers = #{Hdr => Val}};
|
|
||||||
set_header(Hdr, Val, Msg = #message{headers = Headers}) ->
|
set_header(Hdr, Val, Msg = #message{headers = Headers}) ->
|
||||||
Msg#message{headers = maps:put(Hdr, Val, Headers)}.
|
Msg#message{headers = maps:put(Hdr, Val, Headers)}.
|
||||||
|
|
||||||
-spec(remove_header(term(), emqx_types:message()) -> emqx_types:message()).
|
-spec(remove_header(term(), emqx_types:message()) -> emqx_types:message()).
|
||||||
remove_header(_Hdr, Msg = #message{headers = undefined}) ->
|
|
||||||
Msg;
|
|
||||||
remove_header(Hdr, Msg = #message{headers = Headers}) ->
|
remove_header(Hdr, Msg = #message{headers = Headers}) ->
|
||||||
case maps:is_key(Hdr, Headers) of
|
case maps:is_key(Hdr, Headers) of
|
||||||
true -> Msg#message{headers = maps:remove(Hdr, Headers)};
|
true -> Msg#message{headers = maps:remove(Hdr, Headers)};
|
||||||
|
@ -201,18 +222,18 @@ remove_header(Hdr, Msg = #message{headers = Headers}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(is_expired(emqx_types:message()) -> boolean()).
|
-spec(is_expired(emqx_types:message()) -> boolean()).
|
||||||
is_expired(#message{headers = #{'Message-Expiry-Interval' := Interval},
|
is_expired(#message{headers = #{properties := #{'Message-Expiry-Interval' := Interval}},
|
||||||
timestamp = CreatedAt}) ->
|
timestamp = CreatedAt}) ->
|
||||||
elapsed(CreatedAt) > timer:seconds(Interval);
|
elapsed(CreatedAt) > timer:seconds(Interval);
|
||||||
is_expired(_Msg) -> false.
|
is_expired(_Msg) -> false.
|
||||||
|
|
||||||
-spec(update_expiry(emqx_types:message()) -> emqx_types:message()).
|
-spec(update_expiry(emqx_types:message()) -> emqx_types:message()).
|
||||||
update_expiry(Msg = #message{headers = #{'Message-Expiry-Interval' := Interval},
|
update_expiry(Msg = #message{headers = #{properties := Props = #{'Message-Expiry-Interval' := Interval}},
|
||||||
timestamp = CreatedAt}) ->
|
timestamp = CreatedAt}) ->
|
||||||
case elapsed(CreatedAt) of
|
case elapsed(CreatedAt) of
|
||||||
Elapsed when Elapsed > 0 ->
|
Elapsed when Elapsed > 0 ->
|
||||||
Interval1 = max(1, Interval - (Elapsed div 1000)),
|
Interval1 = max(1, Interval - (Elapsed div 1000)),
|
||||||
set_header('Message-Expiry-Interval', Interval1, Msg);
|
set_header(properties, Props#{'Message-Expiry-Interval' => Interval1}, Msg);
|
||||||
_ -> Msg
|
_ -> Msg
|
||||||
end;
|
end;
|
||||||
update_expiry(Msg) -> Msg.
|
update_expiry(Msg) -> Msg.
|
||||||
|
@ -229,21 +250,11 @@ to_packet(PacketId, Msg = #message{qos = QoS, headers = Headers,
|
||||||
},
|
},
|
||||||
variable = #mqtt_packet_publish{topic_name = Topic,
|
variable = #mqtt_packet_publish{topic_name = Topic,
|
||||||
packet_id = PacketId,
|
packet_id = PacketId,
|
||||||
properties = props(Headers)
|
properties = maps:get(properties, Headers, #{})
|
||||||
},
|
},
|
||||||
payload = Payload
|
payload = Payload
|
||||||
}.
|
}.
|
||||||
|
|
||||||
props(undefined) -> undefined;
|
|
||||||
props(Headers) -> maps:with(['Payload-Format-Indicator',
|
|
||||||
'Response-Topic',
|
|
||||||
'Correlation-Data',
|
|
||||||
'User-Property',
|
|
||||||
'Subscription-Identifier',
|
|
||||||
'Content-Type',
|
|
||||||
'Message-Expiry-Interval'
|
|
||||||
], Headers).
|
|
||||||
|
|
||||||
%% @doc Message to map
|
%% @doc Message to map
|
||||||
-spec(to_map(emqx_types:message()) -> map()).
|
-spec(to_map(emqx_types:message()) -> map()).
|
||||||
to_map(#message{
|
to_map(#message{
|
||||||
|
|
|
@ -373,34 +373,26 @@ validate_topic_filters(TopicFilters) ->
|
||||||
emqx_topic:validate(TopicFilter)
|
emqx_topic:validate(TopicFilter)
|
||||||
end, TopicFilters).
|
end, TopicFilters).
|
||||||
|
|
||||||
-spec(to_message(emqx_types:clientinfo(), emqx_ypes:packet()) -> emqx_types:message()).
|
-spec(to_message(emqx_types:packet(), emqx_types:clientid()) -> emqx_types:message()).
|
||||||
to_message(ClientInfo, Packet) ->
|
to_message(Packet, ClientId) ->
|
||||||
to_message(ClientInfo, #{}, Packet).
|
to_message(Packet, ClientId, #{}).
|
||||||
|
|
||||||
%% @doc Transform Publish Packet to Message.
|
%% @doc Transform Publish Packet to Message.
|
||||||
-spec(to_message(emqx_types:clientinfo(), map(), emqx_ypes:packet())
|
-spec(to_message(emqx_types:packet(), emqx_types:clientid(), map()) -> emqx_types:message()).
|
||||||
-> emqx_types:message()).
|
to_message(#mqtt_packet{
|
||||||
to_message(#{protocol := Protocol,
|
header = #mqtt_packet_header{
|
||||||
clientid := ClientId,
|
type = ?PUBLISH,
|
||||||
username := Username,
|
retain = Retain,
|
||||||
peerhost := PeerHost
|
qos = QoS,
|
||||||
}, Headers,
|
dup = Dup},
|
||||||
#mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
variable = #mqtt_packet_publish{
|
||||||
retain = Retain,
|
topic_name = Topic,
|
||||||
qos = QoS,
|
properties = Props},
|
||||||
dup = Dup
|
payload = Payload
|
||||||
},
|
}, ClientId, Headers) ->
|
||||||
variable = #mqtt_packet_publish{topic_name = Topic,
|
|
||||||
properties = Props
|
|
||||||
},
|
|
||||||
payload = Payload
|
|
||||||
}) ->
|
|
||||||
Msg = emqx_message:make(ClientId, QoS, Topic, Payload),
|
Msg = emqx_message:make(ClientId, QoS, Topic, Payload),
|
||||||
Headers1 = merge_props(Headers#{protocol => Protocol,
|
Msg#message{flags = #{dup => Dup, retain => Retain},
|
||||||
username => Username,
|
headers = Headers#{properties => Props}}.
|
||||||
peerhost => PeerHost
|
|
||||||
}, Props),
|
|
||||||
Msg#message{flags = #{dup => Dup, retain => Retain}, headers = Headers1}.
|
|
||||||
|
|
||||||
-spec(will_msg(#mqtt_packet_connect{}) -> emqx_types:message()).
|
-spec(will_msg(#mqtt_packet_connect{}) -> emqx_types:message()).
|
||||||
will_msg(#mqtt_packet_connect{will_flag = false}) ->
|
will_msg(#mqtt_packet_connect{will_flag = false}) ->
|
||||||
|
@ -413,13 +405,8 @@ will_msg(#mqtt_packet_connect{clientid = ClientId,
|
||||||
will_props = Props,
|
will_props = Props,
|
||||||
will_payload = Payload}) ->
|
will_payload = Payload}) ->
|
||||||
Msg = emqx_message:make(ClientId, QoS, Topic, Payload),
|
Msg = emqx_message:make(ClientId, QoS, Topic, Payload),
|
||||||
Headers = merge_props(#{username => Username}, Props),
|
Msg#message{flags = #{dup => false, retain => Retain},
|
||||||
Msg#message{flags = #{dup => false, retain => Retain}, headers = Headers}.
|
headers = #{username => Username, properties => Props}}.
|
||||||
|
|
||||||
merge_props(Headers, undefined) ->
|
|
||||||
Headers;
|
|
||||||
merge_props(Headers, Props) ->
|
|
||||||
maps:merge(Headers, Props).
|
|
||||||
|
|
||||||
%% @doc Format packet
|
%% @doc Format packet
|
||||||
-spec(format(emqx_types:packet()) -> iolist()).
|
-spec(format(emqx_types:packet()) -> iolist()).
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ subscribe/4
|
-export([ subscribe/4
|
||||||
, unsubscribe/3
|
, unsubscribe/4
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ publish/3
|
-export([ publish/3
|
||||||
|
@ -261,13 +261,13 @@ is_subscriptions_full(#session{subscriptions = Subs,
|
||||||
%% Client -> Broker: UNSUBSCRIBE
|
%% Client -> Broker: UNSUBSCRIBE
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-spec(unsubscribe(emqx_types:clientinfo(), emqx_types:topic(), session())
|
-spec(unsubscribe(emqx_types:clientinfo(), emqx_types:topic(), emqx_types:subopts(), session())
|
||||||
-> {ok, session()} | {error, emqx_types:reason_code()}).
|
-> {ok, session()} | {error, emqx_types:reason_code()}).
|
||||||
unsubscribe(ClientInfo, TopicFilter, Session = #session{subscriptions = Subs}) ->
|
unsubscribe(ClientInfo, TopicFilter, UnSubOpts, Session = #session{subscriptions = Subs}) ->
|
||||||
case maps:find(TopicFilter, Subs) of
|
case maps:find(TopicFilter, Subs) of
|
||||||
{ok, SubOpts} ->
|
{ok, SubOpts} ->
|
||||||
ok = emqx_broker:unsubscribe(TopicFilter),
|
ok = emqx_broker:unsubscribe(TopicFilter),
|
||||||
ok = emqx_hooks:run('session.unsubscribed', [ClientInfo, TopicFilter, SubOpts]),
|
ok = emqx_hooks:run('session.unsubscribed', [ClientInfo, TopicFilter, maps:merge(SubOpts, UnSubOpts)]),
|
||||||
{ok, Session#session{subscriptions = maps:remove(TopicFilter, Subs)}};
|
{ok, Session#session{subscriptions = maps:remove(TopicFilter, Subs)}};
|
||||||
error ->
|
error ->
|
||||||
{error, ?RC_NO_SUBSCRIPTION_EXISTED}
|
{error, ?RC_NO_SUBSCRIPTION_EXISTED}
|
||||||
|
@ -523,7 +523,8 @@ enrich_subopts([{rap, 0}|Opts], Msg = #message{headers = #{retained := true}}, S
|
||||||
enrich_subopts([{rap, 0}|Opts], Msg, Session) ->
|
enrich_subopts([{rap, 0}|Opts], Msg, Session) ->
|
||||||
enrich_subopts(Opts, emqx_message:set_flag(retain, false, Msg), Session);
|
enrich_subopts(Opts, emqx_message:set_flag(retain, false, Msg), Session);
|
||||||
enrich_subopts([{subid, SubId}|Opts], Msg, Session) ->
|
enrich_subopts([{subid, SubId}|Opts], Msg, Session) ->
|
||||||
Msg1 = emqx_message:set_header('Subscription-Identifier', SubId, Msg),
|
Props = emqx_message:get_header(properties, Msg, #{}),
|
||||||
|
Msg1 = emqx_message:set_header(properties, Props#{'Subscription-Identifier' => SubId}, Msg),
|
||||||
enrich_subopts(Opts, Msg1, Session).
|
enrich_subopts(Opts, Msg1, Session).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -63,6 +63,9 @@
|
||||||
|
|
||||||
-export_type([ payload/0
|
-export_type([ payload/0
|
||||||
, message/0
|
, message/0
|
||||||
|
, flag/0
|
||||||
|
, flags/0
|
||||||
|
, headers/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export_type([ deliver/0
|
-export_type([ deliver/0
|
||||||
|
@ -179,6 +182,9 @@
|
||||||
-type(subscriber() :: {pid(), subid()}).
|
-type(subscriber() :: {pid(), subid()}).
|
||||||
-type(payload() :: binary() | iodata()).
|
-type(payload() :: binary() | iodata()).
|
||||||
-type(message() :: #message{}).
|
-type(message() :: #message{}).
|
||||||
|
-type(flag() :: atom()).
|
||||||
|
-type(flags() :: #{flag() := boolean()}).
|
||||||
|
-type(headers() :: map()).
|
||||||
-type(banned() :: #banned{}).
|
-type(banned() :: #banned{}).
|
||||||
-type(deliver() :: {deliver, topic(), message()}).
|
-type(deliver() :: {deliver, topic(), message()}).
|
||||||
-type(delivery() :: #delivery{}).
|
-type(delivery() :: #delivery{}).
|
||||||
|
|
|
@ -279,7 +279,7 @@ t_handle_in_subscribe(_) ->
|
||||||
|
|
||||||
t_handle_in_unsubscribe(_) ->
|
t_handle_in_unsubscribe(_) ->
|
||||||
ok = meck:expect(emqx_session, unsubscribe,
|
ok = meck:expect(emqx_session, unsubscribe,
|
||||||
fun(_, _, Session) ->
|
fun(_, _, _, Session) ->
|
||||||
{ok, Session}
|
{ok, Session}
|
||||||
end),
|
end),
|
||||||
Channel = channel(#{conn_state => connected}),
|
Channel = channel(#{conn_state => connected}),
|
||||||
|
@ -345,12 +345,12 @@ t_process_publish_qos1(_) ->
|
||||||
t_process_subscribe(_) ->
|
t_process_subscribe(_) ->
|
||||||
ok = meck:expect(emqx_session, subscribe, fun(_, _, _, Session) -> {ok, Session} end),
|
ok = meck:expect(emqx_session, subscribe, fun(_, _, _, Session) -> {ok, Session} end),
|
||||||
TopicFilters = [{<<"+">>, ?DEFAULT_SUBOPTS}],
|
TopicFilters = [{<<"+">>, ?DEFAULT_SUBOPTS}],
|
||||||
{[?RC_SUCCESS], _Channel} = emqx_channel:process_subscribe(TopicFilters, channel()).
|
{[?RC_SUCCESS], _Channel} = emqx_channel:process_subscribe(TopicFilters, #{}, channel()).
|
||||||
|
|
||||||
t_process_unsubscribe(_) ->
|
t_process_unsubscribe(_) ->
|
||||||
ok = meck:expect(emqx_session, unsubscribe, fun(_, _, Session) -> {ok, Session} end),
|
ok = meck:expect(emqx_session, unsubscribe, fun(_, _, _, Session) -> {ok, Session} end),
|
||||||
TopicFilters = [{<<"+">>, ?DEFAULT_SUBOPTS}],
|
TopicFilters = [{<<"+">>, ?DEFAULT_SUBOPTS}],
|
||||||
{[?RC_SUCCESS], _Channel} = emqx_channel:process_unsubscribe(TopicFilters, channel()).
|
{[?RC_SUCCESS], _Channel} = emqx_channel:process_unsubscribe(TopicFilters, #{}, channel()).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Test cases for handle_deliver
|
%% Test cases for handle_deliver
|
||||||
|
@ -465,7 +465,7 @@ t_handle_info_subscribe(_) ->
|
||||||
{ok, _Chan} = emqx_channel:handle_info({subscribe, topic_filters()}, channel()).
|
{ok, _Chan} = emqx_channel:handle_info({subscribe, topic_filters()}, channel()).
|
||||||
|
|
||||||
t_handle_info_unsubscribe(_) ->
|
t_handle_info_unsubscribe(_) ->
|
||||||
ok = meck:expect(emqx_session, unsubscribe, fun(_, _, Session) -> {ok, Session} end),
|
ok = meck:expect(emqx_session, unsubscribe, fun(_, _, _, Session) -> {ok, Session} end),
|
||||||
{ok, _Chan} = emqx_channel:handle_info({unsubscribe, topic_filters()}, channel()).
|
{ok, _Chan} = emqx_channel:handle_info({unsubscribe, topic_filters()}, channel()).
|
||||||
|
|
||||||
t_handle_info_sock_closed(_) ->
|
t_handle_info_sock_closed(_) ->
|
||||||
|
@ -541,7 +541,7 @@ t_packing_alias(_) ->
|
||||||
?assertEqual(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<>>, properties = #{'Topic-Alias' => 1}}}, RePacket2),
|
?assertEqual(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<>>, properties = #{'Topic-Alias' => 1}}}, RePacket2),
|
||||||
|
|
||||||
{RePacket3, _} = emqx_channel:packing_alias(Packet2, NChannel2),
|
{RePacket3, _} = emqx_channel:packing_alias(Packet2, NChannel2),
|
||||||
?assertEqual(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"y">>, properties = undefined}}, RePacket3),
|
?assertEqual(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"y">>, properties = #{}}}, RePacket3),
|
||||||
|
|
||||||
?assertMatch({#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"z">>}}, _}, emqx_channel:packing_alias(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"z">>}}, channel())).
|
?assertMatch({#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"z">>}}, _}, emqx_channel:packing_alias(#mqtt_packet{variable = #mqtt_packet_publish{topic_name = <<"z">>}}, channel())).
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ connpkt() ->
|
||||||
is_bridge = false,
|
is_bridge = false,
|
||||||
clean_start = true,
|
clean_start = true,
|
||||||
keepalive = 30,
|
keepalive = 30,
|
||||||
properties = undefined,
|
properties = #{},
|
||||||
clientid = <<"clientid">>,
|
clientid = <<"clientid">>,
|
||||||
username = <<"username">>,
|
username = <<"username">>,
|
||||||
password = <<"passwd">>
|
password = <<"passwd">>
|
||||||
|
|
|
@ -141,10 +141,6 @@ prop_serialize_parse_connect() ->
|
||||||
?FORALL(Opts = #{version := ProtoVer}, parse_opts(),
|
?FORALL(Opts = #{version := ProtoVer}, parse_opts(),
|
||||||
begin
|
begin
|
||||||
ProtoName = proplists:get_value(ProtoVer, ?PROTOCOL_NAMES),
|
ProtoName = proplists:get_value(ProtoVer, ?PROTOCOL_NAMES),
|
||||||
DefaultProps = if ProtoVer == ?MQTT_PROTO_V5 ->
|
|
||||||
#{};
|
|
||||||
true -> undefined
|
|
||||||
end,
|
|
||||||
Packet = ?CONNECT_PACKET(#mqtt_packet_connect{
|
Packet = ?CONNECT_PACKET(#mqtt_packet_connect{
|
||||||
proto_name = ProtoName,
|
proto_name = ProtoName,
|
||||||
proto_ver = ProtoVer,
|
proto_ver = ProtoVer,
|
||||||
|
@ -153,10 +149,10 @@ prop_serialize_parse_connect() ->
|
||||||
will_flag = true,
|
will_flag = true,
|
||||||
will_retain = true,
|
will_retain = true,
|
||||||
will_topic = <<"will">>,
|
will_topic = <<"will">>,
|
||||||
will_props = DefaultProps,
|
will_props = #{},
|
||||||
will_payload = <<"bye">>,
|
will_payload = <<"bye">>,
|
||||||
clean_start = true,
|
clean_start = true,
|
||||||
properties = DefaultProps
|
properties = #{}
|
||||||
}),
|
}),
|
||||||
ok == ?assertEqual(Packet, parse_serialize(Packet, Opts))
|
ok == ?assertEqual(Packet, parse_serialize(Packet, Opts))
|
||||||
end).
|
end).
|
||||||
|
|
|
@ -48,7 +48,7 @@ t_restart_listeners(_) ->
|
||||||
ok = emqx_listeners:stop().
|
ok = emqx_listeners:stop().
|
||||||
|
|
||||||
render_config_file() ->
|
render_config_file() ->
|
||||||
Path = local_path(["etc", "emqx.conf"]),
|
Path = local_path(["..", "..", "..", "..", "etc", "emqx.conf"]),
|
||||||
{ok, Temp} = file:read_file(Path),
|
{ok, Temp} = file:read_file(Path),
|
||||||
Vars0 = mustache_vars(),
|
Vars0 = mustache_vars(),
|
||||||
Vars = [{atom_to_list(N), iolist_to_binary(V)} || {N, V} <- Vars0],
|
Vars = [{atom_to_list(N), iolist_to_binary(V)} || {N, V} <- Vars0],
|
||||||
|
|
|
@ -86,7 +86,7 @@ t_clean_dup(_) ->
|
||||||
?assertNot(emqx_message:get_flag(dup, Msg2)).
|
?assertNot(emqx_message:get_flag(dup, Msg2)).
|
||||||
|
|
||||||
t_get_set_flags(_) ->
|
t_get_set_flags(_) ->
|
||||||
Msg = #message{id = <<"id">>, qos = ?QOS_1, flags = undefined},
|
Msg = #message{id = <<"id">>, qos = ?QOS_1},
|
||||||
Msg1 = emqx_message:set_flags(#{retain => true}, Msg),
|
Msg1 = emqx_message:set_flags(#{retain => true}, Msg),
|
||||||
?assertEqual(#{retain => true}, emqx_message:get_flags(Msg1)),
|
?assertEqual(#{retain => true}, emqx_message:get_flags(Msg1)),
|
||||||
Msg2 = emqx_message:set_flags(#{dup => true}, Msg1),
|
Msg2 = emqx_message:set_flags(#{dup => true}, Msg1),
|
||||||
|
@ -109,7 +109,7 @@ t_get_set_flag(_) ->
|
||||||
Msg6 = emqx_message:set_flags(#{dup => true, retain => true}, Msg5),
|
Msg6 = emqx_message:set_flags(#{dup => true, retain => true}, Msg5),
|
||||||
?assert(emqx_message:get_flag(dup, Msg6)),
|
?assert(emqx_message:get_flag(dup, Msg6)),
|
||||||
?assert(emqx_message:get_flag(retain, Msg6)),
|
?assert(emqx_message:get_flag(retain, Msg6)),
|
||||||
Msg7 = #message{id = <<"id">>, qos = ?QOS_1, flags = undefined},
|
Msg7 = #message{id = <<"id">>, qos = ?QOS_1},
|
||||||
Msg8 = emqx_message:set_flag(retain, Msg7),
|
Msg8 = emqx_message:set_flag(retain, Msg7),
|
||||||
Msg9 = emqx_message:set_flag(retain, true, Msg7),
|
Msg9 = emqx_message:set_flag(retain, true, Msg7),
|
||||||
?assertEqual(#{retain => true}, emqx_message:get_flags(Msg8)),
|
?assertEqual(#{retain => true}, emqx_message:get_flags(Msg8)),
|
||||||
|
@ -135,7 +135,7 @@ t_get_set_header(_) ->
|
||||||
?assertEqual(#{b => 2, c => 3}, emqx_message:get_headers(Msg4)).
|
?assertEqual(#{b => 2, c => 3}, emqx_message:get_headers(Msg4)).
|
||||||
|
|
||||||
t_undefined_headers(_) ->
|
t_undefined_headers(_) ->
|
||||||
Msg = #message{id = <<"id">>, qos = ?QOS_0, headers = undefined},
|
Msg = #message{id = <<"id">>, qos = ?QOS_0},
|
||||||
Msg1 = emqx_message:set_headers(#{a => 1, b => 2}, Msg),
|
Msg1 = emqx_message:set_headers(#{a => 1, b => 2}, Msg),
|
||||||
?assertEqual(1, emqx_message:get_header(a, Msg1)),
|
?assertEqual(1, emqx_message:get_header(a, Msg1)),
|
||||||
Msg2 = emqx_message:set_header(c, 3, Msg),
|
Msg2 = emqx_message:set_header(c, 3, Msg),
|
||||||
|
@ -144,14 +144,14 @@ t_undefined_headers(_) ->
|
||||||
t_format(_) ->
|
t_format(_) ->
|
||||||
Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>),
|
Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>),
|
||||||
io:format("~s~n", [emqx_message:format(Msg)]),
|
io:format("~s~n", [emqx_message:format(Msg)]),
|
||||||
Msg1 = emqx_message:set_header('Subscription-Identifier', 1,
|
Msg1 = emqx_message:set_header(properties, #{'Subscription-Identifier' => 1},
|
||||||
emqx_message:set_flag(dup, Msg)),
|
emqx_message:set_flag(dup, Msg)),
|
||||||
io:format("~s~n", [emqx_message:format(Msg1)]).
|
io:format("~s~n", [emqx_message:format(Msg1)]).
|
||||||
|
|
||||||
t_is_expired(_) ->
|
t_is_expired(_) ->
|
||||||
Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>),
|
Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>),
|
||||||
?assertNot(emqx_message:is_expired(Msg)),
|
?assertNot(emqx_message:is_expired(Msg)),
|
||||||
Msg1 = emqx_message:set_headers(#{'Message-Expiry-Interval' => 1}, Msg),
|
Msg1 = emqx_message:set_headers(#{properties => #{'Message-Expiry-Interval' => 1}}, Msg),
|
||||||
timer:sleep(500),
|
timer:sleep(500),
|
||||||
?assertNot(emqx_message:is_expired(Msg1)),
|
?assertNot(emqx_message:is_expired(Msg1)),
|
||||||
timer:sleep(600),
|
timer:sleep(600),
|
||||||
|
@ -159,7 +159,8 @@ t_is_expired(_) ->
|
||||||
timer:sleep(1000),
|
timer:sleep(1000),
|
||||||
Msg = emqx_message:update_expiry(Msg),
|
Msg = emqx_message:update_expiry(Msg),
|
||||||
Msg2 = emqx_message:update_expiry(Msg1),
|
Msg2 = emqx_message:update_expiry(Msg1),
|
||||||
?assertEqual(1, emqx_message:get_header('Message-Expiry-Interval', Msg2)).
|
Props = emqx_message:get_header(properties, Msg2),
|
||||||
|
?assertEqual(1, maps:get('Message-Expiry-Interval', Props)).
|
||||||
|
|
||||||
% t_to_list(_) ->
|
% t_to_list(_) ->
|
||||||
% error('TODO').
|
% error('TODO').
|
||||||
|
@ -172,7 +173,7 @@ t_to_packet(_) ->
|
||||||
},
|
},
|
||||||
variable = #mqtt_packet_publish{topic_name = <<"topic">>,
|
variable = #mqtt_packet_publish{topic_name = <<"topic">>,
|
||||||
packet_id = 10,
|
packet_id = 10,
|
||||||
properties = undefined
|
properties = #{}
|
||||||
},
|
},
|
||||||
payload = <<"payload">>
|
payload = <<"payload">>
|
||||||
},
|
},
|
||||||
|
@ -193,7 +194,7 @@ t_to_packet_with_props(_) ->
|
||||||
payload = <<"payload">>
|
payload = <<"payload">>
|
||||||
},
|
},
|
||||||
Msg = emqx_message:make(<<"clientid">>, ?QOS_0, <<"topic">>, <<"payload">>),
|
Msg = emqx_message:make(<<"clientid">>, ?QOS_0, <<"topic">>, <<"payload">>),
|
||||||
Msg1 = emqx_message:set_header('Subscription-Identifier', 1, Msg),
|
Msg1 = emqx_message:set_header(properties, #{'Subscription-Identifier' => 1}, Msg),
|
||||||
?assertEqual(Pkt, emqx_message:to_packet(10, Msg1)).
|
?assertEqual(Pkt, emqx_message:to_packet(10, Msg1)).
|
||||||
|
|
||||||
t_to_map(_) ->
|
t_to_map(_) ->
|
||||||
|
@ -201,8 +202,8 @@ t_to_map(_) ->
|
||||||
List = [{id, emqx_message:id(Msg)},
|
List = [{id, emqx_message:id(Msg)},
|
||||||
{qos, ?QOS_1},
|
{qos, ?QOS_1},
|
||||||
{from, <<"clientid">>},
|
{from, <<"clientid">>},
|
||||||
{flags, undefined},
|
{flags, #{}},
|
||||||
{headers, undefined},
|
{headers, #{}},
|
||||||
{topic, <<"topic">>},
|
{topic, <<"topic">>},
|
||||||
{payload, <<"payload">>},
|
{payload, <<"payload">>},
|
||||||
{timestamp, emqx_message:timestamp(Msg)}],
|
{timestamp, emqx_message:timestamp(Msg)}],
|
||||||
|
|
|
@ -85,7 +85,6 @@ t_connect_info(_) ->
|
||||||
will_retain = true,
|
will_retain = true,
|
||||||
will_qos = ?QOS_2,
|
will_qos = ?QOS_2,
|
||||||
will_topic = <<"topic">>,
|
will_topic = <<"topic">>,
|
||||||
will_props = undefined,
|
|
||||||
will_payload = <<"payload">>
|
will_payload = <<"payload">>
|
||||||
},
|
},
|
||||||
?assertEqual(<<"MQTT">>, emqx_packet:info(proto_name, ConnPkt)),
|
?assertEqual(<<"MQTT">>, emqx_packet:info(proto_name, ConnPkt)),
|
||||||
|
@ -96,9 +95,9 @@ t_connect_info(_) ->
|
||||||
?assertEqual(?QOS_2, emqx_packet:info(will_qos, ConnPkt)),
|
?assertEqual(?QOS_2, emqx_packet:info(will_qos, ConnPkt)),
|
||||||
?assertEqual(true, emqx_packet:info(will_retain, ConnPkt)),
|
?assertEqual(true, emqx_packet:info(will_retain, ConnPkt)),
|
||||||
?assertEqual(0, emqx_packet:info(keepalive, ConnPkt)),
|
?assertEqual(0, emqx_packet:info(keepalive, ConnPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, ConnPkt)),
|
?assertEqual(#{}, emqx_packet:info(properties, ConnPkt)),
|
||||||
?assertEqual(<<"clientid">>, emqx_packet:info(clientid, ConnPkt)),
|
?assertEqual(<<"clientid">>, emqx_packet:info(clientid, ConnPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(will_props, ConnPkt)),
|
?assertEqual(#{}, emqx_packet:info(will_props, ConnPkt)),
|
||||||
?assertEqual(<<"topic">>, emqx_packet:info(will_topic, ConnPkt)),
|
?assertEqual(<<"topic">>, emqx_packet:info(will_topic, ConnPkt)),
|
||||||
?assertEqual(<<"payload">>, emqx_packet:info(will_payload, ConnPkt)),
|
?assertEqual(<<"payload">>, emqx_packet:info(will_payload, ConnPkt)),
|
||||||
?assertEqual(<<"username">>, emqx_packet:info(username, ConnPkt)),
|
?assertEqual(<<"username">>, emqx_packet:info(username, ConnPkt)),
|
||||||
|
@ -108,54 +107,54 @@ t_connack_info(_) ->
|
||||||
AckPkt = #mqtt_packet_connack{ack_flags = 0, reason_code = 0},
|
AckPkt = #mqtt_packet_connack{ack_flags = 0, reason_code = 0},
|
||||||
?assertEqual(0, emqx_packet:info(ack_flags, AckPkt)),
|
?assertEqual(0, emqx_packet:info(ack_flags, AckPkt)),
|
||||||
?assertEqual(0, emqx_packet:info(reason_code, AckPkt)),
|
?assertEqual(0, emqx_packet:info(reason_code, AckPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, AckPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, AckPkt)).
|
||||||
|
|
||||||
t_publish_info(_) ->
|
t_publish_info(_) ->
|
||||||
PubPkt = #mqtt_packet_publish{topic_name = <<"t">>, packet_id = 1},
|
PubPkt = #mqtt_packet_publish{topic_name = <<"t">>, packet_id = 1},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, PubPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, PubPkt)),
|
||||||
?assertEqual(<<"t">>, emqx_packet:info(topic_name, PubPkt)),
|
?assertEqual(<<"t">>, emqx_packet:info(topic_name, PubPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, PubPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, PubPkt)).
|
||||||
|
|
||||||
t_puback_info(_) ->
|
t_puback_info(_) ->
|
||||||
AckPkt = #mqtt_packet_puback{packet_id = 1, reason_code = 0},
|
AckPkt = #mqtt_packet_puback{packet_id = 1, reason_code = 0},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, AckPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, AckPkt)),
|
||||||
?assertEqual(0, emqx_packet:info(reason_code, AckPkt)),
|
?assertEqual(0, emqx_packet:info(reason_code, AckPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, AckPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, AckPkt)).
|
||||||
|
|
||||||
t_subscribe_info(_) ->
|
t_subscribe_info(_) ->
|
||||||
TopicFilters = [{<<"t/#">>, #{}}],
|
TopicFilters = [{<<"t/#">>, #{}}],
|
||||||
SubPkt = #mqtt_packet_subscribe{packet_id = 1, topic_filters = TopicFilters},
|
SubPkt = #mqtt_packet_subscribe{packet_id = 1, topic_filters = TopicFilters},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, SubPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, SubPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, SubPkt)),
|
?assertEqual(#{}, emqx_packet:info(properties, SubPkt)),
|
||||||
?assertEqual(TopicFilters, emqx_packet:info(topic_filters, SubPkt)).
|
?assertEqual(TopicFilters, emqx_packet:info(topic_filters, SubPkt)).
|
||||||
|
|
||||||
t_suback_info(_) ->
|
t_suback_info(_) ->
|
||||||
SubackPkt = #mqtt_packet_suback{packet_id = 1, reason_codes = [0]},
|
SubackPkt = #mqtt_packet_suback{packet_id = 1, reason_codes = [0]},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, SubackPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, SubackPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, SubackPkt)),
|
?assertEqual(#{}, emqx_packet:info(properties, SubackPkt)),
|
||||||
?assertEqual([0], emqx_packet:info(reason_codes, SubackPkt)).
|
?assertEqual([0], emqx_packet:info(reason_codes, SubackPkt)).
|
||||||
|
|
||||||
t_unsubscribe_info(_) ->
|
t_unsubscribe_info(_) ->
|
||||||
UnsubPkt = #mqtt_packet_unsubscribe{packet_id = 1, topic_filters = [<<"t/#">>]},
|
UnsubPkt = #mqtt_packet_unsubscribe{packet_id = 1, topic_filters = [<<"t/#">>]},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, UnsubPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, UnsubPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, UnsubPkt)),
|
?assertEqual(#{}, emqx_packet:info(properties, UnsubPkt)),
|
||||||
?assertEqual([<<"t/#">>], emqx_packet:info(topic_filters, UnsubPkt)).
|
?assertEqual([<<"t/#">>], emqx_packet:info(topic_filters, UnsubPkt)).
|
||||||
|
|
||||||
t_unsuback_info(_) ->
|
t_unsuback_info(_) ->
|
||||||
AckPkt = #mqtt_packet_unsuback{packet_id = 1, reason_codes = [0]},
|
AckPkt = #mqtt_packet_unsuback{packet_id = 1, reason_codes = [0]},
|
||||||
?assertEqual(1, emqx_packet:info(packet_id, AckPkt)),
|
?assertEqual(1, emqx_packet:info(packet_id, AckPkt)),
|
||||||
?assertEqual([0], emqx_packet:info(reason_codes, AckPkt)),
|
?assertEqual([0], emqx_packet:info(reason_codes, AckPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, AckPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, AckPkt)).
|
||||||
|
|
||||||
t_disconnect_info(_) ->
|
t_disconnect_info(_) ->
|
||||||
DisconnPkt = #mqtt_packet_disconnect{reason_code = 0},
|
DisconnPkt = #mqtt_packet_disconnect{reason_code = 0},
|
||||||
?assertEqual(0, emqx_packet:info(reason_code, DisconnPkt)),
|
?assertEqual(0, emqx_packet:info(reason_code, DisconnPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, DisconnPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, DisconnPkt)).
|
||||||
|
|
||||||
t_auth_info(_) ->
|
t_auth_info(_) ->
|
||||||
AuthPkt = #mqtt_packet_auth{reason_code = 0},
|
AuthPkt = #mqtt_packet_auth{reason_code = 0},
|
||||||
?assertEqual(0, emqx_packet:info(reason_code, AuthPkt)),
|
?assertEqual(0, emqx_packet:info(reason_code, AuthPkt)),
|
||||||
?assertEqual(undefined, emqx_packet:info(properties, AuthPkt)).
|
?assertEqual(#{}, emqx_packet:info(properties, AuthPkt)).
|
||||||
|
|
||||||
t_set_props(_) ->
|
t_set_props(_) ->
|
||||||
Pkts = [#mqtt_packet_connect{}, #mqtt_packet_connack{}, #mqtt_packet_publish{},
|
Pkts = [#mqtt_packet_connect{}, #mqtt_packet_connack{}, #mqtt_packet_publish{},
|
||||||
|
@ -245,6 +244,7 @@ t_from_to_message(_) ->
|
||||||
ExpectedMsg1 = emqx_message:set_flags(#{dup => false, retain => false}, ExpectedMsg),
|
ExpectedMsg1 = emqx_message:set_flags(#{dup => false, retain => false}, ExpectedMsg),
|
||||||
ExpectedMsg2 = emqx_message:set_headers(#{peerhost => {127,0,0,1},
|
ExpectedMsg2 = emqx_message:set_headers(#{peerhost => {127,0,0,1},
|
||||||
protocol => mqtt,
|
protocol => mqtt,
|
||||||
|
properties => #{},
|
||||||
username => <<"test">>
|
username => <<"test">>
|
||||||
}, ExpectedMsg1),
|
}, ExpectedMsg1),
|
||||||
Pkt = #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
Pkt = #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
|
||||||
|
@ -255,10 +255,10 @@ t_from_to_message(_) ->
|
||||||
packet_id = 10,
|
packet_id = 10,
|
||||||
properties = #{}},
|
properties = #{}},
|
||||||
payload = <<"payload">>},
|
payload = <<"payload">>},
|
||||||
MsgFromPkt = emqx_packet:to_message(#{protocol => mqtt,
|
MsgFromPkt = emqx_packet:to_message(Pkt, <<"clientid">>,
|
||||||
clientid => <<"clientid">>,
|
#{protocol => mqtt,
|
||||||
username => <<"test">>,
|
username => <<"test">>,
|
||||||
peerhost => {127,0,0,1}}, Pkt),
|
peerhost => {127,0,0,1}}),
|
||||||
?assertEqual(ExpectedMsg2, MsgFromPkt#message{id = emqx_message:id(ExpectedMsg),
|
?assertEqual(ExpectedMsg2, MsgFromPkt#message{id = emqx_message:id(ExpectedMsg),
|
||||||
timestamp = emqx_message:timestamp(ExpectedMsg)
|
timestamp = emqx_message:timestamp(ExpectedMsg)
|
||||||
}).
|
}).
|
||||||
|
@ -283,7 +283,6 @@ t_will_msg(_) ->
|
||||||
will_retain = true,
|
will_retain = true,
|
||||||
will_qos = ?QOS_2,
|
will_qos = ?QOS_2,
|
||||||
will_topic = <<"topic">>,
|
will_topic = <<"topic">>,
|
||||||
will_props = undefined,
|
|
||||||
will_payload = <<"payload">>
|
will_payload = <<"payload">>
|
||||||
},
|
},
|
||||||
Msg2 = emqx_packet:will_msg(Pkt2),
|
Msg2 = emqx_packet:will_msg(Pkt2),
|
||||||
|
@ -297,7 +296,6 @@ t_format(_) ->
|
||||||
will_retain = true,
|
will_retain = true,
|
||||||
will_qos = ?QOS_2,
|
will_qos = ?QOS_2,
|
||||||
will_topic = <<"topic">>,
|
will_topic = <<"topic">>,
|
||||||
will_props = undefined,
|
|
||||||
will_payload = <<"payload">>}))]),
|
will_payload = <<"payload">>}))]),
|
||||||
io:format("~s", [emqx_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{password = password}))]),
|
io:format("~s", [emqx_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{password = password}))]),
|
||||||
io:format("~s", [emqx_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]),
|
io:format("~s", [emqx_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]),
|
||||||
|
|
|
@ -116,9 +116,9 @@ t_is_subscriptions_full_true(_) ->
|
||||||
t_unsubscribe(_) ->
|
t_unsubscribe(_) ->
|
||||||
ok = meck:expect(emqx_broker, unsubscribe, fun(_) -> ok end),
|
ok = meck:expect(emqx_broker, unsubscribe, fun(_) -> ok end),
|
||||||
Session = session(#{subscriptions => #{<<"#">> => subopts()}}),
|
Session = session(#{subscriptions => #{<<"#">> => subopts()}}),
|
||||||
{ok, Session1} = emqx_session:unsubscribe(clientinfo(), <<"#">>, Session),
|
{ok, Session1} = emqx_session:unsubscribe(clientinfo(), <<"#">>, #{}, Session),
|
||||||
{error, ?RC_NO_SUBSCRIPTION_EXISTED} =
|
{error, ?RC_NO_SUBSCRIPTION_EXISTED} =
|
||||||
emqx_session:unsubscribe(clientinfo(), <<"#">>, Session1).
|
emqx_session:unsubscribe(clientinfo(), <<"#">>, #{}, Session1).
|
||||||
|
|
||||||
t_publish_qos0(_) ->
|
t_publish_qos0(_) ->
|
||||||
ok = meck:expect(emqx_broker, publish, fun(_) -> [] end),
|
ok = meck:expect(emqx_broker, publish, fun(_) -> [] end),
|
||||||
|
|
|
@ -304,7 +304,7 @@ t_parse_incoming(_) ->
|
||||||
St = ?ws_conn:parse_incoming(<<48,3>>, st()),
|
St = ?ws_conn:parse_incoming(<<48,3>>, st()),
|
||||||
St1 = ?ws_conn:parse_incoming(<<0,1,116>>, St),
|
St1 = ?ws_conn:parse_incoming(<<0,1,116>>, St),
|
||||||
Packet = ?PUBLISH_PACKET(?QOS_0, <<"t">>, undefined, <<>>),
|
Packet = ?PUBLISH_PACKET(?QOS_0, <<"t">>, undefined, <<>>),
|
||||||
[{incoming, Packet}] = ?ws_conn:info(postponed, St1).
|
?assertMatch([{incoming, Packet}], ?ws_conn:info(postponed, St1)).
|
||||||
|
|
||||||
t_parse_incoming_frame_error(_) ->
|
t_parse_incoming_frame_error(_) ->
|
||||||
St = ?ws_conn:parse_incoming(<<3,2,1,0>>, st()),
|
St = ?ws_conn:parse_incoming(<<3,2,1,0>>, st()),
|
||||||
|
|
Loading…
Reference in New Issue