chore(test): delete plugin_template from plugins_SUITE
This commit is contained in:
parent
3414e0b601
commit
1ef2b8d06c
|
@ -13,7 +13,7 @@
|
|||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
-module(emqx_mgmt_api_plugin).
|
||||
-module(emqx_mgmt_api_plugins).
|
||||
|
||||
-behaviour(minirest_api).
|
||||
|
||||
|
@ -65,7 +65,7 @@ schema("/plugins") ->
|
|||
'operationId' => list_plugins,
|
||||
get => #{
|
||||
description => "List all install plugins.<br>"
|
||||
"Plugins starts in the order of the list from the top to the bottom. <br>"
|
||||
"Plugins are launched in top-down order.<br>"
|
||||
"Using `POST /plugins/{name}/move` to change the boot order.",
|
||||
responses => #{
|
||||
200 => hoconsc:array(hoconsc:ref(plugin))
|
|
@ -1 +0,0 @@
|
|||
Subproject commit ddab50fafeed6b1faea70fc9ffd8c700d7e26ec1
|
|
@ -1,21 +0,0 @@
|
|||
# emqx-plugin-template
|
||||
|
||||
This is a template plugin for EMQ X >= 5.0.
|
||||
|
||||
For EMQ X >= 4.3, please see branch emqx-v4
|
||||
|
||||
For older EMQ X versions, plugin development is no longer maintained.
|
||||
|
||||
## Release
|
||||
|
||||
A EMQ X plugin release is a zip package including
|
||||
|
||||
1. A JSON format metadata file
|
||||
2. A tar file with plugin's apps packed
|
||||
|
||||
Execute `make rel` to have the package created like:
|
||||
|
||||
```
|
||||
_build/default/emqx_plugrel/emqx_plugin_template-<vsn>.tar.gz
|
||||
```
|
||||
See EMQ X documents for details on how to deploy the plugin.
|
|
@ -1,4 +0,0 @@
|
|||
## This is a demo config in HOCON format
|
||||
## The same format used by EMQ X since 5.0
|
||||
|
||||
magic_n = 42
|
|
@ -1,26 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_cli_demo).
|
||||
|
||||
-export([cmd/1]).
|
||||
|
||||
cmd(["arg1", "arg2"]) ->
|
||||
emqx_ctl:print("ok");
|
||||
|
||||
cmd(_) ->
|
||||
emqx_ctl:usage([{"cmd arg1 arg2", "cmd demo"}]).
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
{application, emqx_plugin_template,
|
||||
[{description, "EMQ X Plugin Template"},
|
||||
{vsn, "5.0.0"},
|
||||
{modules, []},
|
||||
{registered, [emqx_plugin_template_sup]},
|
||||
{applications, [kernel,stdlib,map_sets]},
|
||||
{mod, {emqx_plugin_template_app,[]}},
|
||||
{env, []},
|
||||
{licenses, ["Apache-2.0"]},
|
||||
{maintainers, ["EMQ X Team <contact@emqx.io>"]},
|
||||
{links, [{"Homepage", "https://emqx.io/"},
|
||||
{"Github", "https://github.com/emqx/emqx-plugin-template"}
|
||||
]}
|
||||
]}.
|
|
@ -1,198 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_plugin_template).
|
||||
|
||||
%% for #message{} record
|
||||
%% no need for this include if we call emqx_message:to_map/1 to convert it to a map
|
||||
-include_lib("emqx/include/emqx.hrl").
|
||||
|
||||
%% for logging
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
|
||||
-export([ load/1
|
||||
, unload/0
|
||||
]).
|
||||
|
||||
%% Client Lifecircle Hooks
|
||||
-export([ on_client_connect/3
|
||||
, on_client_connack/4
|
||||
, on_client_connected/3
|
||||
, on_client_disconnected/4
|
||||
, on_client_authenticate/3
|
||||
, on_client_check_acl/5
|
||||
, on_client_subscribe/4
|
||||
, on_client_unsubscribe/4
|
||||
]).
|
||||
|
||||
%% Session Lifecircle Hooks
|
||||
-export([ on_session_created/3
|
||||
, on_session_subscribed/4
|
||||
, on_session_unsubscribed/4
|
||||
, on_session_resumed/3
|
||||
, on_session_discarded/3
|
||||
, on_session_takeovered/3
|
||||
, on_session_terminated/4
|
||||
]).
|
||||
|
||||
%% Message Pubsub Hooks
|
||||
-export([ on_message_publish/2
|
||||
, on_message_delivered/3
|
||||
, on_message_acked/3
|
||||
, on_message_dropped/4
|
||||
]).
|
||||
|
||||
%% Called when the plugin application start
|
||||
load(Env) ->
|
||||
emqx:hook('client.connect', {?MODULE, on_client_connect, [Env]}),
|
||||
emqx:hook('client.connack', {?MODULE, on_client_connack, [Env]}),
|
||||
emqx:hook('client.connected', {?MODULE, on_client_connected, [Env]}),
|
||||
emqx:hook('client.disconnected', {?MODULE, on_client_disconnected, [Env]}),
|
||||
emqx:hook('client.authenticate', {?MODULE, on_client_authenticate, [Env]}),
|
||||
emqx:hook('client.check_acl', {?MODULE, on_client_check_acl, [Env]}),
|
||||
emqx:hook('client.subscribe', {?MODULE, on_client_subscribe, [Env]}),
|
||||
emqx:hook('client.unsubscribe', {?MODULE, on_client_unsubscribe, [Env]}),
|
||||
emqx:hook('session.created', {?MODULE, on_session_created, [Env]}),
|
||||
emqx:hook('session.subscribed', {?MODULE, on_session_subscribed, [Env]}),
|
||||
emqx:hook('session.unsubscribed',{?MODULE, on_session_unsubscribed, [Env]}),
|
||||
emqx:hook('session.resumed', {?MODULE, on_session_resumed, [Env]}),
|
||||
emqx:hook('session.discarded', {?MODULE, on_session_discarded, [Env]}),
|
||||
emqx:hook('session.takeovered', {?MODULE, on_session_takeovered, [Env]}),
|
||||
emqx:hook('session.terminated', {?MODULE, on_session_terminated, [Env]}),
|
||||
emqx:hook('message.publish', {?MODULE, on_message_publish, [Env]}),
|
||||
emqx:hook('message.delivered', {?MODULE, on_message_delivered, [Env]}),
|
||||
emqx:hook('message.acked', {?MODULE, on_message_acked, [Env]}),
|
||||
emqx:hook('message.dropped', {?MODULE, on_message_dropped, [Env]}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Client Lifecircle Hooks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
on_client_connect(ConnInfo, Props, _Env) ->
|
||||
%% this is to demo the usage of EMQ X's structured-logging macro
|
||||
%% * Recommended to always have a `msg` field,
|
||||
%% * Use underscore instead of space to help log indexers,
|
||||
%% * Try to use static fields
|
||||
?SLOG(debug, #{msg => "demo_log_msg_on_client_connect",
|
||||
conninfo => ConnInfo,
|
||||
props => Props}),
|
||||
{ok, Props}.
|
||||
|
||||
on_client_connack(ConnInfo = #{clientid := ClientId}, Rc, Props, _Env) ->
|
||||
io:format("Client(~s) connack, ConnInfo: ~p, Rc: ~p, Props: ~p~n",
|
||||
[ClientId, ConnInfo, Rc, Props]),
|
||||
{ok, Props}.
|
||||
|
||||
on_client_connected(ClientInfo = #{clientid := ClientId}, ConnInfo, _Env) ->
|
||||
io:format("Client(~s) connected, ClientInfo:~n~p~n, ConnInfo:~n~p~n",
|
||||
[ClientId, ClientInfo, ConnInfo]).
|
||||
|
||||
on_client_disconnected(ClientInfo = #{clientid := ClientId}, ReasonCode, ConnInfo, _Env) ->
|
||||
io:format("Client(~s) disconnected due to ~p, ClientInfo:~n~p~n, ConnInfo:~n~p~n",
|
||||
[ClientId, ReasonCode, ClientInfo, ConnInfo]).
|
||||
|
||||
on_client_authenticate(_ClientInfo = #{clientid := ClientId}, Result, _Env) ->
|
||||
io:format("Client(~s) authenticate, Result:~n~p~n", [ClientId, Result]),
|
||||
{ok, Result}.
|
||||
|
||||
on_client_check_acl(_ClientInfo = #{clientid := ClientId}, Topic, PubSub, Result, _Env) ->
|
||||
io:format("Client(~s) check_acl, PubSub:~p, Topic:~p, Result:~p~n",
|
||||
[ClientId, PubSub, Topic, Result]),
|
||||
{ok, Result}.
|
||||
|
||||
on_client_subscribe(#{clientid := ClientId}, _Properties, TopicFilters, _Env) ->
|
||||
io:format("Client(~s) will subscribe: ~p~n", [ClientId, TopicFilters]),
|
||||
{ok, TopicFilters}.
|
||||
|
||||
on_client_unsubscribe(#{clientid := ClientId}, _Properties, TopicFilters, _Env) ->
|
||||
io:format("Client(~s) will unsubscribe ~p~n", [ClientId, TopicFilters]),
|
||||
{ok, TopicFilters}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Session Lifecircle Hooks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
on_session_created(#{clientid := ClientId}, SessInfo, _Env) ->
|
||||
io:format("Session(~s) created, Session Info:~n~p~n", [ClientId, SessInfo]).
|
||||
|
||||
on_session_subscribed(#{clientid := ClientId}, Topic, SubOpts, _Env) ->
|
||||
io:format("Session(~s) subscribed ~s with subopts: ~p~n", [ClientId, Topic, SubOpts]).
|
||||
|
||||
on_session_unsubscribed(#{clientid := ClientId}, Topic, Opts, _Env) ->
|
||||
io:format("Session(~s) unsubscribed ~s with opts: ~p~n", [ClientId, Topic, Opts]).
|
||||
|
||||
on_session_resumed(#{clientid := ClientId}, SessInfo, _Env) ->
|
||||
io:format("Session(~s) resumed, Session Info:~n~p~n", [ClientId, SessInfo]).
|
||||
|
||||
on_session_discarded(_ClientInfo = #{clientid := ClientId}, SessInfo, _Env) ->
|
||||
io:format("Session(~s) is discarded. Session Info: ~p~n", [ClientId, SessInfo]).
|
||||
|
||||
on_session_takeovered(_ClientInfo = #{clientid := ClientId}, SessInfo, _Env) ->
|
||||
io:format("Session(~s) is takeovered. Session Info: ~p~n", [ClientId, SessInfo]).
|
||||
|
||||
on_session_terminated(_ClientInfo = #{clientid := ClientId}, Reason, SessInfo, _Env) ->
|
||||
io:format("Session(~s) is terminated due to ~p~nSession Info: ~p~n",
|
||||
[ClientId, Reason, SessInfo]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Message PubSub Hooks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% Transform message and return
|
||||
on_message_publish(Message = #message{topic = <<"$SYS/", _/binary>>}, _Env) ->
|
||||
{ok, Message};
|
||||
|
||||
on_message_publish(Message, _Env) ->
|
||||
io:format("Publish ~s~n", [emqx_message:to_map(Message)]),
|
||||
{ok, Message}.
|
||||
|
||||
on_message_dropped(#message{topic = <<"$SYS/", _/binary>>}, _By, _Reason, _Env) ->
|
||||
ok;
|
||||
on_message_dropped(Message, _By = #{node := Node}, Reason, _Env) ->
|
||||
io:format("Message dropped by node ~s due to ~s: ~p~n",
|
||||
[Node, Reason, emqx_message:to_map(Message)]).
|
||||
|
||||
on_message_delivered(_ClientInfo = #{clientid := ClientId}, Message, _Env) ->
|
||||
io:format("Message delivered to client(~s): ~p~n",
|
||||
[ClientId, emqx_message:to_map(Message)]),
|
||||
{ok, Message}.
|
||||
|
||||
on_message_acked(_ClientInfo = #{clientid := ClientId}, Message, _Env) ->
|
||||
io:format("Message acked by client(~s): ~p~n",
|
||||
[ClientId, emqx_message:to_map(Message)]).
|
||||
|
||||
%% Called when the plugin application stop
|
||||
unload() ->
|
||||
emqx:unhook('client.connect', {?MODULE, on_client_connect}),
|
||||
emqx:unhook('client.connack', {?MODULE, on_client_connack}),
|
||||
emqx:unhook('client.connected', {?MODULE, on_client_connected}),
|
||||
emqx:unhook('client.disconnected', {?MODULE, on_client_disconnected}),
|
||||
emqx:unhook('client.authenticate', {?MODULE, on_client_authenticate}),
|
||||
emqx:unhook('client.check_acl', {?MODULE, on_client_check_acl}),
|
||||
emqx:unhook('client.subscribe', {?MODULE, on_client_subscribe}),
|
||||
emqx:unhook('client.unsubscribe', {?MODULE, on_client_unsubscribe}),
|
||||
emqx:unhook('session.created', {?MODULE, on_session_created}),
|
||||
emqx:unhook('session.subscribed', {?MODULE, on_session_subscribed}),
|
||||
emqx:unhook('session.unsubscribed',{?MODULE, on_session_unsubscribed}),
|
||||
emqx:unhook('session.resumed', {?MODULE, on_session_resumed}),
|
||||
emqx:unhook('session.discarded', {?MODULE, on_session_discarded}),
|
||||
emqx:unhook('session.takeovered', {?MODULE, on_session_takeovered}),
|
||||
emqx:unhook('session.terminated', {?MODULE, on_session_terminated}),
|
||||
emqx:unhook('message.publish', {?MODULE, on_message_publish}),
|
||||
emqx:unhook('message.delivered', {?MODULE, on_message_delivered}),
|
||||
emqx:unhook('message.acked', {?MODULE, on_message_acked}),
|
||||
emqx:unhook('message.dropped', {?MODULE, on_message_dropped}).
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_plugin_template_app).
|
||||
|
||||
-behaviour(application).
|
||||
|
||||
-emqx_plugin(?MODULE).
|
||||
|
||||
-export([ start/2
|
||||
, stop/1
|
||||
]).
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
{ok, Sup} = emqx_plugin_template_sup:start_link(),
|
||||
emqx_plugin_template:load(application:get_all_env()),
|
||||
{ok, Sup}.
|
||||
|
||||
stop(_State) ->
|
||||
emqx_plugin_template:unload().
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_plugin_template_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-export([start_link/0]).
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
{ok, { {one_for_all, 0, 1}, []} }.
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{application,map_sets,
|
||||
[{description,"sets-like wrapper based on maps"},
|
||||
{vsn,"1.1.0"},
|
||||
{registered,[]},
|
||||
{applications,[kernel,stdlib]},
|
||||
{env,[]},
|
||||
{modules,[]},
|
||||
{links,[{"Github","https://github.com/k32/map_sets"}]},
|
||||
{licenses,["public domain"]}]}.
|
|
@ -1,179 +0,0 @@
|
|||
%% s/sets/map_sets/g
|
||||
%% Why? Because spead (This module piggybacks on `maps' module's BIFs)
|
||||
-module(map_sets).
|
||||
|
||||
-export([ new/0
|
||||
, is_set/1
|
||||
, size/1
|
||||
, to_list/1
|
||||
, from_list/1
|
||||
]).
|
||||
|
||||
-export([ is_element/2
|
||||
, add_element/2
|
||||
, del_element/2
|
||||
]).
|
||||
|
||||
-export([ union/2
|
||||
, union/1
|
||||
, intersection/2
|
||||
, intersection/1
|
||||
]).
|
||||
|
||||
-export([ is_disjoint/2
|
||||
]).
|
||||
|
||||
-export([ subtract/2
|
||||
, is_subset/2
|
||||
]).
|
||||
|
||||
-export([ fold/3
|
||||
, filter/2
|
||||
]).
|
||||
|
||||
-export_type([set/1, set/0]).
|
||||
|
||||
-type set(Key) :: #{Key => term()}.
|
||||
-type set() :: set(term()).
|
||||
|
||||
-define(UNUSED, []).
|
||||
|
||||
-ifdef(OTP_RELEASE). %% OTP21+ supports map iterators
|
||||
|
||||
-define(iterable(A), maps:iterator(A)).
|
||||
|
||||
-define(iterate(I, Last, K, Next, Cons),
|
||||
case maps:next(I) of
|
||||
none -> Last;
|
||||
{K, _, Next} -> Cons
|
||||
end).
|
||||
|
||||
-else.
|
||||
|
||||
-define(iterable(A), maps:keys(A)).
|
||||
|
||||
-define(iterate(I, Last, K, Next, Cons),
|
||||
case I of
|
||||
[] -> Last;
|
||||
[K|Next] -> Cons
|
||||
end).
|
||||
|
||||
-endif.
|
||||
|
||||
-spec new() -> set().
|
||||
new() ->
|
||||
#{}.
|
||||
|
||||
-spec is_set(term()) -> boolean().
|
||||
is_set(A) ->
|
||||
is_map(A).
|
||||
|
||||
-spec size(set()) -> non_neg_integer().
|
||||
size(A) ->
|
||||
maps:size(A).
|
||||
|
||||
-spec fold(Function, Acc, Set) -> Acc when
|
||||
Function :: fun((Element, Acc) -> Acc),
|
||||
Set :: set(Element),
|
||||
Acc :: term().
|
||||
fold(Fun, A, B) ->
|
||||
maps:fold( fun(K, _, Acc) -> Fun(K, Acc) end
|
||||
, A
|
||||
, B).
|
||||
|
||||
-spec filter(Predicate, Set) -> Set when
|
||||
Predicate :: fun((Element) -> boolean()),
|
||||
Set :: set(Element).
|
||||
filter(P, A) ->
|
||||
maps:filter( fun(K, _) -> P(K) end
|
||||
, A).
|
||||
|
||||
-spec to_list(set(Elem)) -> [Elem].
|
||||
to_list(A) ->
|
||||
maps:keys(A).
|
||||
|
||||
-spec from_list([Elem]) -> set(Elem).
|
||||
from_list(L) ->
|
||||
maps:from_list([{I, ?UNUSED} || I <- L]).
|
||||
|
||||
-spec is_element(Elem, set(Elem)) -> boolean().
|
||||
is_element(Elem, Set) ->
|
||||
maps:is_key(Elem, Set).
|
||||
|
||||
-spec add_element(Elem, set(Elem)) -> set(Elem).
|
||||
add_element(Elem, Set) ->
|
||||
Set#{Elem => ?UNUSED}.
|
||||
|
||||
-spec del_element(Elem, set(Elem)) -> set(Elem).
|
||||
del_element(Elem, Set) ->
|
||||
maps:remove(Elem, Set).
|
||||
|
||||
-spec is_subset(set(Elem), set(Elem)) -> boolean().
|
||||
is_subset(S1, S2) ->
|
||||
is_subset_(?iterable(S1), S2).
|
||||
|
||||
is_subset_(Iter, S2) ->
|
||||
?iterate(Iter,
|
||||
true,
|
||||
K, Next,
|
||||
case maps:is_key(K, S2) of
|
||||
true ->
|
||||
is_subset_(Next, S2);
|
||||
false ->
|
||||
false
|
||||
end).
|
||||
|
||||
-spec subtract(set(Elem), set(Elem)) -> set(Elem).
|
||||
subtract(S1, S2) ->
|
||||
maps:without(maps:keys(S2), S1).
|
||||
|
||||
-spec union(set(Elem), set(Elem)) -> set(Elem).
|
||||
union(S1, S2) ->
|
||||
maps:merge(S1, S2).
|
||||
|
||||
-spec union([set(Elem)]) -> set(Elem).
|
||||
union(L) ->
|
||||
lists:foldl(fun maps:merge/2, #{}, L).
|
||||
|
||||
-spec intersection(set(Elem), set(Elem)) -> set(Elem).
|
||||
intersection(S1, S2) ->
|
||||
case maps:size(S1) > maps:size(S2) of
|
||||
true ->
|
||||
intersection_(S1, S2);
|
||||
false ->
|
||||
intersection_(S2, S1)
|
||||
end.
|
||||
intersection_(Large, Small) ->
|
||||
maps:fold( fun(E, _, Acc) ->
|
||||
case maps:is_key(E, Large) of
|
||||
true ->
|
||||
Acc #{E => ?UNUSED};
|
||||
_ ->
|
||||
Acc
|
||||
end
|
||||
end
|
||||
, #{}
|
||||
, Small).
|
||||
|
||||
-spec intersection(nonempty_list(set(Elem))) -> set(Elem).
|
||||
intersection([H|T]) ->
|
||||
lists:foldl(fun intersection/2, H, T).
|
||||
|
||||
-spec is_disjoint(set(Elem), set(Elem)) -> boolean().
|
||||
is_disjoint(S1, S2) ->
|
||||
case maps:size(S1) > maps:size(S2) of
|
||||
true ->
|
||||
is_disjoint_(S1, ?iterable(S2));
|
||||
false ->
|
||||
is_disjoint_(S2, ?iterable(S1))
|
||||
end.
|
||||
is_disjoint_(Large, Small) ->
|
||||
?iterate(Small,
|
||||
true,
|
||||
K, Next,
|
||||
case maps:is_key(K, Large) of
|
||||
true ->
|
||||
false;
|
||||
false ->
|
||||
is_disjoint_(Large, Next)
|
||||
end).
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"authors": [
|
||||
"EMQ X Team"
|
||||
],
|
||||
"builder": {
|
||||
"contact": "emqx-support@emqx.io",
|
||||
"name": "EMQ X Team",
|
||||
"website": "www.emqx.com"
|
||||
},
|
||||
"built_on_otp_release": "24",
|
||||
"compatibility": {
|
||||
"emqx": "~> 5.0"
|
||||
},
|
||||
"date": "2021-12-16",
|
||||
"description": "This is a demo plugin",
|
||||
"functionality": [
|
||||
"Demo"
|
||||
],
|
||||
"git_ref": "ddab50fafeed6b1faea70fc9ffd8c700d7e26ec1",
|
||||
"metadata_vsn": "0.1.0",
|
||||
"name": "emqx_plugin_template",
|
||||
"rel_apps": [
|
||||
"emqx_plugin_template-5.0.0",
|
||||
"map_sets-1.1.0"
|
||||
],
|
||||
"rel_vsn": "5.0-rc.1",
|
||||
"repo": "https://github.com/emqx/emqx-plugin-template"
|
||||
}
|
|
@ -45,7 +45,7 @@ read_plugin_test() ->
|
|||
try
|
||||
ok = write_file(InfoFile, FakeInfo),
|
||||
?assertMatch({error, #{error := "bad_rel_apps"}},
|
||||
emqx_plugins:read_plugin(NameVsn))
|
||||
emqx_plugins:read_plugin(NameVsn, #{}))
|
||||
after
|
||||
emqx_plugins:purge(NameVsn)
|
||||
end
|
||||
|
@ -100,4 +100,3 @@ purge_test() ->
|
|||
ok = file:write_file(Dir, "a"),
|
||||
?assertEqual(ok, emqx_plugins:purge("a-1"))
|
||||
end).
|
||||
|
||||
|
|
Loading…
Reference in New Issue