Merge pull request #6162 from HJianBo/port-44-exhook-feat
Pass message header to 'on_message_publish' hook
This commit is contained in:
commit
d551c7977d
|
@ -192,6 +192,7 @@
|
||||||
username => username(),
|
username => username(),
|
||||||
peerhost => peerhost(),
|
peerhost => peerhost(),
|
||||||
properties => properties(),
|
properties => properties(),
|
||||||
|
allow_publish => boolean(),
|
||||||
atom() => term()}).
|
atom() => term()}).
|
||||||
|
|
||||||
-type(banned() :: #banned{}).
|
-type(banned() :: #banned{}).
|
||||||
|
|
|
@ -25,6 +25,12 @@ exhook {
|
||||||
## Value: false | Duration
|
## Value: false | Duration
|
||||||
auto_reconnect = 60s
|
auto_reconnect = 60s
|
||||||
|
|
||||||
|
## The process pool size for gRPC client
|
||||||
|
##
|
||||||
|
## Default: Equals cpu cores
|
||||||
|
## Value: Integer
|
||||||
|
#pool_size = 16
|
||||||
|
|
||||||
servers = [
|
servers = [
|
||||||
# { name: "default"
|
# { name: "default"
|
||||||
# url: "http://127.0.0.1:9000"
|
# url: "http://127.0.0.1:9000"
|
||||||
|
|
|
@ -358,6 +358,31 @@ message Message {
|
||||||
bytes payload = 6;
|
bytes payload = 6;
|
||||||
|
|
||||||
uint64 timestamp = 7;
|
uint64 timestamp = 7;
|
||||||
|
|
||||||
|
// The key of header can be:
|
||||||
|
// - username:
|
||||||
|
// * Readonly
|
||||||
|
// * The username of sender client
|
||||||
|
// * Value type: utf8 string
|
||||||
|
// - protocol:
|
||||||
|
// * Readonly
|
||||||
|
// * The protocol name of sender client
|
||||||
|
// * Value type: string enum with "mqtt", "mqtt-sn", ...
|
||||||
|
// - peerhost:
|
||||||
|
// * Readonly
|
||||||
|
// * The peerhost of sender client
|
||||||
|
// * Value type: ip address string
|
||||||
|
// - allow_publish:
|
||||||
|
// * Writable
|
||||||
|
// * Whether to allow the message to be published by emqx
|
||||||
|
// * Value type: string enum with "true", "false", default is "true"
|
||||||
|
//
|
||||||
|
// Notes: All header may be missing, which means that the message does not
|
||||||
|
// carry these headers. We can guarantee that clients coming from MQTT,
|
||||||
|
// MQTT-SN, CoAP, LwM2M and other natively supported protocol clients will
|
||||||
|
// carry these headers, but there is no guarantee that messages published
|
||||||
|
// by other means will do, e.g. messages published by HTTP-API
|
||||||
|
map<string, string> headers = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Property {
|
message Property {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{deps,
|
{deps,
|
||||||
[{grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.2"}}}
|
[{grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.4"}}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{grpc,
|
{grpc,
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
|
|
||||||
%% Utils
|
%% Utils
|
||||||
-export([ message/1
|
-export([ message/1
|
||||||
|
, headers/1
|
||||||
, stringfy/1
|
, stringfy/1
|
||||||
, merge_responsed_bool/2
|
, merge_responsed_bool/2
|
||||||
, merge_responsed_message/2
|
, merge_responsed_message/2
|
||||||
|
@ -61,6 +62,8 @@
|
||||||
, call_fold/3
|
, call_fold/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-elvis([{elvis_style, god_modules, disable}]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Clients
|
%% Clients
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -257,17 +260,58 @@ clientinfo(ClientInfo =
|
||||||
cn => maybe(maps:get(cn, ClientInfo, undefined)),
|
cn => maybe(maps:get(cn, ClientInfo, undefined)),
|
||||||
dn => maybe(maps:get(dn, ClientInfo, undefined))}.
|
dn => maybe(maps:get(dn, ClientInfo, undefined))}.
|
||||||
|
|
||||||
message(#message{id = Id, qos = Qos, from = From, topic = Topic, payload = Payload, timestamp = Ts}) ->
|
message(#message{id = Id, qos = Qos, from = From, topic = Topic,
|
||||||
|
payload = Payload, timestamp = Ts, headers = Headers}) ->
|
||||||
#{node => stringfy(node()),
|
#{node => stringfy(node()),
|
||||||
id => emqx_guid:to_hexstr(Id),
|
id => emqx_guid:to_hexstr(Id),
|
||||||
qos => Qos,
|
qos => Qos,
|
||||||
from => stringfy(From),
|
from => stringfy(From),
|
||||||
topic => Topic,
|
topic => Topic,
|
||||||
payload => Payload,
|
payload => Payload,
|
||||||
timestamp => Ts}.
|
timestamp => Ts,
|
||||||
|
headers => headers(Headers)
|
||||||
|
}.
|
||||||
|
|
||||||
assign_to_message(#{qos := Qos, topic := Topic, payload := Payload}, Message) ->
|
headers(Headers) ->
|
||||||
Message#message{qos = Qos, topic = Topic, payload = Payload}.
|
Ls = [username, protocol, peerhost, allow_publish],
|
||||||
|
maps:fold(
|
||||||
|
fun
|
||||||
|
(_, undefined, Acc) ->
|
||||||
|
Acc; %% Ignore undefined value
|
||||||
|
(K, V, Acc) ->
|
||||||
|
case lists:member(K, Ls) of
|
||||||
|
true ->
|
||||||
|
Acc#{atom_to_binary(K) => bin(K, V)};
|
||||||
|
_ ->
|
||||||
|
Acc
|
||||||
|
end
|
||||||
|
end, #{}, Headers).
|
||||||
|
|
||||||
|
bin(K, V) when K == username;
|
||||||
|
K == protocol;
|
||||||
|
K == allow_publish ->
|
||||||
|
bin(V);
|
||||||
|
bin(peerhost, V) ->
|
||||||
|
bin(inet:ntoa(V)).
|
||||||
|
|
||||||
|
bin(V) when is_binary(V) -> V;
|
||||||
|
bin(V) when is_atom(V) -> atom_to_binary(V);
|
||||||
|
bin(V) when is_list(V) -> iolist_to_binary(V).
|
||||||
|
|
||||||
|
assign_to_message(InMessage = #{qos := Qos, topic := Topic,
|
||||||
|
payload := Payload}, Message) ->
|
||||||
|
NMsg = Message#message{qos = Qos, topic = Topic, payload = Payload},
|
||||||
|
enrich_header(maps:get(headers, InMessage, #{}), NMsg).
|
||||||
|
|
||||||
|
enrich_header(Headers, Message) ->
|
||||||
|
case maps:get(<<"allow_publish">>, Headers, undefined) of
|
||||||
|
<<"false">> ->
|
||||||
|
emqx_message:set_header(allow_publish, false, Message);
|
||||||
|
<<"true">> ->
|
||||||
|
emqx_message:set_header(allow_publish, true, Message);
|
||||||
|
_ ->
|
||||||
|
Message
|
||||||
|
end.
|
||||||
|
|
||||||
topicfilters(Tfs) when is_list(Tfs) ->
|
topicfilters(Tfs) when is_list(Tfs) ->
|
||||||
[#{name => Topic, qos => Qos} || {Topic, #{qos := Qos}} <- Tfs].
|
[#{name => Topic, qos => Qos} || {Topic, #{qos := Qos}} <- Tfs].
|
||||||
|
@ -298,11 +342,7 @@ merge_responsed_bool(_Req, #{type := 'IGNORE'}) ->
|
||||||
ignore;
|
ignore;
|
||||||
merge_responsed_bool(Req, #{type := Type, value := {bool_result, NewBool}})
|
merge_responsed_bool(Req, #{type := Type, value := {bool_result, NewBool}})
|
||||||
when is_boolean(NewBool) ->
|
when is_boolean(NewBool) ->
|
||||||
NReq = Req#{result => NewBool},
|
{ret(Type), Req#{result => NewBool}};
|
||||||
case Type of
|
|
||||||
'CONTINUE' -> {ok, NReq};
|
|
||||||
'STOP_AND_RETURN' -> {stop, NReq}
|
|
||||||
end;
|
|
||||||
merge_responsed_bool(_Req, Resp) ->
|
merge_responsed_bool(_Req, Resp) ->
|
||||||
?SLOG(warning, #{msg => "unknown_responsed_value", resp => Resp}),
|
?SLOG(warning, #{msg => "unknown_responsed_value", resp => Resp}),
|
||||||
ignore.
|
ignore.
|
||||||
|
@ -310,11 +350,10 @@ merge_responsed_bool(_Req, Resp) ->
|
||||||
merge_responsed_message(_Req, #{type := 'IGNORE'}) ->
|
merge_responsed_message(_Req, #{type := 'IGNORE'}) ->
|
||||||
ignore;
|
ignore;
|
||||||
merge_responsed_message(Req, #{type := Type, value := {message, NMessage}}) ->
|
merge_responsed_message(Req, #{type := Type, value := {message, NMessage}}) ->
|
||||||
NReq = Req#{message => NMessage},
|
{ret(Type), Req#{message => NMessage}};
|
||||||
case Type of
|
|
||||||
'CONTINUE' -> {ok, NReq};
|
|
||||||
'STOP_AND_RETURN' -> {stop, NReq}
|
|
||||||
end;
|
|
||||||
merge_responsed_message(_Req, Resp) ->
|
merge_responsed_message(_Req, Resp) ->
|
||||||
?SLOG(warning, #{msg => "unknown_responsed_value", resp => Resp}),
|
?SLOG(warning, #{msg => "unknown_responsed_value", resp => Resp}),
|
||||||
ignore.
|
ignore.
|
||||||
|
|
||||||
|
ret('CONTINUE') -> ok;
|
||||||
|
ret('STOP_AND_RETURN') -> stop.
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
, server/1
|
, server/1
|
||||||
, put_request_failed_action/1
|
, put_request_failed_action/1
|
||||||
, get_request_failed_action/0
|
, get_request_failed_action/0
|
||||||
|
, put_pool_size/1
|
||||||
|
, get_pool_size/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
|
@ -117,6 +119,9 @@ init([Servers, AutoReconnect, ReqOpts0]) ->
|
||||||
put_request_failed_action(
|
put_request_failed_action(
|
||||||
maps:get(request_failed_action, ReqOpts0, deny)
|
maps:get(request_failed_action, ReqOpts0, deny)
|
||||||
),
|
),
|
||||||
|
put_pool_size(
|
||||||
|
maps:get(pool_size, ReqOpts0, erlang:system_info(schedulers))
|
||||||
|
),
|
||||||
|
|
||||||
%% Load the hook servers
|
%% Load the hook servers
|
||||||
ReqOpts = maps:without([request_failed_action], ReqOpts0),
|
ReqOpts = maps:without([request_failed_action], ReqOpts0),
|
||||||
|
@ -136,7 +141,7 @@ load_all_servers(Servers, ReqOpts) ->
|
||||||
load_all_servers(Servers, ReqOpts, #{}, #{}).
|
load_all_servers(Servers, ReqOpts, #{}, #{}).
|
||||||
load_all_servers([], _Request, Waiting, Running) ->
|
load_all_servers([], _Request, Waiting, Running) ->
|
||||||
{Waiting, Running};
|
{Waiting, Running};
|
||||||
load_all_servers([#{name := Name0} = Options0|More], ReqOpts, Waiting, Running) ->
|
load_all_servers([#{name := Name0} = Options0 | More], ReqOpts, Waiting, Running) ->
|
||||||
Name = iolist_to_binary(Name0),
|
Name = iolist_to_binary(Name0),
|
||||||
Options = Options0#{name => Name},
|
Options = Options0#{name => Name},
|
||||||
{NWaiting, NRunning} =
|
{NWaiting, NRunning} =
|
||||||
|
@ -291,6 +296,14 @@ put_request_failed_action(Val) ->
|
||||||
get_request_failed_action() ->
|
get_request_failed_action() ->
|
||||||
persistent_term:get({?APP, request_failed_action}).
|
persistent_term:get({?APP, request_failed_action}).
|
||||||
|
|
||||||
|
put_pool_size(Val) ->
|
||||||
|
persistent_term:put({?APP, pool_size}, Val).
|
||||||
|
|
||||||
|
get_pool_size() ->
|
||||||
|
%% Avoid the scenario that the parameter is not set after
|
||||||
|
%% the hot upgrade completed.
|
||||||
|
persistent_term:get({?APP, pool_size}, erlang:system_info(schedulers)).
|
||||||
|
|
||||||
save(Name, ServerState) ->
|
save(Name, ServerState) ->
|
||||||
Saved = persistent_term:get(?APP, []),
|
Saved = persistent_term:get(?APP, []),
|
||||||
persistent_term:put(?APP, lists:reverse([Name | Saved])),
|
persistent_term:put(?APP, lists:reverse([Name | Saved])),
|
||||||
|
|
|
@ -49,6 +49,10 @@ fields(exhook) ->
|
||||||
sc(hoconsc:union([false, duration()]),
|
sc(hoconsc:union([false, duration()]),
|
||||||
#{ default => "60s"
|
#{ default => "60s"
|
||||||
})}
|
})}
|
||||||
|
, {pool_size,
|
||||||
|
sc(integer(),
|
||||||
|
#{ nullable => true
|
||||||
|
})}
|
||||||
, {servers,
|
, {servers,
|
||||||
sc(hoconsc:array(ref(servers)),
|
sc(hoconsc:array(ref(servers)),
|
||||||
#{default => []})}
|
#{default => []})}
|
||||||
|
|
|
@ -75,6 +75,8 @@
|
||||||
|
|
||||||
-dialyzer({nowarn_function, [inc_metrics/2]}).
|
-dialyzer({nowarn_function, [inc_metrics/2]}).
|
||||||
|
|
||||||
|
-elvis([{elvis_style, dont_repeat_yourself, disable}]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Load/Unload APIs
|
%% Load/Unload APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -108,9 +110,10 @@ load(Name, Opts0, ReqOpts) ->
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
channel_opts(Opts = #{url := URL}) ->
|
channel_opts(Opts = #{url := URL}) ->
|
||||||
|
ClientOpts = #{pool_size => emqx_exhook_mngr:get_pool_size()},
|
||||||
case uri_string:parse(URL) of
|
case uri_string:parse(URL) of
|
||||||
#{scheme := "http", host := Host, port := Port} ->
|
#{scheme := "http", host := Host, port := Port} ->
|
||||||
{format_http_uri("http", Host, Port), #{}};
|
{format_http_uri("http", Host, Port), ClientOpts};
|
||||||
#{scheme := "https", host := Host, port := Port} ->
|
#{scheme := "https", host := Host, port := Port} ->
|
||||||
SslOpts =
|
SslOpts =
|
||||||
case maps:get(ssl, Opts, undefined) of
|
case maps:get(ssl, Opts, undefined) of
|
||||||
|
@ -122,8 +125,12 @@ channel_opts(Opts = #{url := URL}) ->
|
||||||
{keyfile, maps:get(keyfile, MapOpts, undefined)}
|
{keyfile, maps:get(keyfile, MapOpts, undefined)}
|
||||||
])
|
])
|
||||||
end,
|
end,
|
||||||
{format_http_uri("https", Host, Port),
|
NClientOpts = ClientOpts#{
|
||||||
#{gun_opts => #{transport => ssl, transport_opts => SslOpts}}};
|
gun_opts =>
|
||||||
|
#{transport => ssl,
|
||||||
|
transport_opts => SslOpts}
|
||||||
|
},
|
||||||
|
{format_http_uri("https", Host, Port), NClientOpts};
|
||||||
_ ->
|
_ ->
|
||||||
error(bad_server_url)
|
error(bad_server_url)
|
||||||
end.
|
end.
|
||||||
|
@ -173,16 +180,19 @@ resolve_hookspec(HookSpecs) when is_list(HookSpecs) ->
|
||||||
case maps:get(name, HookSpec, undefined) of
|
case maps:get(name, HookSpec, undefined) of
|
||||||
undefined -> Acc;
|
undefined -> Acc;
|
||||||
Name0 ->
|
Name0 ->
|
||||||
Name = try binary_to_existing_atom(Name0, utf8) catch T:R:_ -> {T,R} end,
|
Name = try
|
||||||
case lists:member(Name, AvailableHooks) of
|
binary_to_existing_atom(Name0, utf8)
|
||||||
true ->
|
catch T:R:_ -> {T,R}
|
||||||
case lists:member(Name, MessageHooks) of
|
end,
|
||||||
true ->
|
case {lists:member(Name, AvailableHooks),
|
||||||
Acc#{Name => #{topics => maps:get(topics, HookSpec, [])}};
|
lists:member(Name, MessageHooks)} of
|
||||||
_ ->
|
{false, _} ->
|
||||||
Acc#{Name => #{}}
|
error({unknown_hookpoint, Name});
|
||||||
end;
|
{true, false} ->
|
||||||
_ -> error({unknown_hookpoint, Name})
|
Acc#{Name => #{}};
|
||||||
|
{true, true} ->
|
||||||
|
Acc#{Name => #{
|
||||||
|
topics => maps:get(topics, HookSpec, [])}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end, #{}, HookSpecs).
|
end, #{}, HookSpecs).
|
||||||
|
@ -255,7 +265,7 @@ call(Hookpoint, Req, #server{name = ChannName, options = ReqOpts,
|
||||||
%% @private
|
%% @private
|
||||||
inc_metrics(IncFun, Name) when is_function(IncFun) ->
|
inc_metrics(IncFun, Name) when is_function(IncFun) ->
|
||||||
%% BACKW: e4.2.0-e4.2.2
|
%% BACKW: e4.2.0-e4.2.2
|
||||||
{env, [Prefix|_]} = erlang:fun_info(IncFun, env),
|
{env, [Prefix | _]} = erlang:fun_info(IncFun, env),
|
||||||
inc_metrics(Prefix, Name);
|
inc_metrics(Prefix, Name);
|
||||||
inc_metrics(Prefix, Name) when is_list(Prefix) ->
|
inc_metrics(Prefix, Name) when is_list(Prefix) ->
|
||||||
emqx_metrics:inc(list_to_atom(Prefix ++ atom_to_list(Name))).
|
emqx_metrics:inc(list_to_atom(Prefix ++ atom_to_list(Name))).
|
||||||
|
|
|
@ -54,7 +54,8 @@ auto_reconnect() ->
|
||||||
|
|
||||||
request_options() ->
|
request_options() ->
|
||||||
#{timeout => env(request_timeout, 5000),
|
#{timeout => env(request_timeout, 5000),
|
||||||
request_failed_action => env(request_failed_action, deny)
|
request_failed_action => env(request_failed_action, deny),
|
||||||
|
pool_size => env(pool_size, erlang:system_info(schedulers))
|
||||||
}.
|
}.
|
||||||
|
|
||||||
env(Key, Def) ->
|
env(Key, Def) ->
|
||||||
|
@ -67,7 +68,7 @@ env(Key, Def) ->
|
||||||
-spec start_grpc_client_channel(
|
-spec start_grpc_client_channel(
|
||||||
binary(),
|
binary(),
|
||||||
uri_string:uri_string(),
|
uri_string:uri_string(),
|
||||||
grpc_client:options()) -> {ok, pid()} | {error, term()}.
|
grpc_client_sup:options()) -> {ok, pid()} | {error, term()}.
|
||||||
start_grpc_client_channel(Name, SvrAddr, Options) ->
|
start_grpc_client_channel(Name, SvrAddr, Options) ->
|
||||||
grpc_client_sup:create_channel_pool(Name, SvrAddr, Options).
|
grpc_client_sup:create_channel_pool(Name, SvrAddr, Options).
|
||||||
|
|
||||||
|
|
|
@ -299,21 +299,31 @@ on_message_publish(#{message := #{from := From} = Msg} = Req, Md) ->
|
||||||
%% some cases for testing
|
%% some cases for testing
|
||||||
case From of
|
case From of
|
||||||
<<"baduser">> ->
|
<<"baduser">> ->
|
||||||
NMsg = Msg#{qos => 0,
|
NMsg = deny(Msg#{qos => 0,
|
||||||
topic => <<"">>,
|
topic => <<"">>,
|
||||||
payload => <<"">>
|
payload => <<"">>
|
||||||
},
|
}),
|
||||||
{ok, #{type => 'STOP_AND_RETURN',
|
{ok, #{type => 'STOP_AND_RETURN',
|
||||||
value => {message, NMsg}}, Md};
|
value => {message, NMsg}}, Md};
|
||||||
<<"gooduser">> ->
|
<<"gooduser">> ->
|
||||||
NMsg = Msg#{topic => From,
|
NMsg = allow(Msg#{topic => From,
|
||||||
payload => From},
|
payload => From}),
|
||||||
{ok, #{type => 'STOP_AND_RETURN',
|
{ok, #{type => 'STOP_AND_RETURN',
|
||||||
value => {message, NMsg}}, Md};
|
value => {message, NMsg}}, Md};
|
||||||
_ ->
|
_ ->
|
||||||
{ok, #{type => 'IGNORE'}, Md}
|
{ok, #{type => 'IGNORE'}, Md}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
deny(Msg) ->
|
||||||
|
NHeader = maps:put(<<"allow_publish">>, <<"false">>,
|
||||||
|
maps:get(headers, Msg, #{})),
|
||||||
|
maps:put(headers, NHeader, Msg).
|
||||||
|
|
||||||
|
allow(Msg) ->
|
||||||
|
NHeader = maps:put(<<"allow_publish">>, <<"true">>,
|
||||||
|
maps:get(headers, Msg, #{})),
|
||||||
|
maps:put(headers, NHeader, Msg).
|
||||||
|
|
||||||
-spec on_message_delivered(emqx_exhook_pb:message_delivered_request(), grpc:metadata())
|
-spec on_message_delivered(emqx_exhook_pb:message_delivered_request(), grpc:metadata())
|
||||||
-> {ok, emqx_exhook_pb:empty_success(), grpc:metadata()}
|
-> {ok, emqx_exhook_pb:empty_success(), grpc:metadata()}
|
||||||
| {error, grpc_cowboy_h:error_response()}.
|
| {error, grpc_cowboy_h:error_response()}.
|
||||||
|
|
|
@ -296,19 +296,24 @@ prop_message_publish() ->
|
||||||
_ ->
|
_ ->
|
||||||
ExpectedOutMsg = case emqx_message:from(Msg) of
|
ExpectedOutMsg = case emqx_message:from(Msg) of
|
||||||
<<"baduser">> ->
|
<<"baduser">> ->
|
||||||
MsgMap = emqx_message:to_map(Msg),
|
MsgMap = #{headers := Headers}
|
||||||
|
= emqx_message:to_map(Msg),
|
||||||
emqx_message:from_map(
|
emqx_message:from_map(
|
||||||
MsgMap#{qos => 0,
|
MsgMap#{qos => 0,
|
||||||
topic => <<"">>,
|
topic => <<"">>,
|
||||||
payload => <<"">>
|
payload => <<"">>,
|
||||||
|
headers => maps:put(allow_publish, false, Headers)
|
||||||
});
|
});
|
||||||
<<"gooduser">> = From ->
|
<<"gooduser">> = From ->
|
||||||
MsgMap = emqx_message:to_map(Msg),
|
MsgMap = #{headers := Headers}
|
||||||
|
= emqx_message:to_map(Msg),
|
||||||
emqx_message:from_map(
|
emqx_message:from_map(
|
||||||
MsgMap#{topic => From,
|
MsgMap#{topic => From,
|
||||||
payload => From
|
payload => From,
|
||||||
|
headers => maps:put(allow_publish, true, Headers)
|
||||||
});
|
});
|
||||||
_ -> Msg
|
_ ->
|
||||||
|
Msg
|
||||||
end,
|
end,
|
||||||
?assertEqual(ExpectedOutMsg, OutMsg),
|
?assertEqual(ExpectedOutMsg, OutMsg),
|
||||||
|
|
||||||
|
@ -461,7 +466,9 @@ from_message(Msg) ->
|
||||||
from => stringfy(emqx_message:from(Msg)),
|
from => stringfy(emqx_message:from(Msg)),
|
||||||
topic => emqx_message:topic(Msg),
|
topic => emqx_message:topic(Msg),
|
||||||
payload => emqx_message:payload(Msg),
|
payload => emqx_message:payload(Msg),
|
||||||
timestamp => emqx_message:timestamp(Msg)
|
timestamp => emqx_message:timestamp(Msg),
|
||||||
|
headers => emqx_exhook_handler:headers(
|
||||||
|
emqx_message:get_headers(Msg))
|
||||||
}.
|
}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
{deps, [
|
{deps, [
|
||||||
{grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.2"}}}
|
{grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.4"}}}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{plugins, [
|
{plugins, [
|
||||||
|
|
Loading…
Reference in New Issue