diff --git a/apps/emqx_gateway_mqttsn/include/emqx_mqttsn.hrl b/apps/emqx_gateway_mqttsn/include/emqx_mqttsn.hrl index 5ab2d4a05..2b63e8c12 100644 --- a/apps/emqx_gateway_mqttsn/include/emqx_mqttsn.hrl +++ b/apps/emqx_gateway_mqttsn/include/emqx_mqttsn.hrl @@ -14,6 +14,8 @@ %% limitations under the License. %%-------------------------------------------------------------------- +-define(SN_MAX_PREDEF_TOPIC_ID, 1024). + %%-------------------------------------------------------------------- %% MQTT-SN Types %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_registry.erl b/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_registry.erl index ce3495c52..7cf665f76 100644 --- a/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_registry.erl +++ b/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_registry.erl @@ -33,38 +33,40 @@ ]). -define(PKEY(Id), {mqttsn, predef_topics, Id}). --define(PKEY_MAX_PREDEF_ID, {mqttsn, max_predef_topic_id}). -type registry() :: #{ %% The next topic id to be assigned to new registration - next_topic_id := pos_integer(), + last_topic_id := pos_integer(), %% The mapping from topic id to topic name id_to_name := map(), %% The mapping from topic name to topic id name_to_id := map() }. -%%----------------------------------------------------------------------------- +-type predef_topic() :: #{ + id := 1..1024, + topic := iolist() +}. --spec persist_predefined_topics(list()) -> ok. +%%----------------------------------------------------------------------------- +%% APIs + +-spec persist_predefined_topics([predef_topic()]) -> ok. persist_predefined_topics(PredefTopics) when is_list(PredefTopics) -> - MaxPredefId = lists:foldl( - fun(#{id := TopicId, topic := TopicName0}, AccId) -> + try + F = fun(#{id := TopicId, topic := TopicName0}) when TopicId =< 1024 -> TopicName = iolist_to_binary(TopicName0), persistent_term:put(?PKEY(TopicId), TopicName), - persistent_term:put(?PKEY(TopicName), TopicId), - case TopicId > AccId of - true -> TopicId; - false -> AccId - end + persistent_term:put(?PKEY(TopicName), TopicId) end, - 0, - PredefTopics - ), - persistent_term:put(?PKEY_MAX_PREDEF_ID, MaxPredefId), - ok. + lists:foreach(F, PredefTopics) + catch + _:_ -> + clear_predefined_topics(PredefTopics), + error(badarg) + end. --spec clear_predefined_topics(list()) -> ok. +-spec clear_predefined_topics([predef_topic()]) -> ok. clear_predefined_topics(PredefTopics) -> lists:foreach( fun(#{id := TopicId, topic := TopicName0}) -> @@ -74,13 +76,12 @@ clear_predefined_topics(PredefTopics) -> end, PredefTopics ), - persistent_term:erase(?PKEY_MAX_PREDEF_ID), ok. -spec init() -> registry(). init() -> #{ - next_topic_id => persistent_term:get(?PKEY_MAX_PREDEF_ID, 0), + last_topic_id => ?SN_MAX_PREDEF_TOPIC_ID, id_to_name => #{}, name_to_id => #{} }. @@ -113,7 +114,7 @@ reg( do_reg( TopicName, Registry = #{ - next_topic_id := TopicId0, + last_topic_id := TopicId0, id_to_name := IdMap, name_to_id := NameMap } @@ -123,7 +124,7 @@ do_reg( {error, too_large}; NextTopicId -> NRegistry = Registry#{ - next_topic_id := NextTopicId, + last_topic_id := NextTopicId, id_to_name := maps:put(NextTopicId, TopicName, IdMap), name_to_id := maps:put(TopicName, NextTopicId, NameMap) }, diff --git a/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_schema.erl b/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_schema.erl index 8adf7a934..08fb854b4 100644 --- a/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_schema.erl +++ b/apps/emqx_gateway_mqttsn/src/emqx_mqttsn_schema.erl @@ -16,6 +16,7 @@ -module(emqx_mqttsn_schema). +-include("emqx_mqttsn.hrl"). -include_lib("hocon/include/hoconsc.hrl"). -include_lib("typerefl/include/types.hrl"). @@ -72,7 +73,7 @@ fields(mqttsn) -> fields(mqttsn_predefined) -> [ {id, - sc(integer(), #{ + sc(range(1, ?SN_MAX_PREDEF_TOPIC_ID), #{ required => true, desc => ?DESC(mqttsn_predefined_id) })}, diff --git a/apps/emqx_gateway_mqttsn/test/emqx_sn_protocol_SUITE.erl b/apps/emqx_gateway_mqttsn/test/emqx_sn_protocol_SUITE.erl index 92e5e2ddf..c3fa89c70 100644 --- a/apps/emqx_gateway_mqttsn/test/emqx_sn_protocol_SUITE.erl +++ b/apps/emqx_gateway_mqttsn/test/emqx_sn_protocol_SUITE.erl @@ -47,7 +47,7 @@ -define(LOG(Format, Args), ct:log("TEST: " ++ Format, Args)). --define(MAX_PRED_TOPIC_ID, 2). +-define(MAX_PRED_TOPIC_ID, ?SN_MAX_PREDEF_TOPIC_ID). -define(PREDEF_TOPIC_ID1, 1). -define(PREDEF_TOPIC_ID2, 2). -define(PREDEF_TOPIC_NAME1, <<"/predefined/topic/name/hello">>). diff --git a/apps/emqx_gateway_mqttsn/test/emqx_sn_registry_SUITE.erl b/apps/emqx_gateway_mqttsn/test/emqx_sn_registry_SUITE.erl index 6c821ebf4..8d60570a0 100644 --- a/apps/emqx_gateway_mqttsn/test/emqx_sn_registry_SUITE.erl +++ b/apps/emqx_gateway_mqttsn/test/emqx_sn_registry_SUITE.erl @@ -19,10 +19,11 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx_mqttsn.hrl"). -include_lib("eunit/include/eunit.hrl"). -define(REGISTRY, emqx_mqttsn_registry). --define(MAX_PREDEF_ID, 2). +-define(MAX_PREDEF_ID, ?SN_MAX_PREDEF_TOPIC_ID). -define(PREDEF_TOPICS, [ #{id => 1, topic => <<"/predefined/topic/name/hello">>}, #{id => 2, topic => <<"/predefined/topic/name/nice">>} @@ -75,8 +76,8 @@ t_reach_maximum(_) -> Reg0 = ?REGISTRY:init(), Reg = register_a_lot(?MAX_PREDEF_ID + 1, 16#ffff, Reg0), ?assertEqual({error, too_large}, ?REGISTRY:reg(<<"TopicABC">>, Reg)), - ?assertEqual(?MAX_PREDEF_ID + 1, ?REGISTRY:lookup_topic_id(<<"Topic3">>, Reg)), - ?assertEqual(?MAX_PREDEF_ID + 2, ?REGISTRY:lookup_topic_id(<<"Topic4">>, Reg)). + ?assertEqual(?MAX_PREDEF_ID + 1, ?REGISTRY:lookup_topic_id(<<"Topic1025">>, Reg)), + ?assertEqual(?MAX_PREDEF_ID + 2, ?REGISTRY:lookup_topic_id(<<"Topic1026">>, Reg)). t_deny_wildcard_topic(_) -> Reg = ?REGISTRY:init(),