161 lines
5.0 KiB
Erlang
161 lines
5.0 KiB
Erlang
%%%-------------------------------------------------------------------
|
|
%%% @author licheng5
|
|
%%% @copyright (C) 2020, <COMPANY>
|
|
%%% @doc
|
|
%%%
|
|
%%% @end
|
|
%%% Created : 11. 12月 2020 上午10:57
|
|
%%%-------------------------------------------------------------------
|
|
-module(iot_util).
|
|
-author("licheng5").
|
|
|
|
%% API
|
|
-export([timestamp/0, number_format/2, current_time/0, timestamp_of_seconds/0, float_to_binary/2, int_format/2, file_uri/1]).
|
|
-export([step/3, chunks/2, rand_bytes/1, uuid/0, md5/1, parse_mapper/1]).
|
|
-export([json_data/1, json_error/2, is_json/1]).
|
|
-export([queue_limited_in/3, assert_call/2, assert/2]).
|
|
|
|
-spec is_json(Json :: term()) -> boolean().
|
|
is_json(Json) when is_binary(Json) ->
|
|
case catch jiffy:decode(Json, [return_maps]) of
|
|
Result when is_list(Result) orelse is_map(Result) ->
|
|
true;
|
|
_ ->
|
|
false
|
|
end;
|
|
is_json(_Json) ->
|
|
false.
|
|
|
|
%% 时间,精确到毫秒
|
|
timestamp() ->
|
|
{Mega, Seconds, Micro} = os:timestamp(),
|
|
(Mega * 1000000 + Seconds) * 1000 + Micro div 1000.
|
|
|
|
current_time() ->
|
|
{Mega, Seconds, _Micro} = os:timestamp(),
|
|
Mega * 1000000 + Seconds.
|
|
|
|
timestamp_of_seconds() ->
|
|
{Mega, Seconds, _Micro} = os:timestamp(),
|
|
Mega * 1000000 + Seconds.
|
|
|
|
number_format(Num, _Decimals) when is_integer(Num) ->
|
|
Num;
|
|
number_format(Float, Decimals) when is_float(Float) ->
|
|
list_to_float(float_to_list(Float, [{decimals, Decimals}, compact])).
|
|
|
|
int_format(Num, Len) when is_integer(Num), Len > 0 ->
|
|
S = integer_to_list(Num),
|
|
case length(S) > Len of
|
|
true ->
|
|
list_to_integer(lists:sublist(S, 1, Len));
|
|
false ->
|
|
Num
|
|
end.
|
|
|
|
step(Start, End, Step) when is_integer(Start), is_integer(End), is_integer(Step), Start < End, Step > 0 ->
|
|
step(Start, End, Step, []).
|
|
step(Start, End, Step, Acc) when Start < End ->
|
|
step(Start + Step, End, Step, [{Start, min(Start + Step, End)} | Acc]);
|
|
step(_, _, _, Acc) ->
|
|
lists:reverse(Acc).
|
|
|
|
%% 将数据分组
|
|
-spec chunks(list(), integer()) -> [list()].
|
|
chunks(List, Size) when is_list(List), is_integer(Size), Size > 0, length(List) =< Size ->
|
|
[List];
|
|
chunks(List, Size) when is_list(List), is_integer(Size), Size > 0 ->
|
|
chunks0(List, Size, Size, [], []).
|
|
chunks0([], _, _, [], AccTarget) ->
|
|
lists:reverse(AccTarget);
|
|
chunks0([], _, _, Target, AccTarget) ->
|
|
lists:reverse([lists:reverse(Target) | AccTarget]);
|
|
chunks0(List, Size, 0, Target, AccTarget) ->
|
|
chunks0(List, Size, Size, [], [lists:reverse(Target) | AccTarget]);
|
|
chunks0([Hd | Tail], Size, Num, Target, AccTarget) ->
|
|
chunks0(Tail, Size, Num - 1, [Hd | Target], AccTarget).
|
|
|
|
json_data(Data) ->
|
|
jiffy:encode(#{
|
|
<<"result">> => Data
|
|
}, [force_utf8]).
|
|
|
|
json_error(ErrCode, ErrMessage) when is_integer(ErrCode), is_binary(ErrMessage) ->
|
|
jiffy:encode(#{
|
|
<<"error">> => #{
|
|
<<"code">> => ErrCode,
|
|
<<"message">> => ErrMessage
|
|
}
|
|
}, [force_utf8]).
|
|
|
|
uuid() ->
|
|
rand_bytes(16).
|
|
|
|
-spec rand_bytes(Size :: integer()) -> string().
|
|
rand_bytes(Size) when is_integer(Size), Size > 0 ->
|
|
Size1 = erlang:ceil(Size / 2),
|
|
Bytes = crypto:strong_rand_bytes(Size1),
|
|
S = lists:flatten([integer_to_list(E, 16) || <<E:4>> <= Bytes]),
|
|
lists:sublist(string:to_lower(S), 1, Size).
|
|
|
|
queue_limited_in(Item, Q, Num) when is_integer(Num) ->
|
|
case queue:len(Q) >= Num of
|
|
true ->
|
|
Q1 = queue:drop(Q),
|
|
queue:in(Item, Q1);
|
|
false ->
|
|
queue:in(Item, Q)
|
|
end.
|
|
|
|
assert_call(true, Fun) ->
|
|
Fun();
|
|
assert_call(false, _) ->
|
|
ok.
|
|
|
|
-spec md5(Str :: binary()) -> binary().
|
|
md5(Str) when is_binary(Str) ->
|
|
list_to_binary(lists:flatten([hex(X) || <<X:4>> <= erlang:md5(Str)])).
|
|
|
|
hex(N) when N < 10 ->
|
|
$0 + N;
|
|
hex(N) ->
|
|
$a + (N - 10).
|
|
|
|
%% 转换映射器
|
|
-spec parse_mapper(Mapper :: binary() | string()) -> error | {ok, F :: fun((binary(), any()) -> any())}.
|
|
parse_mapper(Mapper) when is_binary(Mapper) ->
|
|
parse_mapper(binary_to_list(Mapper));
|
|
parse_mapper(Mapper) when is_list(Mapper) ->
|
|
{ok, Tokens, _} = erl_scan:string(Mapper),
|
|
{ok, ExprList} = erl_parse:parse_exprs(Tokens),
|
|
{value, F, _} = erl_eval:exprs(ExprList, []),
|
|
case is_function(F, 2) orelse is_function(F, 3) of
|
|
true ->
|
|
{ok, F};
|
|
false ->
|
|
error
|
|
end.
|
|
|
|
-spec float_to_binary(Num :: number(), integer()) -> binary().
|
|
float_to_binary(V, _) when is_integer(V) ->
|
|
integer_to_binary(V);
|
|
float_to_binary(V, Decimals) when is_float(V), is_integer(Decimals) ->
|
|
S = float_to_list(V, [{decimals, Decimals}, compact]),
|
|
list_to_binary(S).
|
|
|
|
assert(true, _) ->
|
|
ok;
|
|
assert(false, F) when is_function(F) ->
|
|
F();
|
|
assert(false, Msg) ->
|
|
throw(Msg).
|
|
|
|
|
|
-spec file_uri(Filename :: binary()) -> error | {ok, FileUri :: binary()}.
|
|
file_uri(Filename) when is_binary(Filename) ->
|
|
case binary:split(Filename, <<"-">>, [global]) of
|
|
[Year, Month, Day | _] ->
|
|
{ok, <<"https://lgsiot.njau.edu.cn/upload/", Year/binary, $/, Month/binary, $/, Day/binary, $/, Filename/binary>>};
|
|
_ ->
|
|
error
|
|
end. |