feat(bpapi): Introduce bpapi behavior
This commit is contained in:
parent
0f6ec9d646
commit
4f3f938d71
|
@ -15,9 +15,7 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-module(emqx_bpapi).
|
-module(emqx_bpapi).
|
||||||
|
|
||||||
-export_type([var_name/0, call/0, rpc/0, bpapi_meta/0, semver/0]).
|
-export_type([var_name/0, call/0, rpc/0, bpapi_meta/0]).
|
||||||
|
|
||||||
-type semver() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
|
|
||||||
|
|
||||||
-type api() :: atom().
|
-type api() :: atom().
|
||||||
-type api_version() :: non_neg_integer().
|
-type api_version() :: non_neg_integer().
|
||||||
|
@ -31,3 +29,11 @@
|
||||||
, calls := [rpc()]
|
, calls := [rpc()]
|
||||||
, casts := [rpc()]
|
, casts := [rpc()]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-callback introduced_in() -> string().
|
||||||
|
|
||||||
|
-callback deprecated_since() -> string().
|
||||||
|
|
||||||
|
-callback bpapi_meta() -> bpapi_meta().
|
||||||
|
|
||||||
|
-optional_callbacks([deprecated_since/0]).
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
{ api :: atom()
|
{ api :: atom()
|
||||||
, module :: atom()
|
, module :: atom()
|
||||||
, version :: non_neg_integer() | undefined
|
, version :: non_neg_integer() | undefined
|
||||||
, introduced_in :: emqx_bpapi:semver() | undefined
|
|
||||||
, deprecated_since :: emqx_bpapi:semver() | undefined
|
|
||||||
, targets = [] :: [{semantics(), emqx_bpapi:call(), emqx_bpapi:call()}]
|
, targets = [] :: [{semantics(), emqx_bpapi:call(), emqx_bpapi:call()}]
|
||||||
, errors = [] :: [string()]
|
, errors = [] :: [string()]
|
||||||
, file
|
, file
|
||||||
|
@ -39,10 +37,6 @@
|
||||||
|
|
||||||
format_error(invalid_name) ->
|
format_error(invalid_name) ->
|
||||||
"BPAPI module name should follow <API>_proto_v<number> pattern";
|
"BPAPI module name should follow <API>_proto_v<number> pattern";
|
||||||
format_error(invalid_introduced_in) ->
|
|
||||||
"-introduced_in attribute should be present and its value should be a semver string";
|
|
||||||
format_error(invalid_deprecated_since) ->
|
|
||||||
"value of -deprecated_since attribute should be a semver string";
|
|
||||||
format_error({invalid_fun, Name, Arity}) ->
|
format_error({invalid_fun, Name, Arity}) ->
|
||||||
io_lib:format("malformed function ~p/~p. "
|
io_lib:format("malformed function ~p/~p. "
|
||||||
"BPAPI functions should have exactly one clause "
|
"BPAPI functions should have exactly one clause "
|
||||||
|
@ -68,24 +62,18 @@ go({attribute, Line, module, Mod}, S) ->
|
||||||
{ok, API, Vsn} -> S#s{api = API, version = Vsn, module = Mod};
|
{ok, API, Vsn} -> S#s{api = API, version = Vsn, module = Mod};
|
||||||
error -> push_err(Line, invalid_name, S)
|
error -> push_err(Line, invalid_name, S)
|
||||||
end;
|
end;
|
||||||
go({attribute, _Line, introduced_in, Str}, S) ->
|
go({function, _Line, introduced_in, 0, _}, S) ->
|
||||||
case is_list(Str) andalso parse_semver(Str) of
|
S;
|
||||||
{ok, Vsn} -> S#s{introduced_in = Vsn};
|
go({function, _Line, deprecated_since, 0, _}, S) ->
|
||||||
error -> S %% Don't report error here, it's done in check/1
|
S;
|
||||||
end;
|
|
||||||
go({attribute, Line, deprecated_since, Str}, S) ->
|
|
||||||
case is_list(Str) andalso parse_semver(Str) of
|
|
||||||
{ok, Vsn} -> S#s{deprecated_since = Vsn};
|
|
||||||
error -> push_err(Line, invalid_deprecated_since, S)
|
|
||||||
end;
|
|
||||||
go({function, Line, Name, Arity, Clauses}, S) ->
|
go({function, Line, Name, Arity, Clauses}, S) ->
|
||||||
analyze_fun(Line, Name, Arity, Clauses, S);
|
analyze_fun(Line, Name, Arity, Clauses, S);
|
||||||
go(_, S) ->
|
go(_, S) ->
|
||||||
S.
|
S.
|
||||||
|
|
||||||
check(#s{errors = Err0, introduced_in = II}) ->
|
check(#s{errors = Err}) ->
|
||||||
[{none, invalid_introduced_in} || II =:= undefined] ++
|
%% Post-processing checks can be placed here
|
||||||
Err0.
|
Err.
|
||||||
|
|
||||||
finalize(Forms, S) ->
|
finalize(Forms, S) ->
|
||||||
{Attrs, Funcs} = lists:splitwith(fun is_attribute/1, Forms),
|
{Attrs, Funcs} = lists:splitwith(fun is_attribute/1, Forms),
|
||||||
|
@ -191,16 +179,6 @@ push_err(Line, Err, S = #s{errors = Errs}) ->
|
||||||
push_target(Target, S = #s{targets = Targets}) ->
|
push_target(Target, S = #s{targets = Targets}) ->
|
||||||
S#s{targets = [Target|Targets]}.
|
S#s{targets = [Target|Targets]}.
|
||||||
|
|
||||||
|
|
||||||
-spec parse_semver(string()) -> {ok, emqx_bpapi:semver()}
|
|
||||||
| error.
|
|
||||||
parse_semver(Str) ->
|
|
||||||
Opts = [{capture, all_but_first, list}],
|
|
||||||
case re:run(Str, "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$", Opts) of
|
|
||||||
{match, [A, B, C]} -> {ok, {list_to_integer(A), list_to_integer(B), list_to_integer(C)}};
|
|
||||||
nomatch -> error
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec api_and_version(module()) -> {ok, emqx_bpapi:api(), emqx_bpapi:version()} | error.
|
-spec api_and_version(module()) -> {ok, emqx_bpapi:api(), emqx_bpapi:version()} | error.
|
||||||
api_and_version(Module) ->
|
api_and_version(Module) ->
|
||||||
Opts = [{capture, all_but_first, list}],
|
Opts = [{capture, all_but_first, list}],
|
||||||
|
|
|
@ -16,15 +16,19 @@
|
||||||
|
|
||||||
-module(emqx_broker_proto_v1).
|
-module(emqx_broker_proto_v1).
|
||||||
|
|
||||||
-introduced_in("5.0.0").
|
-behaviour(emqx_bpapi).
|
||||||
|
|
||||||
-export([ forward/3
|
-export([ introduced_in/0
|
||||||
|
, forward/3
|
||||||
, forward_async/3
|
, forward_async/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("bpapi.hrl").
|
-include("bpapi.hrl").
|
||||||
-include("emqx.hrl").
|
-include("emqx.hrl").
|
||||||
|
|
||||||
|
introduced_in() ->
|
||||||
|
"5.0.0".
|
||||||
|
|
||||||
-spec forward(node(), emqx_types:topic(), emqx_types:delivery()) -> emqx_types:deliver_result().
|
-spec forward(node(), emqx_types:topic(), emqx_types:delivery()) -> emqx_types:deliver_result().
|
||||||
forward(Node, Topic, Delivery = #delivery{}) when is_binary(Topic) ->
|
forward(Node, Topic, Delivery = #delivery{}) when is_binary(Topic) ->
|
||||||
emqx_rpc:call(Topic, Node, emqx_broker, dispatch, [Topic, Delivery]).
|
emqx_rpc:call(Topic, Node, emqx_broker, dispatch, [Topic, Delivery]).
|
||||||
|
|
Loading…
Reference in New Issue