chore(proj): resync apps

This commit is contained in:
Zaiming Shi 2020-12-10 15:32:00 +01:00
parent ed510936fe
commit 3a91ff8a7b
30 changed files with 155 additions and 314 deletions

View File

@ -119,7 +119,7 @@ translate_env() ->
#{host := Host0,
port := Port,
path := Path} = uri_string:parse(list_to_binary(URL)),
{ok, Host} = inet:parse_address(binary_to_list(Host0)),
Host = get_addr(binary_to_list(Host0)),
[{Name, {Host, Port, binary_to_list(Path)}} | Acc]
end
end, [], [acl_req, auth_req, super_req]),
@ -145,3 +145,16 @@ same_host_and_port([{_, {Host, Port, _}}, URL = {_, {Host, Port, _}} | Rest]) ->
same_host_and_port([URL | Rest]);
same_host_and_port(_) ->
false.
get_addr(Hostname) ->
case inet:parse_address(Hostname) of
{ok, {_,_,_,_} = Addr} -> Addr;
{ok, {_,_,_,_,_,_,_,_} = Addr} -> Addr;
{error, einval} ->
case inet:getaddr(Hostname, inet) of
{error, _} ->
{ok, Addr} = inet:getaddr(Hostname, inet6),
Addr;
{ok, Addr} -> Addr
end
end.

View File

@ -1,10 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -63,10 +63,8 @@ check(ClientInfo = #{ clientid := Clientid
emqx_metrics:inc(?AUTH_METRICS(ignore)),
ok;
List ->
case [ Hash || <<Salt:4/binary, Hash/binary>> <- lists:sort(fun emqx_auth_mnesia_cli:comparing/2, List),
Hash =:= hash(NPassword, Salt, HashType)
] of
[] ->
case match_password(NPassword, HashType, List) of
false ->
?LOG(error, "[Mnesia] Auth from mnesia failed: ~p", [ClientInfo]),
emqx_metrics:inc(?AUTH_METRICS(failure)),
{stop, AuthResult#{anonymous => false, auth_result => password_error}};
@ -78,7 +76,34 @@ check(ClientInfo = #{ clientid := Clientid
description() -> "Authentication with Mnesia".
match_password(Password, HashType, HashList) ->
lists:any(
fun(Secret) ->
case is_salt_hash(Secret, HashType) of
true ->
<<Salt:4/binary, Hash/binary>> = Secret,
Hash =:= hash(Password, Salt, HashType);
_ ->
Secret =:= hash(Password, HashType)
end
end, HashList).
hash(undefined, HashType) ->
hash(<<>>, HashType);
hash(Password, HashType) ->
emqx_passwd:hash(HashType, Password).
hash(undefined, SaltBin, HashType) ->
hash(<<>>, SaltBin, HashType);
hash(Password, SaltBin, HashType) ->
emqx_passwd:hash(HashType, <<SaltBin/binary, Password/binary>>).
is_salt_hash(_, plain) ->
true;
is_salt_hash(Secret, HashType) ->
not (byte_size(Secret) == len(HashType)).
len(md5) -> 32;
len(sha) -> 40;
len(sha256) -> 64;
len(sha512) -> 128.

View File

@ -1,9 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -1,9 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -24,3 +24,5 @@ erlang.mk
rebar.lock
/.idea/
.DS_Store
/.ci/redis/nodes.*.conf
/.ci/redis/*.log

View File

@ -1,10 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -69,21 +69,18 @@ set_special_configs(_App) ->
ok.
init_redis_rows() ->
{ok, Connection} = ?POOL(?APP),
%% Users
[eredis:q(Connection, ["HMSET", Key|FiledValue]) || {Key, FiledValue} <- ?INIT_AUTH],
[q(["HMSET", Key|FiledValue]) || {Key, FiledValue} <- ?INIT_AUTH],
%% ACLs
emqx_modules:load_module(emqx_mod_acl_internal, false),
Result = [eredis:q(Connection, ["HSET", Key, Filed, Value]) || {Key, Filed, Value} <- ?INIT_ACL],
Result = [q(["HSET", Key, Filed, Value]) || {Key, Filed, Value} <- ?INIT_ACL],
ct:pal("redis init result: ~p~n", [Result]).
deinit_redis_rows() ->
{ok, Connection} = ?POOL(?APP),
AuthKeys = [Key || {Key, _Filed, _Value} <- ?INIT_AUTH],
AclKeys = [Key || {Key, _Value} <- ?INIT_ACL],
eredis:q(Connection, ["DEL" | AuthKeys]),
eredis:q(Connection, ["DEL" | AclKeys]).
q(["DEL" | AuthKeys]),
q(["DEL" | AclKeys]).
%%--------------------------------------------------------------------
%% Cases
@ -121,9 +118,8 @@ t_check_auth(_) ->
{error, _} = emqx_access_control:authenticate(Bcrypt#{password => <<"password">>}).
t_check_auth_hget(_) ->
{ok, Connection} = ?POOL(?APP),
eredis:q(Connection, ["HSET", "mqtt_user:hset", "password", "hset"]),
eredis:q(Connection, ["HSET", "mqtt_user:hset", "is_superuser", "1"]),
q(["HSET", "mqtt_user:hset", "password", "hset"]),
q(["HSET", "mqtt_user:hset", "is_superuser", "1"]),
reload([{password_hash, plain}, {auth_cmd, "HGET mqtt_user:%u password"}]),
Hset = #{clientid => <<"hset">>, username => <<"hset">>, zone => external},
{ok, #{is_superuser := true}} = emqx_access_control:authenticate(Hset#{password => <<"hset">>}).
@ -164,6 +160,16 @@ t_acl_super(_) ->
end,
emqtt:disconnect(C).
t_check_cluster_connection(_) ->
?assertMatch({error, _Reason}, reload([{server, [{type,cluster},
{pool_size,8},
{auto_reconnect,1},
{database,0},
{password,[]},
{sentinel,[]},
{servers,[{"wrong",6379},{"wrong",6380},{"wrong",6381}]}]}])).
%%--------------------------------------------------------------------
%% Internal funcs
%%--------------------------------------------------------------------
@ -172,3 +178,13 @@ reload(Config) when is_list(Config) ->
application:stop(?APP),
[application:set_env(?APP, K, V) || {K, V} <- Config],
application:start(?APP).
q(Cmd) ->
{ok, Server} = application:get_env(?APP, server),
case proplists:get_value(type, Server) of
single ->
{ok, Connection} = ?POOL(?APP),
eredis:q(Connection, Cmd);
cluster ->
eredis_cluster:q(emqx_auth_redis, Cmd)
end.

View File

@ -1,10 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<"*.">>, []}
]
}.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
webpackJsonp([20],{"4odX":function(t,e){},LbE0:function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var a={name:"help-view",components:{},data:function(){return{lang:window.localStorage.getItem("language")||"en"}},computed:{learnEnterprise:function(){return"zh"===this.lang?"https://www.emqx.io/cn/products/enterprise":"https://www.emqx.io/products/enterprise"},freeTrial:function(){return"zh"===this.lang?"https://www.emqx.io/cn/downloads#enterprise":"https://www.emqx.io/downloads#enterprise"},docsLink:function(){return"zh"===this.lang?"https://docs.emqx.io/broker/v4/cn":"https://docs.emqx.io/broker/v4/en"},faqLink:function(){return"zh"===this.lang?"https://docs.emqx.io/broker/latest/cn/faq/faq.html":"https://docs.emqx.io/tutorial/v4/en/faq/faq.html"}},methods:{}},n={render:function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"help-view"},[s("div",{staticClass:"page-title"},[t._v(t._s(t.$t("leftbar.help")))]),t._v(" "),s("div",{staticClass:"help-item"},[s("h3",[t._v(t._s(t.$t("help.quickStart")))]),t._v(" "),s("p",[t._v(t._s(t.$t("help.emqxDesc")))]),t._v(" "),s("a",{attrs:{target:"_blank",href:"https://github.com/emqx/emqx"}},[t._v("Github")])]),t._v(" "),s("el-divider"),t._v(" "),s("div",{staticClass:"help-item"},[s("h3",[t._v(t._s(t.$t("help.emqxEnterprise")))]),t._v(" "),s("p",{domProps:{innerHTML:t._s(t.$t("help.enterpriseDesc"))}}),t._v(" "),s("a",{attrs:{target:"_blank",href:t.learnEnterprise}},[t._v("\n "+t._s(t.$t("oper.learnMore"))+"\n ")]),t._v(" "),s("a",{attrs:{target:"_blank",href:t.freeTrial}},[t._v("\n "+t._s(t.$t("help.freeTrial"))+"\n ")])]),t._v(" "),s("el-divider"),t._v(" "),s("div",{staticClass:"help-item"},[s("h3",[t._v(t._s(t.$t("help.useDocs")))]),t._v(" "),s("p",[t._v(t._s(t.$t("help.docsDesc")))]),t._v(" "),s("a",{attrs:{target:"_blank",href:t.docsLink}},[t._v("\n "+t._s(t.$t("help.forwardView"))+"\n ")])]),t._v(" "),s("el-divider"),t._v(" "),s("div",{staticClass:"help-item"},[s("h3",[t._v("FAQ")]),t._v(" "),s("p",[t._v(t._s(t.$t("help.faqDesc")))]),t._v(" "),s("a",{attrs:{target:"_blank",href:t.faqLink}},[t._v("\n "+t._s(t.$t("help.forwardFaq"))+"\n ")])]),t._v(" "),s("el-divider"),t._v(" "),s("div",{staticClass:"help-item"},[s("h3",[t._v(t._s(t.$t("help.followUs")))]),t._v(" "),t._m(0),t._v(" "),t._m(1),t._v(" "),t._m(2),t._v(" "),t._m(3),t._v(" "),t._m(4),t._v(" "),t._m(5)])],1)},staticRenderFns:[function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://github.com/emqx/emqx"}},[e("i",{staticClass:"iconfont icon-git"})])},function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://twitter.com/emqtt"}},[e("i",{staticClass:"iconfont icon-tuite"})])},function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://emqx.slack.com/"}},[e("i",{staticClass:"iconfont icon-slack"})])},function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://stackoverflow.com/questions/tagged/emq"}},[e("i",{staticClass:"iconfont icon-stack-overflow"})])},function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://groups.google.com/forum/#!forum/emqtt"}},[e("i",{staticClass:"iconfont icon-icons-google_groups"})])},function(){var t=this.$createElement,e=this._self._c||t;return e("a",{staticClass:"follow-link",attrs:{target:"_blank",href:"https://www.youtube.com/channel/UCDU9GWFk8NTGiTvPx_2XskA"}},[e("i",{staticClass:"iconfont icon-youtube"})])}]};var i=s("VU/8")(a,n,!1,function(t){s("4odX")},null,null);e.default=i.exports}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
!function(e){var a=window.webpackJsonp;window.webpackJsonp=function(c,t,f){for(var o,d,b,i=0,u=[];i<c.length;i++)d=c[i],n[d]&&u.push(n[d][0]),n[d]=0;for(o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);for(a&&a(c,t,f);u.length;)u.shift()();if(f)for(i=0;i<f.length;i++)b=r(r.s=f[i]);return b};var c={},n={27:0};function r(a){if(c[a])return c[a].exports;var n=c[a]={i:a,l:!1,exports:{}};return e[a].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.e=function(e){var a=n[e];if(0===a)return new Promise(function(e){e()});if(a)return a[2];var c=new Promise(function(c,r){a=n[e]=[c,r]});a[2]=c;var t=document.getElementsByTagName("head")[0],f=document.createElement("script");f.type="text/javascript",f.charset="utf-8",f.async=!0,f.timeout=12e4,r.nc&&f.setAttribute("nonce",r.nc),f.src=r.p+"static/js/"+e+"."+{0:"7a09d1383e1319441399",1:"fcd6fde8b053e80bc68f",2:"71ffb214c95162432f13",3:"25b49772270df4b9915d",4:"93d4473fcf7768693652",5:"8935139a413f40d70253",6:"ef8e6aa7a51fa7564f71",7:"92a348a80764134ff2a9",8:"e86f6131cc8a9138368d",9:"473ceac05f7dfe3f3e92",10:"188c5e479f887d471dde",11:"3861aeb3036b8f41a6e8",12:"43feccc8f1584bdba5c2",13:"026a13a2a59abd354bd5",14:"0342a1a3d29f1adca947",15:"7d11711536eb5b2ca561",16:"6bfd6f3eb9216e73149c",17:"1d56280c16e6e2b81cff",18:"a0c394cb4b55bee2fa82",19:"060521bb4ba4f7a81ac0",20:"308aa0fdf6653ef3299f",21:"306758a2a6ef73532290",22:"d968dc6f54a690adde18",23:"7837b8f015b7d486b74f",24:"ccbcfda924431cb282e2",25:"8b2dccd8a7e1f91a5040",26:"9cd922cc7e5d035cbcc7"}[e]+".js";var o=setTimeout(d,12e4);function d(){f.onerror=f.onload=null,clearTimeout(o);var a=n[e];0!==a&&(a&&a[1](new Error("Loading chunk "+e+" failed.")),n[e]=void 0)}return f.onerror=f.onload=d,t.appendChild(f),c},r.m=e,r.c=c,r.d=function(e,a,c){r.o(e,a)||Object.defineProperty(e,a,{configurable:!1,enumerable:!0,get:c})},r.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(a,"a",a),a},r.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},r.p="/",r.oe=function(e){throw console.error(e),e}}([]);

View File

@ -1,24 +0,0 @@
%%-*- mode: erlang -*-
%% .app.src.script
RemoveLeadingV =
fun(Tag) ->
case re:run(Tag, "^[v]?[0-9]\.[0-9]\.([0-9]|(rc|beta|alpha)\.[0-9])", [{capture, none}]) of
nomatch ->
re:replace(Tag, "/", "-", [{return ,list}]);
_ ->
%% if it is a version number prefixed by 'v' or 'e', then remove it
re:replace(Tag, "[v]", "", [{return ,list}])
end
end,
case os:getenv("EMQX_DEPS_DEFAULT_VSN") of
false -> CONFIG; % env var not defined
[] -> CONFIG; % env var set to empty string
Tag ->
[begin
AppConf0 = lists:keystore(vsn, 1, AppConf, {vsn, RemoveLeadingV(Tag)}),
{application, App, AppConf0}
end || Conf = {application, App, AppConf} <- CONFIG]
end.

View File

@ -1,9 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -1,24 +0,0 @@
%%-*- mode: erlang -*-
%% .app.src.script
RemoveLeadingV =
fun(Tag) ->
case re:run(Tag, "^[v]?[0-9]\.[0-9]\.([0-9]|(rc|beta|alpha)\.[0-9])", [{capture, none}]) of
nomatch ->
re:replace(Tag, "/", "-", [{return ,list}]);
_ ->
%% if it is a version number prefixed by 'v' or 'e', then remove it
re:replace(Tag, "[v]", "", [{return ,list}])
end
end,
case os:getenv("EMQX_DEPS_DEFAULT_VSN") of
false -> CONFIG; % env var not defined
[] -> CONFIG; % env var set to empty string
Tag ->
[begin
AppConf0 = lists:keystore(vsn, 1, AppConf, {vsn, RemoveLeadingV(Tag)}),
{application, App, AppConf0}
end || Conf = {application, App, AppConf} <- CONFIG]
end.

View File

@ -1,9 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -128,6 +128,7 @@
, export_auth_username/0
, export_auth_mnesia/0
, export_acl_mnesia/0
, export_schemas/0
, import_rules/1
, import_resources/1
, import_blacklist/1
@ -137,6 +138,7 @@
, import_auth_username/1
, import_auth_mnesia/1
, import_acl_mnesia/1
, import_schemas/1
, to_version/1
]).
@ -677,6 +679,13 @@ export_acl_mnesia() ->
end, [], ets:tab2list(emqx_acl))
end.
export_schemas() ->
case ets:info(emqx_schema) of
undefined -> [];
_ ->
[emqx_schema_api:format_schema(Schema) || Schema <- emqx_schema_registry:get_all_schemas()]
end.
import_rules(Rules) ->
lists:foreach(fun(#{<<"id">> := RuleId,
<<"rawsql">> := RawSQL,
@ -786,6 +795,12 @@ import_acl_mnesia(Acls) ->
<<"allow">> := Allow} <- Acls ]
end.
import_schemas(Schemas) ->
case ets:info(emqx_schema) of
undefined -> ok;
_ -> [emqx_schema_registry:add_schema(emqx_schema_api:make_schema_params(Schema)) || Schema <- Schemas]
end.
any_to_atom(L) when is_list(L) -> list_to_atom(L);
any_to_atom(B) when is_binary(B) -> binary_to_atom(B, utf8);
any_to_atom(A) when is_atom(A) -> A.

View File

@ -84,6 +84,7 @@ export(_Bindings, _Params) ->
AuthUsername = emqx_mgmt:export_auth_username(),
AuthMnesia = emqx_mgmt:export_auth_mnesia(),
AclMnesia = emqx_mgmt:export_acl_mnesia(),
Schemas = emqx_mgmt:export_schemas(),
Seconds = erlang:system_time(second),
{{Y, M, D}, {H, MM, S}} = emqx_mgmt_util:datetime(Seconds),
Filename = io_lib:format("emqx-export-~p-~p-~p-~p-~p-~p.json", [Y, M, D, H, MM, S]),
@ -99,7 +100,8 @@ export(_Bindings, _Params) ->
{auth_clientid, AuthClientid},
{auth_username, AuthUsername},
{auth_mnesia, AuthMnesia},
{acl_mnesia, AclMnesia}
{acl_mnesia, AclMnesia},
{schemas, Schemas}
],
Bin = emqx_json:encode(Data),
@ -178,19 +180,20 @@ do_import(Filename) ->
case lists:member(Version, ?VERSIONS) of
true ->
try
%emqx_mgmt:import_confs(maps:get(<<"configs">>, Data, []), maps:get(<<"listeners_state">>, Data, [])),
emqx_mgmt:import_confs(maps:get(<<"configs">>, Data, []), maps:get(<<"listeners_state">>, Data, [])),
emqx_mgmt:import_resources(maps:get(<<"resources">>, Data, [])),
emqx_mgmt:import_rules(maps:get(<<"rules">>, Data, [])),
emqx_mgmt:import_blacklist(maps:get(<<"blacklist">>, Data, [])),
emqx_mgmt:import_applications(maps:get(<<"apps">>, Data, [])),
emqx_mgmt:import_users(maps:get(<<"users">>, Data, [])),
%emqx_mgmt:import_modules(maps:get(<<"modules">>, Data, [])),
emqx_mgmt:import_modules(maps:get(<<"modules">>, Data, [])),
emqx_mgmt:import_auth_clientid(maps:get(<<"auth_clientid">>, Data, [])),
emqx_mgmt:import_auth_username(maps:get(<<"auth_username">>, Data, [])),
%emqx_mgmt:import_auth_mnesia(maps:get(<<"auth_mnesia">>, Data, []), Version),
%emqx_mgmt:import_acl_mnesia(maps:get(<<"acl_mnesia">>, Data, []), Version),
emqx_mgmt:import_auth_mnesia(maps:get(<<"auth_mnesia">>, Data, []), Version),
emqx_mgmt:import_acl_mnesia(maps:get(<<"acl_mnesia">>, Data, []), Version),
emqx_mgmt:import_schemas(maps:get(<<"schemas">>, Data, [])),
logger:debug("The emqx data has been imported successfully"),
error({not_implemented, [import_confs,import_modules,import_auth_mnesia,import_acl_mnesia]})
ok
catch Class:Reason:Stack ->
logger:error("The emqx data import failed: ~0p", [{Class,Reason,Stack}]),
{error, import_failed}

View File

@ -567,6 +567,7 @@ data(["export"]) ->
AuthUsername = emqx_mgmt:export_auth_username(),
AuthMnesia = emqx_mgmt:export_auth_mnesia(),
AclMnesia = emqx_mgmt:export_acl_mnesia(),
Schemas = emqx_mgmt:export_schemas(),
Seconds = erlang:system_time(second),
{{Y, M, D}, {H, MM, S}} = emqx_mgmt_util:datetime(Seconds),
Filename = io_lib:format("emqx-export-~p-~p-~p-~p-~p-~p.json", [Y, M, D, H, MM, S]),
@ -582,8 +583,8 @@ data(["export"]) ->
{auth_clientid, AuthClientID},
{auth_username, AuthUsername},
{auth_mnesia, AuthMnesia},
{acl_mnesia, AclMnesia}
],
{acl_mnesia, AclMnesia},
{schemas, Schemas}],
ok = filelib:ensure_dir(NFilename),
case file:write_file(NFilename, emqx_json:encode(Data)) of
ok ->
@ -609,6 +610,7 @@ data(["import", Filename]) ->
emqx_mgmt:import_auth_username(maps:get(<<"auth_username">>, Data, [])),
emqx_mgmt:import_auth_mnesia(maps:get(<<"auth_mnesia">>, Data, [])),
emqx_mgmt:import_acl_mnesia(maps:get(<<"acl_mnesia">>, Data, [])),
emqx_mgmt:import_schemas(maps:get(<<"schemas">>, Data, [])),
emqx_ctl:print("The emqx data has been imported successfully.~n")
catch Class:Reason:Stack ->
emqx_ctl:print("The emqx data import failed due: ~0p~n", [{Class,Reason,Stack}])

View File

@ -1,8 +0,0 @@
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -78,10 +78,6 @@
, bitxor/2
, bitsl/2
, bitsr/2
, bitsize/1
, subbits/2
, subbits/3
, subbits/6
]).
%% Data Type Convertion
@ -237,7 +233,7 @@ payload() ->
payload(Path) ->
fun(#{payload := Payload}) when erlang:is_map(Payload) ->
map_get(Path, Payload);
emqx_rule_maps:nested_get(map_path(Path), Payload);
(_) -> undefined
end.
@ -405,74 +401,6 @@ bitsl(X, I) when is_integer(X), is_integer(I) ->
bitsr(X, I) when is_integer(X), is_integer(I) ->
X bsr I.
bitsize(Bits) when is_bitstring(Bits) ->
bit_size(Bits).
subbits(Bits, Len) when is_integer(Len), is_bitstring(Bits) ->
subbits(Bits, 1, Len).
subbits(Bits, Start, Len) when is_integer(Start), is_integer(Len), is_bitstring(Bits) ->
get_subbits(Bits, Start, Len, <<"integer">>, <<"unsigned">>, <<"big">>).
subbits(Bits, Start, Len, Type, Signedness, Endianness) when is_integer(Start), is_integer(Len), is_bitstring(Bits) ->
get_subbits(Bits, Start, Len, Type, Signedness, Endianness).
get_subbits(Bits, Start, Len, Type, Signedness, Endianness) ->
Begin = Start - 1,
case Bits of
<<_:Begin, Rem/bits>> when Rem =/= <<>> ->
Sz = bit_size(Rem),
do_get_subbits(Rem, Sz, Len, Type, Signedness, Endianness);
_ -> undefined
end.
-define(match_bits(Bits0, Pattern, ElesePattern),
case Bits0 of
Pattern ->
SubBits;
ElesePattern ->
SubBits
end).
do_get_subbits(Bits, Sz, Len, <<"integer">>, <<"unsigned">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/integer-unsigned-big-unit:1, _/bits>>,
<<SubBits:Sz/integer-unsigned-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"float">>, <<"unsigned">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/float-unsigned-big-unit:1, _/bits>>,
<<SubBits:Sz/float-unsigned-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"bits">>, <<"unsigned">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/bits-unsigned-big-unit:1, _/bits>>,
<<SubBits:Sz/bits-unsigned-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"integer">>, <<"signed">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/integer-signed-big-unit:1, _/bits>>,
<<SubBits:Sz/integer-signed-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"float">>, <<"signed">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/float-signed-big-unit:1, _/bits>>,
<<SubBits:Sz/float-signed-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"bits">>, <<"signed">>, <<"big">>) ->
?match_bits(Bits, <<SubBits:Len/bits-signed-big-unit:1, _/bits>>,
<<SubBits:Sz/bits-signed-big-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"integer">>, <<"unsigned">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/integer-unsigned-little-unit:1, _/bits>>,
<<SubBits:Sz/integer-unsigned-little-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"float">>, <<"unsigned">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/float-unsigned-little-unit:1, _/bits>>,
<<SubBits:Sz/float-unsigned-little-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"bits">>, <<"unsigned">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/bits-unsigned-little-unit:1, _/bits>>,
<<SubBits:Sz/bits-unsigned-little-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"integer">>, <<"signed">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/integer-signed-little-unit:1, _/bits>>,
<<SubBits:Sz/integer-signed-little-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"float">>, <<"signed">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/float-signed-little-unit:1, _/bits>>,
<<SubBits:Sz/float-signed-little-unit:1>>);
do_get_subbits(Bits, Sz, Len, <<"bits">>, <<"signed">>, <<"little">>) ->
?match_bits(Bits, <<SubBits:Len/bits-signed-little-unit:1, _/bits>>,
<<SubBits:Sz/bits-signed-little-unit:1>>).
%%------------------------------------------------------------------------------
%% Data Type Convertion Funcs
%%------------------------------------------------------------------------------
@ -679,10 +607,52 @@ map_get(Key, Map) ->
map_get(Key, Map, undefined).
map_get(Key, Map, Default) ->
emqx_rule_maps:nested_get(map_path(Key), Map, Default).
case maps:find(Key, Map) of
{ok, Val} -> Val;
error when is_atom(Key) ->
%% the map may have an equivalent binary-form key
BinKey = emqx_rule_utils:bin(Key),
case maps:find(BinKey, Map) of
{ok, Val} -> Val;
error -> Default
end;
error when is_binary(Key) ->
try %% the map may have an equivalent atom-form key
AtomKey = list_to_existing_atom(binary_to_list(Key)),
case maps:find(AtomKey, Map) of
{ok, Val} -> Val;
error -> Default
end
catch error:badarg ->
Default
end;
error ->
Default
end.
map_put(Key, Val, Map) ->
emqx_rule_maps:nested_put(map_path(Key), Val, Map).
case maps:find(Key, Map) of
{ok, _} -> maps:put(Key, Val, Map);
error when is_atom(Key) ->
%% the map may have an equivalent binary-form key
BinKey = emqx_rule_utils:bin(Key),
case maps:find(BinKey, Map) of
{ok, _} -> maps:put(BinKey, Val, Map);
error -> maps:put(Key, Val, Map)
end;
error when is_binary(Key) ->
try %% the map may have an equivalent atom-form key
AtomKey = list_to_existing_atom(binary_to_list(Key)),
case maps:find(AtomKey, Map) of
{ok, _} -> maps:put(AtomKey, Val, Map);
error -> maps:put(Key, Val, Map)
end
catch error:badarg ->
maps:put(Key, Val, Map)
end;
error ->
maps:put(Key, Val, Map)
end.
mget(Key, Map) ->
mget(Key, Map, undefined).

View File

@ -489,75 +489,22 @@ t_contains(_) ->
t_map_get(_) ->
?assertEqual(1, apply_func(map_get, [<<"a">>, #{a => 1}])),
?assertEqual(undefined, apply_func(map_get, [<<"a">>, #{}])),
?assertEqual(1, apply_func(map_get, [<<"a.b">>, #{a => #{b => 1}}])),
?assertEqual(undefined, apply_func(map_get, [<<"a.c">>, #{a => #{b => 1}}])).
?assertEqual(undefined, apply_func(map_get, [<<"a">>, #{}])).
t_map_put(_) ->
?assertEqual(#{<<"a">> => 1}, apply_func(map_put, [<<"a">>, 1, #{}])),
?assertEqual(#{a => 2}, apply_func(map_put, [<<"a">>, 2, #{a => 1}])),
?assertEqual(#{<<"a">> => #{<<"b">> => 1}}, apply_func(map_put, [<<"a.b">>, 1, #{}])),
?assertEqual(#{a => #{b => 1, <<"c">> => 1}}, apply_func(map_put, [<<"a.c">>, 1, #{a => #{b => 1}}])).
?assertEqual(#{a => 2}, apply_func(map_put, [<<"a">>, 2, #{a => 1}])).
t_mget(_) ->
t_mget(_) ->
?assertEqual(1, apply_func(map_get, [<<"a">>, #{a => 1}])),
?assertEqual(1, apply_func(map_get, [<<"a">>, #{<<"a">> => 1}])),
?assertEqual(undefined, apply_func(map_get, [<<"a">>, #{}])).
t_mput(_) ->
t_mput(_) ->
?assertEqual(#{<<"a">> => 1}, apply_func(map_put, [<<"a">>, 1, #{}])),
?assertEqual(#{<<"a">> => 2}, apply_func(map_put, [<<"a">>, 2, #{<<"a">> => 1}])),
?assertEqual(#{a => 2}, apply_func(map_put, [<<"a">>, 2, #{a => 1}])).
t_bitsize(_) ->
?assertEqual(8, apply_func(bitsize, [<<"a">>])),
?assertEqual(4, apply_func(bitsize, [<<15:4>>])).
t_subbits(_) ->
?assertEqual(1, apply_func(subbits, [<<255:8>>, 1])),
?assertEqual(3, apply_func(subbits, [<<255:8>>, 2])),
?assertEqual(7, apply_func(subbits, [<<255:8>>, 3])),
?assertEqual(15, apply_func(subbits, [<<255:8>>, 4])),
?assertEqual(31, apply_func(subbits, [<<255:8>>, 5])),
?assertEqual(63, apply_func(subbits, [<<255:8>>, 6])),
?assertEqual(127, apply_func(subbits, [<<255:8>>, 7])),
?assertEqual(255, apply_func(subbits, [<<255:8>>, 8])).
t_subbits2(_) ->
?assertEqual(1, apply_func(subbits, [<<255:8>>, 1, 1])),
?assertEqual(3, apply_func(subbits, [<<255:8>>, 1, 2])),
?assertEqual(7, apply_func(subbits, [<<255:8>>, 1, 3])),
?assertEqual(15, apply_func(subbits, [<<255:8>>, 1, 4])),
?assertEqual(31, apply_func(subbits, [<<255:8>>, 1, 5])),
?assertEqual(63, apply_func(subbits, [<<255:8>>, 1, 6])),
?assertEqual(127, apply_func(subbits, [<<255:8>>, 1, 7])),
?assertEqual(255, apply_func(subbits, [<<255:8>>, 1, 8])).
t_subbits2_1(_) ->
?assertEqual(1, apply_func(subbits, [<<255:8>>, 2, 1])),
?assertEqual(3, apply_func(subbits, [<<255:8>>, 2, 2])),
?assertEqual(7, apply_func(subbits, [<<255:8>>, 2, 3])),
?assertEqual(15, apply_func(subbits, [<<255:8>>, 2, 4])),
?assertEqual(31, apply_func(subbits, [<<255:8>>, 2, 5])),
?assertEqual(63, apply_func(subbits, [<<255:8>>, 2, 6])),
?assertEqual(127, apply_func(subbits, [<<255:8>>, 2, 7])),
?assertEqual(127, apply_func(subbits, [<<255:8>>, 2, 8])).
t_subbits2_integer(_) ->
?assertEqual(456, apply_func(subbits, [<<456:32/integer>>, 1, 32, <<"integer">>, <<"signed">>, <<"big">>])),
?assertEqual(-456, apply_func(subbits, [<<-456:32/integer>>, 1, 32, <<"integer">>, <<"signed">>, <<"big">>])).
t_subbits2_float(_) ->
R = apply_func(subbits, [<<5.3:64/float>>, 1, 64, <<"float">>, <<"unsigned">>, <<"big">>]),
RL = (5.3 - R),
ct:pal(";;;;~p", [R]),
?assert( (RL >= 0 andalso RL < 0.0001) orelse (RL =< 0 andalso RL > -0.0001)),
R2 = apply_func(subbits, [<<-5.3:64/float>>, 1, 64, <<"float">>, <<"signed">>, <<"big">>]),
RL2 = (5.3 + R2),
ct:pal(";;;;~p", [R2]),
?assert( (RL2 >= 0 andalso RL2 < 0.0001) orelse (RL2 =< 0 andalso RL2 > -0.0001)).
%%------------------------------------------------------------------------------
%% Test cases for Hash funcs

View File

@ -1,9 +0,0 @@
%% -*-: erlang -*-
{VSN,
[
{<<".*">>, []}
],
[
{<<".*">>, []}
]
}.

View File

@ -85,10 +85,11 @@ done
cleanup_app(){
local app="$1"
pushd "apps/$app"
rm -f Makefile rebar.config.script
rm -f Makefile rebar.config.script LICENSE src/*.app.src.script src/*.appup.src
rm -rf ".github" ".ci"
rm -rf src/*.app.src.script
rm -rf src/*.appup.src
# restore rebar.config and app.src
git checkout rebar.config
git checkout src/*.app.src
popd
}