|
|
@@ -25,6 +25,12 @@
|
|
|
, validate/1
|
|
|
]).
|
|
|
|
|
|
+%% For tests
|
|
|
+-export([all/0]).
|
|
|
+
|
|
|
+-type(prop_name() :: atom()).
|
|
|
+-type(prop_id() :: pos_integer()).
|
|
|
+
|
|
|
-define(PROPS_TABLE,
|
|
|
#{16#01 => {'Payload-Format-Indicator', 'Byte', [?PUBLISH]},
|
|
|
16#02 => {'Message-Expiry-Interval', 'Four-Byte-Integer', [?PUBLISH]},
|
|
|
@@ -52,36 +58,10 @@
|
|
|
16#27 => {'Maximum-Packet-Size', 'Four-Byte-Integer', [?CONNECT, ?CONNACK]},
|
|
|
16#28 => {'Wildcard-Subscription-Available', 'Byte', [?CONNACK]},
|
|
|
16#29 => {'Subscription-Identifier-Available', 'Byte', [?CONNACK]},
|
|
|
- 16#2A => {'Shared-Subscription-Available', 'Byte', [?CONNACK]}}).
|
|
|
-
|
|
|
-name(16#01) -> 'Payload-Format-Indicator';
|
|
|
-name(16#02) -> 'Message-Expiry-Interval';
|
|
|
-name(16#03) -> 'Content-Type';
|
|
|
-name(16#08) -> 'Response-Topic';
|
|
|
-name(16#09) -> 'Correlation-Data';
|
|
|
-name(16#0B) -> 'Subscription-Identifier';
|
|
|
-name(16#11) -> 'Session-Expiry-Interval';
|
|
|
-name(16#12) -> 'Assigned-Client-Identifier';
|
|
|
-name(16#13) -> 'Server-Keep-Alive';
|
|
|
-name(16#15) -> 'Authentication-Method';
|
|
|
-name(16#16) -> 'Authentication-Data';
|
|
|
-name(16#17) -> 'Request-Problem-Information';
|
|
|
-name(16#18) -> 'Will-Delay-Interval';
|
|
|
-name(16#19) -> 'Request-Response-Information';
|
|
|
-name(16#1A) -> 'Response-Information';
|
|
|
-name(16#1C) -> 'Server-Reference';
|
|
|
-name(16#1F) -> 'Reason-String';
|
|
|
-name(16#21) -> 'Receive-Maximum';
|
|
|
-name(16#22) -> 'Topic-Alias-Maximum';
|
|
|
-name(16#23) -> 'Topic-Alias';
|
|
|
-name(16#24) -> 'Maximum-QoS';
|
|
|
-name(16#25) -> 'Retain-Available';
|
|
|
-name(16#26) -> 'User-Property';
|
|
|
-name(16#27) -> 'Maximum-Packet-Size';
|
|
|
-name(16#28) -> 'Wildcard-Subscription-Available';
|
|
|
-name(16#29) -> 'Subscription-Identifier-Available';
|
|
|
-name(16#2A) -> 'Shared-Subscription-Available'.
|
|
|
+ 16#2A => {'Shared-Subscription-Available', 'Byte', [?CONNACK]}
|
|
|
+ }).
|
|
|
|
|
|
+-spec(id(prop_name()) -> prop_id()).
|
|
|
id('Payload-Format-Indicator') -> 16#01;
|
|
|
id('Message-Expiry-Interval') -> 16#02;
|
|
|
id('Content-Type') -> 16#03;
|
|
|
@@ -108,12 +88,47 @@ id('User-Property') -> 16#26;
|
|
|
id('Maximum-Packet-Size') -> 16#27;
|
|
|
id('Wildcard-Subscription-Available') -> 16#28;
|
|
|
id('Subscription-Identifier-Available') -> 16#29;
|
|
|
-id('Shared-Subscription-Available') -> 16#2A.
|
|
|
+id('Shared-Subscription-Available') -> 16#2A;
|
|
|
+id(Name) -> error({bad_property, Name}).
|
|
|
|
|
|
+-spec(name(prop_id()) -> prop_name()).
|
|
|
+name(16#01) -> 'Payload-Format-Indicator';
|
|
|
+name(16#02) -> 'Message-Expiry-Interval';
|
|
|
+name(16#03) -> 'Content-Type';
|
|
|
+name(16#08) -> 'Response-Topic';
|
|
|
+name(16#09) -> 'Correlation-Data';
|
|
|
+name(16#0B) -> 'Subscription-Identifier';
|
|
|
+name(16#11) -> 'Session-Expiry-Interval';
|
|
|
+name(16#12) -> 'Assigned-Client-Identifier';
|
|
|
+name(16#13) -> 'Server-Keep-Alive';
|
|
|
+name(16#15) -> 'Authentication-Method';
|
|
|
+name(16#16) -> 'Authentication-Data';
|
|
|
+name(16#17) -> 'Request-Problem-Information';
|
|
|
+name(16#18) -> 'Will-Delay-Interval';
|
|
|
+name(16#19) -> 'Request-Response-Information';
|
|
|
+name(16#1A) -> 'Response-Information';
|
|
|
+name(16#1C) -> 'Server-Reference';
|
|
|
+name(16#1F) -> 'Reason-String';
|
|
|
+name(16#21) -> 'Receive-Maximum';
|
|
|
+name(16#22) -> 'Topic-Alias-Maximum';
|
|
|
+name(16#23) -> 'Topic-Alias';
|
|
|
+name(16#24) -> 'Maximum-QoS';
|
|
|
+name(16#25) -> 'Retain-Available';
|
|
|
+name(16#26) -> 'User-Property';
|
|
|
+name(16#27) -> 'Maximum-Packet-Size';
|
|
|
+name(16#28) -> 'Wildcard-Subscription-Available';
|
|
|
+name(16#29) -> 'Subscription-Identifier-Available';
|
|
|
+name(16#2A) -> 'Shared-Subscription-Available';
|
|
|
+name(Id) -> error({unsupported_property, Id}).
|
|
|
+
|
|
|
+-spec(filter(emqx_types:packet_type(), emqx_types:properties()|list())
|
|
|
+ -> emqx_types:properties()).
|
|
|
filter(PacketType, Props) when is_map(Props) ->
|
|
|
maps:from_list(filter(PacketType, maps:to_list(Props)));
|
|
|
|
|
|
-filter(PacketType, Props) when ?CONNECT =< PacketType, PacketType =< ?AUTH, is_list(Props) ->
|
|
|
+filter(PacketType, Props) when ?CONNECT =< PacketType,
|
|
|
+ PacketType =< ?AUTH,
|
|
|
+ is_list(Props) ->
|
|
|
Filter = fun(Name) ->
|
|
|
case maps:find(id(Name), ?PROPS_TABLE) of
|
|
|
{ok, {Name, _Type, 'ALL'}} ->
|
|
|
@@ -125,6 +140,7 @@ filter(PacketType, Props) when ?CONNECT =< PacketType, PacketType =< ?AUTH, is_l
|
|
|
end,
|
|
|
[Prop || Prop = {Name, _} <- Props, Filter(Name)].
|
|
|
|
|
|
+-spec(validate(emqx_types:properties()) -> ok).
|
|
|
validate(Props) when is_map(Props) ->
|
|
|
lists:foreach(fun validate_prop/1, maps:to_list(Props)).
|
|
|
|
|
|
@@ -132,23 +148,32 @@ validate_prop(Prop = {Name, Val}) ->
|
|
|
case maps:find(id(Name), ?PROPS_TABLE) of
|
|
|
{ok, {Name, Type, _}} ->
|
|
|
validate_value(Type, Val)
|
|
|
- orelse error(bad_property, Prop);
|
|
|
+ orelse error({bad_property_value, Prop});
|
|
|
error ->
|
|
|
- error({bad_property, Prop})
|
|
|
+ error({bad_property, Name})
|
|
|
end.
|
|
|
|
|
|
validate_value('Byte', Val) ->
|
|
|
- is_integer(Val);
|
|
|
+ is_integer(Val) andalso Val =< 16#FF;
|
|
|
validate_value('Two-Byte-Integer', Val) ->
|
|
|
- is_integer(Val);
|
|
|
+ is_integer(Val) andalso 0 =< Val andalso Val =< 16#FFFF;
|
|
|
validate_value('Four-Byte-Integer', Val) ->
|
|
|
- is_integer(Val);
|
|
|
+ is_integer(Val) andalso 0 =< Val andalso Val =< 16#FFFFFFFF;
|
|
|
validate_value('Variable-Byte-Integer', Val) ->
|
|
|
- is_integer(Val);
|
|
|
+ is_integer(Val) andalso 0 =< Val andalso Val =< 16#7FFFFFFF;
|
|
|
+validate_value('UTF8-String-Pair', {Name, Val}) ->
|
|
|
+ validate_value('UTF8-Encoded-String', Name)
|
|
|
+ andalso validate_value('UTF8-Encoded-String', Val);
|
|
|
+validate_value('UTF8-String-Pair', Pairs) when is_list(Pairs) ->
|
|
|
+ lists:foldl(fun(Pair, OK) ->
|
|
|
+ OK andalso validate_value('UTF8-String-Pair', Pair)
|
|
|
+ end, true, Pairs);
|
|
|
validate_value('UTF8-Encoded-String', Val) ->
|
|
|
is_binary(Val);
|
|
|
validate_value('Binary-Data', Val) ->
|
|
|
is_binary(Val);
|
|
|
-validate_value('UTF8-String-Pair', Val) ->
|
|
|
- is_tuple(Val) orelse is_list(Val).
|
|
|
+validate_value(_Type, _Val) -> false.
|
|
|
+
|
|
|
+-spec(all() -> map()).
|
|
|
+all() -> ?PROPS_TABLE.
|
|
|
|