emqx/apps/emqx_rule_engine/src/emqx_rule_api_schema.erl

148 lines
6.6 KiB
Erlang

-module(emqx_rule_api_schema).
-behaviour(hocon_schema).
-include_lib("typerefl/include/types.hrl").
-include_lib("emqx/include/logger.hrl").
-export([ check_params/2
]).
-export([roots/0, fields/1]).
-type tag() :: rule_creation | rule_test.
-spec check_params(map(), tag()) -> {ok, map()} | {error, term()}.
check_params(Params, Tag) ->
BTag = atom_to_binary(Tag),
try hocon_schema:check_plain(?MODULE, #{BTag => Params},
#{atom_key => true, nullable => true}, [BTag]) of
#{Tag := Checked} -> {ok, Checked}
catch
Error:Reason:ST ->
?SLOG(error, #{msg => "check_rule_params_failed",
exception => Error,
reason => Reason,
stacktrace => ST}),
{error, {Reason, ST}}
end.
%%======================================================================================
%% Hocon Schema Definitions
roots() ->
[ {"rule_creation", sc(ref("rule_creation"), #{desc => "Schema for creating rules"})}
, {"rule_test", sc(ref("rule_test"), #{desc => "Schema for testing rules"})}
].
fields("rule_creation") ->
[ {"id", sc(binary(), #{desc => "The Id of the rule", nullable => false})}
] ++ emqx_rule_engine_schema:fields("rules");
fields("rule_test") ->
[ {"context", sc(hoconsc:union([ ref("ctx_pub")
, ref("ctx_sub")
, ref("ctx_delivered")
, ref("ctx_acked")
, ref("ctx_dropped")
, ref("ctx_connected")
, ref("ctx_disconnected")
]),
#{desc => "The context of the event for testing",
default => #{}})}
, {"sql", sc(binary(), #{desc => "The SQL of the rule for testing", nullable => false})}
];
fields("ctx_pub") ->
[ {"event_type", sc(message_publish, #{desc => "Event Type", nullable => false})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
] ++ [qos()];
fields("ctx_sub") ->
[ {"event_type", sc(session_subscribed, #{desc => "Event Type", nullable => false})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
] ++ [qos()];
fields("ctx_unsub") ->
[{"event_type", sc(session_unsubscribed, #{desc => "Event Type", nullable => false})}] ++
proplists:delete("event_type", fields("ctx_sub"));
fields("ctx_delivered") ->
[ {"event_type", sc(message_delivered, #{desc => "Event Type", nullable => false})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"from_clientid", sc(binary(), #{desc => "The Client ID"})}
, {"from_username", sc(binary(), #{desc => "The User Name"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
] ++ [qos()];
fields("ctx_acked") ->
[{"event_type", sc(message_acked, #{desc => "Event Type", nullable => false})}] ++
proplists:delete("event_type", fields("ctx_delivered"));
fields("ctx_dropped") ->
[ {"event_type", sc(message_dropped, #{desc => "Event Type", nullable => false})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"reason", sc(binary(), #{desc => "The Reason for Dropping"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
] ++ [qos()];
fields("ctx_connected") ->
[ {"event_type", sc(client_connected, #{desc => "Event Type", nullable => false})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"mountpoint", sc(binary(), #{desc => "The Mountpoint"})}
, {"peername", sc(binary(), #{desc => "The IP Address and Port of the Peer Client"})}
, {"sockname", sc(binary(), #{desc => "The IP Address and Port of the Local Listener"})}
, {"proto_name", sc(binary(), #{desc => "Protocol Name"})}
, {"proto_ver", sc(binary(), #{desc => "Protocol Version"})}
, {"keepalive", sc(integer(), #{desc => "KeepAlive"})}
, {"clean_start", sc(boolean(), #{desc => "Clean Start", default => true})}
, {"expiry_interval", sc(integer(), #{desc => "Expiry Interval"})}
, {"is_bridge", sc(boolean(), #{desc => "Is Bridge", default => false})}
, {"connected_at", sc(integer(), #{
desc => "The Time that this Client is Connected"})}
];
fields("ctx_disconnected") ->
[ {"event_type", sc(client_disconnected, #{desc => "Event Type", nullable => false})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"reason", sc(binary(), #{desc => "The Reason for Disconnect"})}
, {"peername", sc(binary(), #{desc => "The IP Address and Port of the Peer Client"})}
, {"sockname", sc(binary(), #{desc => "The IP Address and Port of the Local Listener"})}
, {"disconnected_at", sc(integer(), #{
desc => "The Time that this Client is Disconnected"})}
].
qos() ->
{"qos", sc(hoconsc:union([typerefl:integer(0), typerefl:integer(1), typerefl:integer(2)]),
#{desc => "The Message QoS"})}.
sc(Type, Meta) -> hoconsc:mk(Type, Meta).
ref(Field) -> hoconsc:ref(?MODULE, Field).