refactor(gw): rename gateway type to name
This commit is contained in:
parent
9072a60652
commit
c5a4e05418
|
@ -18,11 +18,11 @@
|
||||||
-define(EMQX_GATEWAY_HRL, 1).
|
-define(EMQX_GATEWAY_HRL, 1).
|
||||||
|
|
||||||
-type instance_id() :: atom().
|
-type instance_id() :: atom().
|
||||||
-type gateway_type() :: atom().
|
-type gateway_name() :: atom().
|
||||||
|
|
||||||
%% @doc The Gateway defination
|
%% @doc The Gateway defination
|
||||||
-type gateway() ::
|
-type gateway() ::
|
||||||
#{ type := gateway_type()
|
#{ name := gateway_name()
|
||||||
, descr => binary() | undefined
|
, descr => binary() | undefined
|
||||||
%% Appears only in creating or detailed info
|
%% Appears only in creating or detailed info
|
||||||
, rawconf => map()
|
, rawconf => map()
|
||||||
|
|
|
@ -48,18 +48,18 @@ unreg() ->
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_gateway_load(_Gateway = #{type := GwType,
|
on_gateway_load(_Gateway = #{name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx) ->
|
}, Ctx) ->
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(GwType, Ctx, Lis)
|
start_listener(GwName, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
|
|
||||||
{ok, ListenerPids, #{ctx => Ctx}}.
|
{ok, ListenerPids, #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
GwType = maps:get(type, NewGateway),
|
GwName = maps:get(name, NewGateway),
|
||||||
try
|
try
|
||||||
%% XXX: 1. How hot-upgrade the changes ???
|
%% XXX: 1. How hot-upgrade the changes ???
|
||||||
%% XXX: 2. Check the New confs first before destroy old instance ???
|
%% XXX: 2. Check the New confs first before destroy old instance ???
|
||||||
|
@ -69,37 +69,37 @@ on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[GwType, Class, Reason, Stk]),
|
[GwName, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_gateway_unload(_Gateway = #{ type := GwType,
|
on_gateway_unload(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwState) ->
|
}, _GwState) ->
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(GwType, Lis)
|
stop_listener(GwName, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwName, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]),
|
[GwName, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason]),
|
[GwName, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_coap_frame,
|
frame_mod => emqx_coap_frame,
|
||||||
|
@ -114,21 +114,21 @@ do_start_listener(udp, Name, ListenOn, SocketOpts, MFA) ->
|
||||||
do_start_listener(dtls, Name, ListenOn, SocketOpts, MFA) ->
|
do_start_listener(dtls, Name, ListenOn, SocketOpts, MFA) ->
|
||||||
esockd:open_dtls(Name, ListenOn, SocketOpts, MFA).
|
esockd:open_dtls(Name, ListenOn, SocketOpts, MFA).
|
||||||
|
|
||||||
name(GwType, Type) ->
|
name(GwName, Type) ->
|
||||||
list_to_atom(lists:concat([GwType, ":", Type])).
|
list_to_atom(lists:concat([GwName, ":", Type])).
|
||||||
|
|
||||||
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwName, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(GwType, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwName, Type, ListenOn, SocketOpts, Cfg),
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case StopRet of
|
case StopRet of
|
||||||
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]);
|
[GwName, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason])
|
[GwName, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwName, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-spec registered_gateway() ->
|
-spec registered_gateway() ->
|
||||||
[{gateway_type(), emqx_gateway_registry:descriptor()}].
|
[{gateway_name(), emqx_gateway_registry:descriptor()}].
|
||||||
registered_gateway() ->
|
registered_gateway() ->
|
||||||
emqx_gateway_registry:list().
|
emqx_gateway_registry:list().
|
||||||
|
|
||||||
|
@ -41,35 +41,35 @@ registered_gateway() ->
|
||||||
list() ->
|
list() ->
|
||||||
emqx_gateway_sup:list_gateway_insta().
|
emqx_gateway_sup:list_gateway_insta().
|
||||||
|
|
||||||
-spec load(gateway_type(), map())
|
-spec load(gateway_name(), map())
|
||||||
-> {ok, pid()}
|
-> {ok, pid()}
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
load(GwType, RawConf) ->
|
load(Name, RawConf) ->
|
||||||
Gateway = #{ type => GwType
|
Gateway = #{ name => Name
|
||||||
, descr => undefined
|
, descr => undefined
|
||||||
, rawconf => RawConf
|
, rawconf => RawConf
|
||||||
},
|
},
|
||||||
emqx_gateway_sup:load_gateway(Gateway).
|
emqx_gateway_sup:load_gateway(Gateway).
|
||||||
|
|
||||||
-spec unload(gateway_type()) -> ok | {error, any()}.
|
-spec unload(gateway_name()) -> ok | {error, any()}.
|
||||||
unload(GwType) ->
|
unload(Name) ->
|
||||||
emqx_gateway_sup:unload_gateway(GwType).
|
emqx_gateway_sup:unload_gateway(Name).
|
||||||
|
|
||||||
-spec lookup(gateway_type()) -> gateway() | undefined.
|
-spec lookup(gateway_name()) -> gateway() | undefined.
|
||||||
lookup(GwType) ->
|
lookup(Name) ->
|
||||||
emqx_gateway_sup:lookup_gateway(GwType).
|
emqx_gateway_sup:lookup_gateway(Name).
|
||||||
|
|
||||||
-spec update(gateway()) -> ok | {error, any()}.
|
-spec update(gateway()) -> ok | {error, any()}.
|
||||||
update(NewGateway) ->
|
update(NewGateway) ->
|
||||||
emqx_gateway_sup:update_gateway(NewGateway).
|
emqx_gateway_sup:update_gateway(NewGateway).
|
||||||
|
|
||||||
-spec start(gateway_type()) -> ok | {error, any()}.
|
-spec start(gateway_name()) -> ok | {error, any()}.
|
||||||
start(GwType) ->
|
start(Name) ->
|
||||||
emqx_gateway_sup:start_gateway_insta(GwType).
|
emqx_gateway_sup:start_gateway_insta(Name).
|
||||||
|
|
||||||
-spec stop(gateway_type()) -> ok | {error, any()}.
|
-spec stop(gateway_name()) -> ok | {error, any()}.
|
||||||
stop(GwType) ->
|
stop(Name) ->
|
||||||
emqx_gateway_sup:stop_gateway_insta(GwType).
|
emqx_gateway_sup:stop_gateway_insta(Name).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
|
|
|
@ -50,30 +50,31 @@ is_cmd(Fun) ->
|
||||||
%% Cmds
|
%% Cmds
|
||||||
|
|
||||||
gateway(["list"]) ->
|
gateway(["list"]) ->
|
||||||
lists:foreach(fun(#{type := Type, status := Status}) ->
|
lists:foreach(fun(#{name := Name} = Gateway) ->
|
||||||
%% FIXME: Get the real running status
|
%% XXX: More infos: listeners?, connected?
|
||||||
emqx_ctl:print("Gateway(type=~s, status=~s~n",
|
Status = maps:get(status, Gateway, stopped),
|
||||||
[Type, Status])
|
emqx_ctl:print("Gateway(name=~s, status=~s)~n",
|
||||||
|
[Name, Status])
|
||||||
end, emqx_gateway:list());
|
end, emqx_gateway:list());
|
||||||
|
|
||||||
gateway(["lookup", GwType]) ->
|
gateway(["lookup", Name]) ->
|
||||||
case emqx_gateway:lookup(atom(GwType)) of
|
case emqx_gateway:lookup(atom(Name)) of
|
||||||
undefined ->
|
undefined ->
|
||||||
emqx_ctl:print("undefined~n");
|
emqx_ctl:print("undefined~n");
|
||||||
Info ->
|
Info ->
|
||||||
emqx_ctl:print("~p~n", [Info])
|
emqx_ctl:print("~p~n", [Info])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
gateway(["stop", GwType]) ->
|
gateway(["stop", Name]) ->
|
||||||
case emqx_gateway:stop(atom(GwType)) of
|
case emqx_gateway:stop(atom(Name)) of
|
||||||
ok ->
|
ok ->
|
||||||
emqx_ctl:print("ok~n");
|
emqx_ctl:print("ok~n");
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
emqx_ctl:print("Error: ~p~n", [Reason])
|
emqx_ctl:print("Error: ~p~n", [Reason])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
gateway(["start", GwType]) ->
|
gateway(["start", Name]) ->
|
||||||
case emqx_gateway:start(atom(GwType)) of
|
case emqx_gateway:start(atom(Name)) of
|
||||||
ok ->
|
ok ->
|
||||||
emqx_ctl:print("ok~n");
|
emqx_ctl:print("ok~n");
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -84,60 +85,60 @@ gateway(_) ->
|
||||||
%% TODO: create/remove APIs
|
%% TODO: create/remove APIs
|
||||||
emqx_ctl:usage([ {"gateway list",
|
emqx_ctl:usage([ {"gateway list",
|
||||||
"List all gateway"}
|
"List all gateway"}
|
||||||
, {"gateway lookup <GatewayType>",
|
, {"gateway lookup <Name>",
|
||||||
"Looup a gateway detailed informations"}
|
"Lookup a gateway detailed informations"}
|
||||||
, {"gateway stop <GatewayType>",
|
, {"gateway stop <Name>",
|
||||||
"Stop a gateway instance"}
|
"Stop a gateway instance"}
|
||||||
, {"gateway start <GatewayType>",
|
, {"gateway start <Name>",
|
||||||
"Start a gateway instance"}
|
"Start a gateway instance"}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
'gateway-registry'(["list"]) ->
|
'gateway-registry'(["list"]) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({GwType, #{cbkmod := CbMod}}) ->
|
fun({Name, #{cbkmod := CbMod}}) ->
|
||||||
emqx_ctl:print("Registered Type: ~s, Callback Module: ~s~n", [GwType, CbMod])
|
emqx_ctl:print("Registered Name: ~s, Callback Module: ~s~n", [Name, CbMod])
|
||||||
end,
|
end,
|
||||||
emqx_gateway_registry:list());
|
emqx_gateway_registry:list());
|
||||||
|
|
||||||
'gateway-registry'(_) ->
|
'gateway-registry'(_) ->
|
||||||
emqx_ctl:usage([ {"gateway-registry list",
|
emqx_ctl:usage([ {"gateway-registry list",
|
||||||
"List all registered gateway types"}
|
"List all registered gateways"}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
'gateway-clients'(["list", Type]) ->
|
'gateway-clients'(["list", Name]) ->
|
||||||
InfoTab = emqx_gateway_cm:tabname(info, Type),
|
InfoTab = emqx_gateway_cm:tabname(info, Name),
|
||||||
dump(InfoTab, client);
|
dump(InfoTab, client);
|
||||||
|
|
||||||
'gateway-clients'(["lookup", Type, ClientId]) ->
|
'gateway-clients'(["lookup", Name, ClientId]) ->
|
||||||
ChanTab = emqx_gateway_cm:tabname(chan, Type),
|
ChanTab = emqx_gateway_cm:tabname(chan, Name),
|
||||||
case ets:lookup(ChanTab, bin(ClientId)) of
|
case ets:lookup(ChanTab, bin(ClientId)) of
|
||||||
[] -> emqx_ctl:print("Not Found.~n");
|
[] -> emqx_ctl:print("Not Found.~n");
|
||||||
[Chann] ->
|
[Chann] ->
|
||||||
InfoTab = emqx_gateway_cm:tabname(info, Type),
|
InfoTab = emqx_gateway_cm:tabname(info, Name),
|
||||||
[ChannInfo] = ets:lookup(InfoTab, Chann),
|
[ChannInfo] = ets:lookup(InfoTab, Chann),
|
||||||
print({client, ChannInfo})
|
print({client, ChannInfo})
|
||||||
end;
|
end;
|
||||||
|
|
||||||
'gateway-clients'(["kick", Type, ClientId]) ->
|
'gateway-clients'(["kick", Name, ClientId]) ->
|
||||||
case emqx_gateway_cm:kick_session(Type, bin(ClientId)) of
|
case emqx_gateway_cm:kick_session(Name, bin(ClientId)) of
|
||||||
ok -> emqx_ctl:print("ok~n");
|
ok -> emqx_ctl:print("ok~n");
|
||||||
_ -> emqx_ctl:print("Not Found.~n")
|
_ -> emqx_ctl:print("Not Found.~n")
|
||||||
end;
|
end;
|
||||||
|
|
||||||
'gateway-clients'(_) ->
|
'gateway-clients'(_) ->
|
||||||
emqx_ctl:usage([ {"gateway-clients list <Type>",
|
emqx_ctl:usage([ {"gateway-clients list <Name>",
|
||||||
"List all clients for a type of gateway"}
|
"List all clients for a gateway"}
|
||||||
, {"gateway-clients lookup <Type> <ClientId>",
|
, {"gateway-clients lookup <Name> <ClientId>",
|
||||||
"Lookup the Client Info for specified client"}
|
"Lookup the Client Info for specified client"}
|
||||||
, {"gateway-clients kick <Type> <ClientId>",
|
, {"gateway-clients kick <Name> <ClientId>",
|
||||||
"Kick out a client"}
|
"Kick out a client"}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
'gateway-metrics'([GatewayType]) ->
|
'gateway-metrics'([Name]) ->
|
||||||
Tab = emqx_gateway_metrics:tabname(GatewayType),
|
Tab = emqx_gateway_metrics:tabname(Name),
|
||||||
case ets:info(Tab) of
|
case ets:info(Tab) of
|
||||||
undefined ->
|
undefined ->
|
||||||
emqx_ctl:print("Bad Gateway Type.~n");
|
emqx_ctl:print("Bad Gateway Name.~n");
|
||||||
_ ->
|
_ ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({K, V}) ->
|
fun({K, V}) ->
|
||||||
|
@ -146,7 +147,7 @@ gateway(_) ->
|
||||||
end;
|
end;
|
||||||
|
|
||||||
'gateway-metrics'(_) ->
|
'gateway-metrics'(_) ->
|
||||||
emqx_ctl:usage([ {"gateway-metrics <GatewayType>",
|
emqx_ctl:usage([ {"gateway-metrics <Name>",
|
||||||
"List all metrics for a gateway"}
|
"List all metrics for a gateway"}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
|
@ -61,13 +61,13 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-record(state, {
|
-record(state, {
|
||||||
type :: atom(), %% Gateway Type
|
gwname :: gateway_name(), %% Gateway Name
|
||||||
locker :: pid(), %% ClientId Locker for CM
|
locker :: pid(), %% ClientId Locker for CM
|
||||||
registry :: pid(), %% ClientId Registry server
|
registry :: pid(), %% ClientId Registry server
|
||||||
chan_pmon :: emqx_pmon:pmon()
|
chan_pmon :: emqx_pmon:pmon()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type option() :: {type, gateway_type()}.
|
-type option() :: {gwname, gateway_name()}.
|
||||||
-type options() :: list(option()).
|
-type options() :: list(option()).
|
||||||
|
|
||||||
-define(T_TAKEOVER, 15000).
|
-define(T_TAKEOVER, 15000).
|
||||||
|
@ -79,142 +79,147 @@
|
||||||
|
|
||||||
-spec start_link(options()) -> {ok, pid()} | ignore | {error, any()}.
|
-spec start_link(options()) -> {ok, pid()} | ignore | {error, any()}.
|
||||||
start_link(Options) ->
|
start_link(Options) ->
|
||||||
Type = proplists:get_value(type, Options),
|
GwName = proplists:get_value(gwname, Options),
|
||||||
gen_server:start_link({local, procname(Type)}, ?MODULE, Options, []).
|
gen_server:start_link({local, procname(GwName)}, ?MODULE, Options, []).
|
||||||
|
|
||||||
procname(Type) ->
|
procname(GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_cm'])).
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_cm'])).
|
||||||
|
|
||||||
-spec cmtabs(Type :: atom()) -> {ChanTab :: atom(),
|
-spec cmtabs(GwName :: gateway_name())
|
||||||
ConnTab :: atom(),
|
-> {ChanTab :: atom(),
|
||||||
ChannInfoTab :: atom()}.
|
ConnTab :: atom(),
|
||||||
cmtabs(Type) ->
|
ChannInfoTab :: atom()}.
|
||||||
{ tabname(chan, Type) %% Client Tabname; Record: {ClientId, Pid}
|
cmtabs(GwName) ->
|
||||||
, tabname(conn, Type) %% Client ConnMod; Recrod: {{ClientId, Pid}, ConnMod}
|
{ tabname(chan, GwName) %% Client Tabname; Record: {ClientId, Pid}
|
||||||
, tabname(info, Type) %% ClientInfo Tabname; Record: {{ClientId, Pid}, ClientInfo, ClientStats}
|
, tabname(conn, GwName) %% Client ConnMod; Recrod: {{ClientId, Pid}, ConnMod}
|
||||||
|
, tabname(info, GwName) %% ClientInfo Tabname; Record: {{ClientId, Pid}, ClientInfo, ClientStats}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
tabname(chan, Type) ->
|
tabname(chan, GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_channel']));
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_channel']));
|
||||||
tabname(conn, Type) ->
|
tabname(conn, GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_channel_conn']));
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_channel_conn']));
|
||||||
tabname(info, Type) ->
|
tabname(info, GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_channel_info'])).
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_channel_info'])).
|
||||||
|
|
||||||
lockername(Type) ->
|
lockername(GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_locker'])).
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_locker'])).
|
||||||
|
|
||||||
-spec register_channel(atom(), binary(), pid(), emqx_types:conninfo()) -> ok.
|
-spec register_channel(gateway_name(),
|
||||||
register_channel(Type, ClientId, ChanPid, #{conn_mod := ConnMod}) when is_pid(ChanPid) ->
|
emqx_types:clientid(),
|
||||||
|
pid(),
|
||||||
|
emqx_types:conninfo()) -> ok.
|
||||||
|
register_channel(GwName, ClientId, ChanPid, #{conn_mod := ConnMod}) when is_pid(ChanPid) ->
|
||||||
Chan = {ClientId, ChanPid},
|
Chan = {ClientId, ChanPid},
|
||||||
true = ets:insert(tabname(chan, Type), Chan),
|
true = ets:insert(tabname(chan, GwName), Chan),
|
||||||
true = ets:insert(tabname(conn, Type), {Chan, ConnMod}),
|
true = ets:insert(tabname(conn, GwName), {Chan, ConnMod}),
|
||||||
ok = emqx_gateway_cm_registry:register_channel(Type, Chan),
|
ok = emqx_gateway_cm_registry:register_channel(GwName, Chan),
|
||||||
cast(procname(Type), {registered, Chan}).
|
cast(procname(GwName), {registered, Chan}).
|
||||||
|
|
||||||
%% @doc Unregister a channel.
|
%% @doc Unregister a channel.
|
||||||
-spec unregister_channel(atom(), emqx_types:clientid()) -> ok.
|
-spec unregister_channel(gateway_name(), emqx_types:clientid()) -> ok.
|
||||||
unregister_channel(Type, ClientId) when is_binary(ClientId) ->
|
unregister_channel(GwName, ClientId) when is_binary(ClientId) ->
|
||||||
true = do_unregister_channel(Type, {ClientId, self()}, cmtabs(Type)),
|
true = do_unregister_channel(GwName, {ClientId, self()}, cmtabs(GwName)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%% @doc Insert/Update the channel info and stats
|
%% @doc Insert/Update the channel info and stats
|
||||||
-spec insert_channel_info(atom(),
|
-spec insert_channel_info(gateway_name(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:infos(),
|
emqx_types:infos(),
|
||||||
emqx_types:stats()) -> ok.
|
emqx_types:stats()) -> ok.
|
||||||
insert_channel_info(Type, ClientId, Info, Stats) ->
|
insert_channel_info(GwName, ClientId, Info, Stats) ->
|
||||||
Chan = {ClientId, self()},
|
Chan = {ClientId, self()},
|
||||||
true = ets:insert(tabname(info, Type), {Chan, Info, Stats}),
|
true = ets:insert(tabname(info, GwName), {Chan, Info, Stats}),
|
||||||
%%?tp(debug, insert_channel_info, #{client_id => ClientId}),
|
%%?tp(debug, insert_channel_info, #{client_id => ClientId}),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%% @doc Get info of a channel.
|
%% @doc Get info of a channel.
|
||||||
-spec get_chan_info(gateway_type(), emqx_types:clientid())
|
-spec get_chan_info(gateway_name(), emqx_types:clientid())
|
||||||
-> emqx_types:infos() | undefined.
|
-> emqx_types:infos() | undefined.
|
||||||
get_chan_info(Type, ClientId) ->
|
get_chan_info(GwName, ClientId) ->
|
||||||
with_channel(Type, ClientId,
|
with_channel(GwName, ClientId,
|
||||||
fun(ChanPid) ->
|
fun(ChanPid) ->
|
||||||
get_chan_info(Type, ClientId, ChanPid)
|
get_chan_info(GwName, ClientId, ChanPid)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
-spec get_chan_info(gateway_type(), emqx_types:clientid(), pid())
|
-spec get_chan_info(gateway_name(), emqx_types:clientid(), pid())
|
||||||
-> emqx_types:infos() | undefined.
|
-> emqx_types:infos() | undefined.
|
||||||
get_chan_info(Type, ClientId, ChanPid) when node(ChanPid) == node() ->
|
get_chan_info(GwName, ClientId, ChanPid) when node(ChanPid) == node() ->
|
||||||
Chan = {ClientId, ChanPid},
|
Chan = {ClientId, ChanPid},
|
||||||
try ets:lookup_element(tabname(info, Type), Chan, 2)
|
try ets:lookup_element(tabname(info, GwName), Chan, 2)
|
||||||
catch
|
catch
|
||||||
error:badarg -> undefined
|
error:badarg -> undefined
|
||||||
end;
|
end;
|
||||||
get_chan_info(Type, ClientId, ChanPid) ->
|
get_chan_info(GwName, ClientId, ChanPid) ->
|
||||||
rpc_call(node(ChanPid), get_chan_info, [Type, ClientId, ChanPid]).
|
rpc_call(node(ChanPid), get_chan_info, [GwName, ClientId, ChanPid]).
|
||||||
|
|
||||||
%% @doc Update infos of the channel.
|
%% @doc Update infos of the channel.
|
||||||
-spec set_chan_info(gateway_type(),
|
-spec set_chan_info(gateway_name(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:infos()) -> boolean().
|
emqx_types:infos()) -> boolean().
|
||||||
set_chan_info(Type, ClientId, Infos) ->
|
set_chan_info(GwName, ClientId, Infos) ->
|
||||||
set_chan_info(Type, ClientId, self(), Infos).
|
set_chan_info(GwName, ClientId, self(), Infos).
|
||||||
|
|
||||||
-spec set_chan_info(gateway_type(),
|
-spec set_chan_info(gateway_name(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
pid(),
|
pid(),
|
||||||
emqx_types:infos()) -> boolean().
|
emqx_types:infos()) -> boolean().
|
||||||
set_chan_info(Type, ClientId, ChanPid, Infos) when node(ChanPid) == node() ->
|
set_chan_info(GwName, ClientId, ChanPid, Infos) when node(ChanPid) == node() ->
|
||||||
Chan = {ClientId, ChanPid},
|
Chan = {ClientId, ChanPid},
|
||||||
try ets:update_element(tabname(info, Type), Chan, {2, Infos})
|
try ets:update_element(tabname(info, GwName), Chan, {2, Infos})
|
||||||
catch
|
catch
|
||||||
error:badarg -> false
|
error:badarg -> false
|
||||||
end;
|
end;
|
||||||
set_chan_info(Type, ClientId, ChanPid, Infos) ->
|
set_chan_info(GwName, ClientId, ChanPid, Infos) ->
|
||||||
rpc_call(node(ChanPid), set_chan_info, [Type, ClientId, ChanPid, Infos]).
|
rpc_call(node(ChanPid), set_chan_info, [GwName, ClientId, ChanPid, Infos]).
|
||||||
|
|
||||||
%% @doc Get channel's stats.
|
%% @doc Get channel's stats.
|
||||||
-spec get_chan_stats(gateway_type(), emqx_types:clientid())
|
-spec get_chan_stats(gateway_name(), emqx_types:clientid())
|
||||||
-> emqx_types:stats() | undefined.
|
-> emqx_types:stats() | undefined.
|
||||||
get_chan_stats(Type, ClientId) ->
|
get_chan_stats(GwName, ClientId) ->
|
||||||
with_channel(Type, ClientId,
|
with_channel(GwName, ClientId,
|
||||||
fun(ChanPid) ->
|
fun(ChanPid) ->
|
||||||
get_chan_stats(Type, ClientId, ChanPid)
|
get_chan_stats(GwName, ClientId, ChanPid)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
-spec get_chan_stats(gateway_type(), emqx_types:clientid(), pid())
|
-spec get_chan_stats(gateway_name(), emqx_types:clientid(), pid())
|
||||||
-> emqx_types:stats() | undefined.
|
-> emqx_types:stats() | undefined.
|
||||||
get_chan_stats(Type, ClientId, ChanPid) when node(ChanPid) == node() ->
|
get_chan_stats(GwName, ClientId, ChanPid) when node(ChanPid) == node() ->
|
||||||
Chan = {ClientId, ChanPid},
|
Chan = {ClientId, ChanPid},
|
||||||
try ets:lookup_element(tabname(info, Type), Chan, 3)
|
try ets:lookup_element(tabname(info, GwName), Chan, 3)
|
||||||
catch
|
catch
|
||||||
error:badarg -> undefined
|
error:badarg -> undefined
|
||||||
end;
|
end;
|
||||||
get_chan_stats(Type, ClientId, ChanPid) ->
|
get_chan_stats(GwName, ClientId, ChanPid) ->
|
||||||
rpc_call(node(ChanPid), get_chan_stats, [Type, ClientId, ChanPid]).
|
rpc_call(node(ChanPid), get_chan_stats, [GwName, ClientId, ChanPid]).
|
||||||
|
|
||||||
-spec set_chan_stats(gateway_type(),
|
-spec set_chan_stats(gateway_name(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:stats()) -> boolean().
|
emqx_types:stats()) -> boolean().
|
||||||
set_chan_stats(Type, ClientId, Stats) ->
|
set_chan_stats(GwName, ClientId, Stats) ->
|
||||||
set_chan_stats(Type, ClientId, self(), Stats).
|
set_chan_stats(GwName, ClientId, self(), Stats).
|
||||||
|
|
||||||
-spec set_chan_stats(gateway_type(),
|
-spec set_chan_stats(gateway_name(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
pid(),
|
pid(),
|
||||||
emqx_types:stats()) -> boolean().
|
emqx_types:stats()) -> boolean().
|
||||||
set_chan_stats(Type, ClientId, ChanPid, Stats) when node(ChanPid) == node() ->
|
set_chan_stats(GwName, ClientId, ChanPid, Stats) when node(ChanPid) == node() ->
|
||||||
Chan = {ClientId, self()},
|
Chan = {ClientId, self()},
|
||||||
try ets:update_element(tabname(info, Type), Chan, {3, Stats})
|
try ets:update_element(tabname(info, GwName), Chan, {3, Stats})
|
||||||
catch
|
catch
|
||||||
error:badarg -> false
|
error:badarg -> false
|
||||||
end;
|
end;
|
||||||
set_chan_stats(Type, ClientId, ChanPid, Stats) ->
|
set_chan_stats(GwName, ClientId, ChanPid, Stats) ->
|
||||||
rpc_call(node(ChanPid), set_chan_stats, [Type, ClientId, ChanPid, Stats]).
|
rpc_call(node(ChanPid), set_chan_stats, [GwName, ClientId, ChanPid, Stats]).
|
||||||
|
|
||||||
-spec connection_closed(gateway_type(), emqx_types:clientid()) -> true.
|
-spec connection_closed(gateway_name(), emqx_types:clientid()) -> true.
|
||||||
connection_closed(Type, ClientId) ->
|
connection_closed(GwName, ClientId) ->
|
||||||
%% XXX: Why we need to delete conn_mod tab ???
|
%% XXX: Why we need to delete conn_mod tab ???
|
||||||
Chan = {ClientId, self()},
|
Chan = {ClientId, self()},
|
||||||
ets:delete_object(tabname(conn, Type), Chan).
|
ets:delete_object(tabname(conn, GwName), Chan).
|
||||||
|
|
||||||
-spec open_session(Type :: atom(), CleanStart :: boolean(),
|
-spec open_session(GwName :: gateway_name(),
|
||||||
|
CleanStart :: boolean(),
|
||||||
ClientInfo :: emqx_types:clientinfo(),
|
ClientInfo :: emqx_types:clientinfo(),
|
||||||
ConnInfo :: emqx_types:conninfo(),
|
ConnInfo :: emqx_types:conninfo(),
|
||||||
CreateSessionFun :: fun((emqx_types:clientinfo(),
|
CreateSessionFun :: fun((emqx_types:clientinfo(),
|
||||||
|
@ -226,24 +231,24 @@ connection_closed(Type, ClientId) ->
|
||||||
}}
|
}}
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
|
|
||||||
open_session(Type, CleanStart, ClientInfo, ConnInfo, CreateSessionFun) ->
|
open_session(GwName, CleanStart, ClientInfo, ConnInfo, CreateSessionFun) ->
|
||||||
open_session(Type, CleanStart, ClientInfo, ConnInfo, CreateSessionFun, emqx_session).
|
open_session(GwName, CleanStart, ClientInfo, ConnInfo, CreateSessionFun, emqx_session).
|
||||||
|
|
||||||
open_session(Type, true = _CleanStart, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
open_session(GwName, true = _CleanStart, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
||||||
Self = self(),
|
Self = self(),
|
||||||
ClientId = maps:get(clientid, ClientInfo),
|
ClientId = maps:get(clientid, ClientInfo),
|
||||||
Fun = fun(_) ->
|
Fun = fun(_) ->
|
||||||
ok = discard_session(Type, ClientId),
|
ok = discard_session(GwName, ClientId),
|
||||||
Session = create_session(Type,
|
Session = create_session(GwName,
|
||||||
ClientInfo,
|
ClientInfo,
|
||||||
ConnInfo,
|
ConnInfo,
|
||||||
CreateSessionFun,
|
CreateSessionFun,
|
||||||
SessionMod
|
SessionMod
|
||||||
),
|
),
|
||||||
register_channel(Type, ClientId, Self, ConnInfo),
|
register_channel(GwName, ClientId, Self, ConnInfo),
|
||||||
{ok, #{session => Session, present => false}}
|
{ok, #{session => Session, present => false}}
|
||||||
end,
|
end,
|
||||||
locker_trans(Type, ClientId, Fun);
|
locker_trans(GwName, ClientId, Fun);
|
||||||
|
|
||||||
open_session(_Type, false = _CleanStart,
|
open_session(_Type, false = _CleanStart,
|
||||||
_ClientInfo, _ConnInfo, _CreateSessionFun, _SessionMod) ->
|
_ClientInfo, _ConnInfo, _CreateSessionFun, _SessionMod) ->
|
||||||
|
@ -251,13 +256,13 @@ open_session(_Type, false = _CleanStart,
|
||||||
{error, not_supported_now}.
|
{error, not_supported_now}.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
create_session(Type, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
create_session(GwName, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
||||||
try
|
try
|
||||||
Session = emqx_gateway_utils:apply(
|
Session = emqx_gateway_utils:apply(
|
||||||
CreateSessionFun,
|
CreateSessionFun,
|
||||||
[ClientInfo, ConnInfo]
|
[ClientInfo, ConnInfo]
|
||||||
),
|
),
|
||||||
ok = emqx_gateway_metrics:inc(Type, 'session.created'),
|
ok = emqx_gateway_metrics:inc(GwName, 'session.created'),
|
||||||
SessionInfo = case is_tuple(Session)
|
SessionInfo = case is_tuple(Session)
|
||||||
andalso element(1, Session) == session of
|
andalso element(1, Session) == session of
|
||||||
true -> SessionMod:info(Session);
|
true -> SessionMod:info(Session);
|
||||||
|
@ -279,17 +284,17 @@ create_session(Type, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc Discard all the sessions identified by the ClientId.
|
%% @doc Discard all the sessions identified by the ClientId.
|
||||||
-spec discard_session(Type :: atom(), binary()) -> ok.
|
-spec discard_session(GwName :: gateway_name(), binary()) -> ok.
|
||||||
discard_session(Type, ClientId) when is_binary(ClientId) ->
|
discard_session(GwName, ClientId) when is_binary(ClientId) ->
|
||||||
case lookup_channels(Type, ClientId) of
|
case lookup_channels(GwName, ClientId) of
|
||||||
[] -> ok;
|
[] -> ok;
|
||||||
ChanPids -> lists:foreach(fun(Pid) -> do_discard_session(Type, ClientId, Pid) end, ChanPids)
|
ChanPids -> lists:foreach(fun(Pid) -> do_discard_session(GwName, ClientId, Pid) end, ChanPids)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
do_discard_session(Type, ClientId, Pid) ->
|
do_discard_session(GwName, ClientId, Pid) ->
|
||||||
try
|
try
|
||||||
discard_session(Type, ClientId, Pid)
|
discard_session(GwName, ClientId, Pid)
|
||||||
catch
|
catch
|
||||||
_ : noproc -> % emqx_ws_connection: call
|
_ : noproc -> % emqx_ws_connection: call
|
||||||
%?tp(debug, "session_already_gone", #{pid => Pid}),
|
%?tp(debug, "session_already_gone", #{pid => Pid}),
|
||||||
|
@ -307,72 +312,72 @@ do_discard_session(Type, ClientId, Pid) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
discard_session(Type, ClientId, ChanPid) when node(ChanPid) == node() ->
|
discard_session(GwName, ClientId, ChanPid) when node(ChanPid) == node() ->
|
||||||
case get_chann_conn_mod(Type, ClientId, ChanPid) of
|
case get_chann_conn_mod(GwName, ClientId, ChanPid) of
|
||||||
undefined -> ok;
|
undefined -> ok;
|
||||||
ConnMod when is_atom(ConnMod) ->
|
ConnMod when is_atom(ConnMod) ->
|
||||||
ConnMod:call(ChanPid, discard, ?T_TAKEOVER)
|
ConnMod:call(ChanPid, discard, ?T_TAKEOVER)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
discard_session(Type, ClientId, ChanPid) ->
|
discard_session(GwName, ClientId, ChanPid) ->
|
||||||
rpc_call(node(ChanPid), discard_session, [Type, ClientId, ChanPid]).
|
rpc_call(node(ChanPid), discard_session, [GwName, ClientId, ChanPid]).
|
||||||
|
|
||||||
-spec kick_session(gateway_type(), emqx_types:clientid())
|
-spec kick_session(gateway_name(), emqx_types:clientid())
|
||||||
-> {error, any()}
|
-> {error, any()}
|
||||||
| ok.
|
| ok.
|
||||||
kick_session(Type, ClientId) ->
|
kick_session(GwName, ClientId) ->
|
||||||
case lookup_channels(Type, ClientId) of
|
case lookup_channels(GwName, ClientId) of
|
||||||
[] -> {error, not_found};
|
[] -> {error, not_found};
|
||||||
[ChanPid] ->
|
[ChanPid] ->
|
||||||
kick_session(Type, ClientId, ChanPid);
|
kick_session(GwName, ClientId, ChanPid);
|
||||||
ChanPids ->
|
ChanPids ->
|
||||||
[ChanPid|StalePids] = lists:reverse(ChanPids),
|
[ChanPid|StalePids] = lists:reverse(ChanPids),
|
||||||
?LOG(error, "More than one channel found: ~p", [ChanPids]),
|
?LOG(error, "More than one channel found: ~p", [ChanPids]),
|
||||||
lists:foreach(fun(StalePid) ->
|
lists:foreach(fun(StalePid) ->
|
||||||
catch discard_session(Type, ClientId, StalePid)
|
catch discard_session(GwName, ClientId, StalePid)
|
||||||
end, StalePids),
|
end, StalePids),
|
||||||
kick_session(Type, ClientId, ChanPid)
|
kick_session(GwName, ClientId, ChanPid)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
kick_session(Type, ClientId, ChanPid) when node(ChanPid) == node() ->
|
kick_session(GwName, ClientId, ChanPid) when node(ChanPid) == node() ->
|
||||||
case get_chan_info(Type, ClientId, ChanPid) of
|
case get_chan_info(GwName, ClientId, ChanPid) of
|
||||||
#{conninfo := #{conn_mod := ConnMod}} ->
|
#{conninfo := #{conn_mod := ConnMod}} ->
|
||||||
ConnMod:call(ChanPid, kick, ?T_TAKEOVER);
|
ConnMod:call(ChanPid, kick, ?T_TAKEOVER);
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, not_found}
|
{error, not_found}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
kick_session(Type, ClientId, ChanPid) ->
|
kick_session(GwName, ClientId, ChanPid) ->
|
||||||
rpc_call(node(ChanPid), kick_session, [Type, ClientId, ChanPid]).
|
rpc_call(node(ChanPid), kick_session, [GwName, ClientId, ChanPid]).
|
||||||
|
|
||||||
with_channel(Type, ClientId, Fun) ->
|
with_channel(GwName, ClientId, Fun) ->
|
||||||
case lookup_channels(Type, ClientId) of
|
case lookup_channels(GwName, ClientId) of
|
||||||
[] -> undefined;
|
[] -> undefined;
|
||||||
[Pid] -> Fun(Pid);
|
[Pid] -> Fun(Pid);
|
||||||
Pids -> Fun(lists:last(Pids))
|
Pids -> Fun(lists:last(Pids))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc Lookup channels.
|
%% @doc Lookup channels.
|
||||||
-spec(lookup_channels(atom(), emqx_types:clientid()) -> list(pid())).
|
-spec(lookup_channels(gateway_name(), emqx_types:clientid()) -> list(pid())).
|
||||||
lookup_channels(Type, ClientId) ->
|
lookup_channels(GwName, ClientId) ->
|
||||||
emqx_gateway_cm_registry:lookup_channels(Type, ClientId).
|
emqx_gateway_cm_registry:lookup_channels(GwName, ClientId).
|
||||||
|
|
||||||
get_chann_conn_mod(Type, ClientId, ChanPid) when node(ChanPid) == node() ->
|
get_chann_conn_mod(GwName, ClientId, ChanPid) when node(ChanPid) == node() ->
|
||||||
Chan = {ClientId, ChanPid},
|
Chan = {ClientId, ChanPid},
|
||||||
try [ConnMod] = ets:lookup_element(tabname(conn, Type), Chan, 2), ConnMod
|
try [ConnMod] = ets:lookup_element(tabname(conn, GwName), Chan, 2), ConnMod
|
||||||
catch
|
catch
|
||||||
error:badarg -> undefined
|
error:badarg -> undefined
|
||||||
end;
|
end;
|
||||||
get_chann_conn_mod(Type, ClientId, ChanPid) ->
|
get_chann_conn_mod(GwName, ClientId, ChanPid) ->
|
||||||
rpc_call(node(ChanPid), get_chann_conn_mod, [Type, ClientId, ChanPid]).
|
rpc_call(node(ChanPid), get_chann_conn_mod, [GwName, ClientId, ChanPid]).
|
||||||
|
|
||||||
%% Locker
|
%% Locker
|
||||||
|
|
||||||
locker_trans(_Type, undefined, Fun) ->
|
locker_trans(_Type, undefined, Fun) ->
|
||||||
Fun([]);
|
Fun([]);
|
||||||
locker_trans(Type, ClientId, Fun) ->
|
locker_trans(GwName, ClientId, Fun) ->
|
||||||
Locker = lockername(Type),
|
Locker = lockername(GwName),
|
||||||
case locker_lock(Locker, ClientId) of
|
case locker_lock(Locker, ClientId) of
|
||||||
{true, Nodes} ->
|
{true, Nodes} ->
|
||||||
try Fun(Nodes) after locker_unlock(Locker, ClientId) end;
|
try Fun(Nodes) after locker_unlock(Locker, ClientId) end;
|
||||||
|
@ -401,27 +406,27 @@ cast(Name, Msg) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
init(Options) ->
|
init(Options) ->
|
||||||
Type = proplists:get_value(type, Options),
|
GwName = proplists:get_value(gwname, Options),
|
||||||
|
|
||||||
TabOpts = [public, {write_concurrency, true}],
|
TabOpts = [public, {write_concurrency, true}],
|
||||||
|
|
||||||
{ChanTab, ConnTab, InfoTab} = cmtabs(Type),
|
{ChanTab, ConnTab, InfoTab} = cmtabs(GwName),
|
||||||
ok = emqx_tables:new(ChanTab, [bag, {read_concurrency, true}|TabOpts]),
|
ok = emqx_tables:new(ChanTab, [bag, {read_concurrency, true}|TabOpts]),
|
||||||
ok = emqx_tables:new(ConnTab, [bag | TabOpts]),
|
ok = emqx_tables:new(ConnTab, [bag | TabOpts]),
|
||||||
ok = emqx_tables:new(InfoTab, [set, compressed | TabOpts]),
|
ok = emqx_tables:new(InfoTab, [set, compressed | TabOpts]),
|
||||||
|
|
||||||
%% Start link cm-registry process
|
%% Start link cm-registry process
|
||||||
%% XXX: Should I hang it under a higher level supervisor?
|
%% XXX: Should I hang it under a higher level supervisor?
|
||||||
{ok, Registry} = emqx_gateway_cm_registry:start_link(Type),
|
{ok, Registry} = emqx_gateway_cm_registry:start_link(GwName),
|
||||||
|
|
||||||
%% Start locker process
|
%% Start locker process
|
||||||
{ok, Locker} = ekka_locker:start_link(lockername(Type)),
|
{ok, Locker} = ekka_locker:start_link(lockername(GwName)),
|
||||||
|
|
||||||
%% Interval update stats
|
%% Interval update stats
|
||||||
%% TODO: v0.2
|
%% TODO: v0.2
|
||||||
%ok = emqx_stats:update_interval(chan_stats, fun ?MODULE:stats_fun/0),
|
%ok = emqx_stats:update_interval(chan_stats, fun ?MODULE:stats_fun/0),
|
||||||
|
|
||||||
{ok, #state{type = Type,
|
{ok, #state{gwname = GwName,
|
||||||
locker = Locker,
|
locker = Locker,
|
||||||
registry = Registry,
|
registry = Registry,
|
||||||
chan_pmon = emqx_pmon:new()}}.
|
chan_pmon = emqx_pmon:new()}}.
|
||||||
|
@ -438,12 +443,12 @@ handle_cast(_Msg, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
handle_info({'DOWN', _MRef, process, Pid, _Reason},
|
handle_info({'DOWN', _MRef, process, Pid, _Reason},
|
||||||
State = #state{type = Type, chan_pmon = PMon}) ->
|
State = #state{gwname = GwName, chan_pmon = PMon}) ->
|
||||||
ChanPids = [Pid | emqx_misc:drain_down(?DEFAULT_BATCH_SIZE)],
|
ChanPids = [Pid | emqx_misc:drain_down(?DEFAULT_BATCH_SIZE)],
|
||||||
{Items, PMon1} = emqx_pmon:erase_all(ChanPids, PMon),
|
{Items, PMon1} = emqx_pmon:erase_all(ChanPids, PMon),
|
||||||
|
|
||||||
CmTabs = cmtabs(Type),
|
CmTabs = cmtabs(GwName),
|
||||||
ok = emqx_pool:async_submit(fun do_unregister_channel_task/3, [Items, Type, CmTabs]),
|
ok = emqx_pool:async_submit(fun do_unregister_channel_task/3, [Items, GwName, CmTabs]),
|
||||||
{noreply, State#state{chan_pmon = PMon1}};
|
{noreply, State#state{chan_pmon = PMon1}};
|
||||||
|
|
||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
|
@ -455,18 +460,18 @@ terminate(_Reason, _State) ->
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
do_unregister_channel_task(Items, Type, CmTabs) ->
|
do_unregister_channel_task(Items, GwName, CmTabs) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({ChanPid, ClientId}) ->
|
fun({ChanPid, ClientId}) ->
|
||||||
do_unregister_channel(Type, {ClientId, ChanPid}, CmTabs)
|
do_unregister_channel(GwName, {ClientId, ChanPid}, CmTabs)
|
||||||
end, Items).
|
end, Items).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
do_unregister_channel(Type, Chan, {ChanTab, ConnTab, InfoTab}) ->
|
do_unregister_channel(GwName, Chan, {ChanTab, ConnTab, InfoTab}) ->
|
||||||
ok = emqx_gateway_cm_registry:unregister_channel(Type, Chan),
|
ok = emqx_gateway_cm_registry:unregister_channel(GwName, Chan),
|
||||||
true = ets:delete(ConnTab, Chan),
|
true = ets:delete(ConnTab, Chan),
|
||||||
true = ets:delete(InfoTab, Chan),
|
true = ets:delete(InfoTab, Chan),
|
||||||
ets:delete_object(ChanTab, Chan).
|
ets:delete_object(ChanTab, Chan).
|
||||||
|
|
|
@ -27,10 +27,8 @@
|
||||||
%% configuration, register devices and other common operations.
|
%% configuration, register devices and other common operations.
|
||||||
%%
|
%%
|
||||||
-type context() ::
|
-type context() ::
|
||||||
#{ %% Gateway Instance ID
|
#{ %% Gateway Name
|
||||||
instid := instance_id()
|
gwname := gateway_name()
|
||||||
%% Gateway ID
|
|
||||||
, type := gateway_type()
|
|
||||||
%% Autenticator
|
%% Autenticator
|
||||||
, auth := emqx_authn:chain_id() | undefined
|
, auth := emqx_authn:chain_id() | undefined
|
||||||
%% The ConnectionManager PID
|
%% The ConnectionManager PID
|
||||||
|
@ -98,41 +96,43 @@ authenticate(_Ctx, ClientInfo) ->
|
||||||
}}
|
}}
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
open_session(Ctx, CleanStart, ClientInfo, ConnInfo, CreateSessionFun) ->
|
open_session(Ctx, CleanStart, ClientInfo, ConnInfo, CreateSessionFun) ->
|
||||||
open_session(Ctx, CleanStart, ClientInfo, ConnInfo, CreateSessionFun, emqx_session).
|
open_session(Ctx, CleanStart, ClientInfo, ConnInfo,
|
||||||
|
CreateSessionFun, emqx_session).
|
||||||
|
|
||||||
open_session(Ctx, false, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
open_session(Ctx, false, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
||||||
logger:warning("clean_start=false is not supported now, "
|
logger:warning("clean_start=false is not supported now, "
|
||||||
"fallback to clean_start mode"),
|
"fallback to clean_start mode"),
|
||||||
open_session(Ctx, true, ClientInfo, ConnInfo, CreateSessionFun, SessionMod);
|
open_session(Ctx, true, ClientInfo, ConnInfo, CreateSessionFun, SessionMod);
|
||||||
|
|
||||||
open_session(_Ctx = #{type := Type},
|
open_session(_Ctx = #{gwname := GwName},
|
||||||
CleanStart, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
CleanStart, ClientInfo, ConnInfo, CreateSessionFun, SessionMod) ->
|
||||||
emqx_gateway_cm:open_session(Type, CleanStart,
|
emqx_gateway_cm:open_session(GwName, CleanStart,
|
||||||
ClientInfo, ConnInfo, CreateSessionFun, SessionMod).
|
ClientInfo, ConnInfo,
|
||||||
|
CreateSessionFun, SessionMod).
|
||||||
|
|
||||||
-spec insert_channel_info(context(),
|
-spec insert_channel_info(context(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:infos(),
|
emqx_types:infos(),
|
||||||
emqx_types:stats()) -> ok.
|
emqx_types:stats()) -> ok.
|
||||||
insert_channel_info(_Ctx = #{type := Type}, ClientId, Infos, Stats) ->
|
insert_channel_info(_Ctx = #{gwname := GwName}, ClientId, Infos, Stats) ->
|
||||||
emqx_gateway_cm:insert_channel_info(Type, ClientId, Infos, Stats).
|
emqx_gateway_cm:insert_channel_info(GwName, ClientId, Infos, Stats).
|
||||||
|
|
||||||
%% @doc Set the Channel Info to the ConnectionManager for this client
|
%% @doc Set the Channel Info to the ConnectionManager for this client
|
||||||
-spec set_chan_info(context(),
|
-spec set_chan_info(context(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:infos()) -> boolean().
|
emqx_types:infos()) -> boolean().
|
||||||
set_chan_info(_Ctx = #{type := Type}, ClientId, Infos) ->
|
set_chan_info(_Ctx = #{gwname := GwName}, ClientId, Infos) ->
|
||||||
emqx_gateway_cm:set_chan_info(Type, ClientId, Infos).
|
emqx_gateway_cm:set_chan_info(GwName, ClientId, Infos).
|
||||||
|
|
||||||
-spec set_chan_stats(context(),
|
-spec set_chan_stats(context(),
|
||||||
emqx_types:clientid(),
|
emqx_types:clientid(),
|
||||||
emqx_types:stats()) -> boolean().
|
emqx_types:stats()) -> boolean().
|
||||||
set_chan_stats(_Ctx = #{type := Type}, ClientId, Stats) ->
|
set_chan_stats(_Ctx = #{gwname := GwName}, ClientId, Stats) ->
|
||||||
emqx_gateway_cm:set_chan_stats(Type, ClientId, Stats).
|
emqx_gateway_cm:set_chan_stats(GwName, ClientId, Stats).
|
||||||
|
|
||||||
-spec connection_closed(context(), emqx_types:clientid()) -> boolean().
|
-spec connection_closed(context(), emqx_types:clientid()) -> boolean().
|
||||||
connection_closed(_Ctx = #{type := Type}, ClientId) ->
|
connection_closed(_Ctx = #{gwname := GwName}, ClientId) ->
|
||||||
emqx_gateway_cm:connection_closed(Type, ClientId).
|
emqx_gateway_cm:connection_closed(GwName, ClientId).
|
||||||
|
|
||||||
-spec authorize(context(), emqx_types:clientinfo(),
|
-spec authorize(context(), emqx_types:clientinfo(),
|
||||||
emqx_types:pubsub(), emqx_types:topic())
|
emqx_types:pubsub(), emqx_types:topic())
|
||||||
|
@ -140,11 +140,11 @@ connection_closed(_Ctx = #{type := Type}, ClientId) ->
|
||||||
authorize(_Ctx, ClientInfo, PubSub, Topic) ->
|
authorize(_Ctx, ClientInfo, PubSub, Topic) ->
|
||||||
emqx_access_control:authorize(ClientInfo, PubSub, Topic).
|
emqx_access_control:authorize(ClientInfo, PubSub, Topic).
|
||||||
|
|
||||||
metrics_inc(_Ctx = #{type := Type}, Name) ->
|
metrics_inc(_Ctx = #{gwname := GwName}, Name) ->
|
||||||
emqx_gateway_metrics:inc(Type, Name).
|
emqx_gateway_metrics:inc(GwName, Name).
|
||||||
|
|
||||||
metrics_inc(_Ctx = #{type := Type}, Name, Oct) ->
|
metrics_inc(_Ctx = #{gwname := GwName}, Name, Oct) ->
|
||||||
emqx_gateway_metrics:inc(Type, Name, Oct).
|
emqx_gateway_metrics:inc(GwName, Name, Oct).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
|
|
|
@ -42,18 +42,18 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_link(Type) ->
|
start_link(GwName) ->
|
||||||
supervisor:start_link({local, Type}, ?MODULE, [Type]).
|
supervisor:start_link({local, GwName}, ?MODULE, [GwName]).
|
||||||
|
|
||||||
-spec create_insta(pid(), gateway(), map()) -> {ok, GwInstaPid :: pid()} | {error, any()}.
|
-spec create_insta(pid(), gateway(), map()) -> {ok, GwInstaPid :: pid()} | {error, any()}.
|
||||||
create_insta(Sup, Gateway = #{type := GwType}, GwDscrptr) ->
|
create_insta(Sup, Gateway = #{name := Name}, GwDscrptr) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
case emqx_gateway_utils:find_sup_child(Sup, Name) of
|
||||||
{ok, _GwInstaPid} -> {error, alredy_existed};
|
{ok, _GwInstaPid} -> {error, alredy_existed};
|
||||||
false ->
|
false ->
|
||||||
Ctx = ctx(Sup, GwType),
|
Ctx = ctx(Sup, Name),
|
||||||
%%
|
%%
|
||||||
ChildSpec = emqx_gateway_utils:childspec(
|
ChildSpec = emqx_gateway_utils:childspec(
|
||||||
GwType,
|
Name,
|
||||||
worker,
|
worker,
|
||||||
emqx_gateway_insta_sup,
|
emqx_gateway_insta_sup,
|
||||||
[Gateway, Ctx, GwDscrptr]
|
[Gateway, Ctx, GwDscrptr]
|
||||||
|
@ -63,34 +63,34 @@ create_insta(Sup, Gateway = #{type := GwType}, GwDscrptr) ->
|
||||||
)
|
)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec remove_insta(pid(), GwType :: gateway_type()) -> ok | {error, any()}.
|
-spec remove_insta(pid(), Name :: gateway_name()) -> ok | {error, any()}.
|
||||||
remove_insta(Sup, GwType) ->
|
remove_insta(Sup, Name) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
case emqx_gateway_utils:find_sup_child(Sup, Name) of
|
||||||
false -> ok;
|
false -> ok;
|
||||||
{ok, _GwInstaPid} ->
|
{ok, _GwInstaPid} ->
|
||||||
ok = supervisor:terminate_child(Sup, GwType),
|
ok = supervisor:terminate_child(Sup, Name),
|
||||||
ok = supervisor:delete_child(Sup, GwType)
|
ok = supervisor:delete_child(Sup, Name)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec update_insta(pid(), NewGateway :: gateway()) -> ok | {error, any()}.
|
-spec update_insta(pid(), NewGateway :: gateway()) -> ok | {error, any()}.
|
||||||
update_insta(Sup, NewGateway = #{type := GwType}) ->
|
update_insta(Sup, NewGateway = #{name := Name}) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
case emqx_gateway_utils:find_sup_child(Sup, Name) of
|
||||||
false -> {error, not_found};
|
false -> {error, not_found};
|
||||||
{ok, GwInstaPid} ->
|
{ok, GwInstaPid} ->
|
||||||
emqx_gateway_insta_sup:update(GwInstaPid, NewGateway)
|
emqx_gateway_insta_sup:update(GwInstaPid, NewGateway)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec start_insta(pid(), gateway_type()) -> ok | {error, any()}.
|
-spec start_insta(pid(), gateway_name()) -> ok | {error, any()}.
|
||||||
start_insta(Sup, GwType) ->
|
start_insta(Sup, Name) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
case emqx_gateway_utils:find_sup_child(Sup, Name) of
|
||||||
false -> {error, not_found};
|
false -> {error, not_found};
|
||||||
{ok, GwInstaPid} ->
|
{ok, GwInstaPid} ->
|
||||||
emqx_gateway_insta_sup:enable(GwInstaPid)
|
emqx_gateway_insta_sup:enable(GwInstaPid)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec stop_insta(pid(), gateway_type()) -> ok | {error, any()}.
|
-spec stop_insta(pid(), gateway_name()) -> ok | {error, any()}.
|
||||||
stop_insta(Sup, GwType) ->
|
stop_insta(Sup, Name) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
case emqx_gateway_utils:find_sup_child(Sup, Name) of
|
||||||
false -> {error, not_found};
|
false -> {error, not_found};
|
||||||
{ok, GwInstaPid} ->
|
{ok, GwInstaPid} ->
|
||||||
emqx_gateway_insta_sup:disable(GwInstaPid)
|
emqx_gateway_insta_sup:disable(GwInstaPid)
|
||||||
|
@ -99,33 +99,31 @@ stop_insta(Sup, GwType) ->
|
||||||
-spec list_insta(pid()) -> [gateway()].
|
-spec list_insta(pid()) -> [gateway()].
|
||||||
list_insta(Sup) ->
|
list_insta(Sup) ->
|
||||||
lists:filtermap(
|
lists:filtermap(
|
||||||
fun({GwType, GwInstaPid, _Type, _Mods}) ->
|
fun({Name, GwInstaPid, _Type, _Mods}) ->
|
||||||
is_gateway_insta_id(GwType)
|
is_gateway_insta_id(Name)
|
||||||
andalso {true, emqx_gateway_insta_sup:info(GwInstaPid)}
|
andalso {true, emqx_gateway_insta_sup:info(GwInstaPid)}
|
||||||
end, supervisor:which_children(Sup)).
|
end, supervisor:which_children(Sup)).
|
||||||
|
|
||||||
%% Supervisor callback
|
%% Supervisor callback
|
||||||
|
|
||||||
%% @doc Initialize Top Supervisor for a Protocol
|
%% @doc Initialize Top Supervisor for a Protocol
|
||||||
init([Type]) ->
|
init([GwName]) ->
|
||||||
SupFlags = #{ strategy => one_for_one
|
SupFlags = #{ strategy => one_for_one
|
||||||
, intensity => 10
|
, intensity => 10
|
||||||
, period => 60
|
, period => 60
|
||||||
},
|
},
|
||||||
CmOpts = [{type, Type}],
|
CmOpts = [{gwname, GwName}],
|
||||||
CM = emqx_gateway_utils:childspec(worker, emqx_gateway_cm, [CmOpts]),
|
CM = emqx_gateway_utils:childspec(worker, emqx_gateway_cm, [CmOpts]),
|
||||||
Metrics = emqx_gateway_utils:childspec(worker, emqx_gateway_metrics, [Type]),
|
Metrics = emqx_gateway_utils:childspec(worker, emqx_gateway_metrics, [GwName]),
|
||||||
{ok, {SupFlags, [CM, Metrics]}}.
|
{ok, {SupFlags, [CM, Metrics]}}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
ctx(Sup, GwType) ->
|
ctx(Sup, Name) ->
|
||||||
{_, Type} = erlang:process_info(Sup, registered_name),
|
|
||||||
{ok, CM} = emqx_gateway_utils:find_sup_child(Sup, emqx_gateway_cm),
|
{ok, CM} = emqx_gateway_utils:find_sup_child(Sup, emqx_gateway_cm),
|
||||||
#{ instid => GwType
|
#{ gwname => Name
|
||||||
, type => Type
|
|
||||||
, cm => CM
|
, cm => CM
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,8 @@ call(Pid, Req) ->
|
||||||
|
|
||||||
init([Gateway, Ctx0, _GwDscrptr]) ->
|
init([Gateway, Ctx0, _GwDscrptr]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
#{type := GwType, rawconf := RawConf} = Gateway,
|
#{name := GwName, rawconf := RawConf} = Gateway,
|
||||||
Ctx = do_init_context(GwType, RawConf, Ctx0),
|
Ctx = do_init_context(GwName, RawConf, Ctx0),
|
||||||
State = #state{
|
State = #state{
|
||||||
gw = Gateway,
|
gw = Gateway,
|
||||||
ctx = Ctx,
|
ctx = Ctx,
|
||||||
|
@ -102,11 +102,11 @@ init([Gateway, Ctx0, _GwDscrptr]) ->
|
||||||
{ok, NState}
|
{ok, NState}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_init_context(GwType, RawConf, Ctx) ->
|
do_init_context(GwName, RawConf, Ctx) ->
|
||||||
Auth = case maps:get(authentication, RawConf, #{enable => false}) of
|
Auth = case maps:get(authentication, RawConf, #{enable => false}) of
|
||||||
#{enable := true,
|
#{enable := true,
|
||||||
authenticators := AuthCfgs} when is_list(AuthCfgs) ->
|
authenticators := AuthCfgs} when is_list(AuthCfgs) ->
|
||||||
create_authenticators_for_gateway_insta(GwType, AuthCfgs);
|
create_authenticators_for_gateway_insta(GwName, AuthCfgs);
|
||||||
_ ->
|
_ ->
|
||||||
undefined
|
undefined
|
||||||
end,
|
end,
|
||||||
|
@ -116,8 +116,8 @@ do_deinit_context(Ctx) ->
|
||||||
cleanup_authenticators_for_gateway_insta(maps:get(auth, Ctx)),
|
cleanup_authenticators_for_gateway_insta(maps:get(auth, Ctx)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
handle_call(info, _From, State = #state{gw = Gateway}) ->
|
handle_call(info, _From, State = #state{gw = Gateway, status = Status}) ->
|
||||||
{reply, Gateway, State};
|
{reply, Gateway#{status => Status}, State};
|
||||||
|
|
||||||
handle_call(disable, _From, State = #state{status = Status}) ->
|
handle_call(disable, _From, State = #state{status = Status}) ->
|
||||||
case Status of
|
case Status of
|
||||||
|
@ -146,21 +146,22 @@ handle_call(enable, _From, State = #state{status = Status}) ->
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% Stopped -> update
|
%% Stopped -> update
|
||||||
handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
handle_call({update, NewGateway}, _From, State = #state{
|
||||||
status = stopped}) ->
|
gw = Gateway,
|
||||||
case maps:get(type, NewGateway, undefined)
|
status = stopped}) ->
|
||||||
== maps:get(type, Gateway, undefined) of
|
case maps:get(name, NewGateway, undefined)
|
||||||
|
== maps:get(name, Gateway, undefined) of
|
||||||
true ->
|
true ->
|
||||||
{reply, ok, State#state{gw = NewGateway}};
|
{reply, ok, State#state{gw = NewGateway}};
|
||||||
false ->
|
false ->
|
||||||
{reply, {error, gateway_type_not_match}, State}
|
{reply, {error, gateway_name_not_match}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% Running -> update
|
%% Running -> update
|
||||||
handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
||||||
status = running}) ->
|
status = running}) ->
|
||||||
case maps:get(type, NewGateway, undefined)
|
case maps:get(name, NewGateway, undefined)
|
||||||
== maps:get(type, Gateway, undefined) of
|
== maps:get(name, Gateway, undefined) of
|
||||||
true ->
|
true ->
|
||||||
case cb_gateway_update(NewGateway, State) of
|
case cb_gateway_update(NewGateway, State) of
|
||||||
{ok, NState} ->
|
{ok, NState} ->
|
||||||
|
@ -169,7 +170,7 @@ handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
||||||
{reply, {error, Reason}, State}
|
{reply, {error, Reason}, State}
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
{reply, {error, gateway_type_not_match}, State}
|
{reply, {error, gateway_name_not_match}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
|
@ -215,8 +216,8 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
|
|
||||||
%% @doc AuthCfgs is a array of authenticatior configurations,
|
%% @doc AuthCfgs is a array of authenticatior configurations,
|
||||||
%% see: emqx_authn_schema:authenticators/1
|
%% see: emqx_authn_schema:authenticators/1
|
||||||
create_authenticators_for_gateway_insta(GwType, AuthCfgs) ->
|
create_authenticators_for_gateway_insta(GwName, AuthCfgs) ->
|
||||||
ChainId = atom_to_binary(GwType, utf8),
|
ChainId = atom_to_binary(GwName, utf8),
|
||||||
case emqx_authn:create_chain(#{id => ChainId}) of
|
case emqx_authn:create_chain(#{id => ChainId}) of
|
||||||
{ok, _ChainInfo} ->
|
{ok, _ChainInfo} ->
|
||||||
Results = lists:map(fun(AuthCfg = #{name := Name}) ->
|
Results = lists:map(fun(AuthCfg = #{name := Name}) ->
|
||||||
|
@ -250,10 +251,10 @@ cleanup_authenticators_for_gateway_insta(ChainId) ->
|
||||||
"reason: ~p", [ChainId, Reason])
|
"reason: ~p", [ChainId, Reason])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_gateway_unload(State = #state{gw = Gateway = #{type := GwType},
|
cb_gateway_unload(State = #state{gw = Gateway = #{name := GwName},
|
||||||
gw_state = GwState}) ->
|
gw_state = GwState}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwName),
|
||||||
CbMod:on_gateway_unload(Gateway, GwState),
|
CbMod:on_gateway_unload(Gateway, GwState),
|
||||||
{ok, State#state{child_pids = [],
|
{ok, State#state{child_pids = [],
|
||||||
gw_state = undefined,
|
gw_state = undefined,
|
||||||
|
@ -267,10 +268,10 @@ cb_gateway_unload(State = #state{gw = Gateway = #{type := GwType},
|
||||||
{error, {Class, Reason, Stk}}
|
{error, {Class, Reason, Stk}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_gateway_load(State = #state{gw = Gateway = #{type := GwType},
|
cb_gateway_load(State = #state{gw = Gateway = #{name := GwName},
|
||||||
ctx = Ctx}) ->
|
ctx = Ctx}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwName),
|
||||||
case CbMod:on_gateway_load(Gateway, Ctx) of
|
case CbMod:on_gateway_load(Gateway, Ctx) of
|
||||||
{error, Reason} -> throw({callback_return_error, Reason});
|
{error, Reason} -> throw({callback_return_error, Reason});
|
||||||
{ok, ChildPidOrSpecs, GwState} ->
|
{ok, ChildPidOrSpecs, GwState} ->
|
||||||
|
@ -285,17 +286,17 @@ cb_gateway_load(State = #state{gw = Gateway = #{type := GwType},
|
||||||
Class : Reason1 : Stk ->
|
Class : Reason1 : Stk ->
|
||||||
logger:error("Failed to load ~s gateway (~0p, ~0p) crashed: "
|
logger:error("Failed to load ~s gateway (~0p, ~0p) crashed: "
|
||||||
"{~p, ~p}, stacktrace: ~0p",
|
"{~p, ~p}, stacktrace: ~0p",
|
||||||
[GwType, Gateway, Ctx,
|
[GwName, Gateway, Ctx,
|
||||||
Class, Reason1, Stk]),
|
Class, Reason1, Stk]),
|
||||||
{error, {Class, Reason1, Stk}}
|
{error, {Class, Reason1, Stk}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_gateway_update(NewGateway,
|
cb_gateway_update(NewGateway,
|
||||||
State = #state{gw = Gateway = #{type := GwType},
|
State = #state{gw = Gateway = #{name := GwName},
|
||||||
ctx = Ctx,
|
ctx = Ctx,
|
||||||
gw_state = GwState}) ->
|
gw_state = GwState}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwName),
|
||||||
case CbMod:on_gateway_update(NewGateway, Gateway, GwState) of
|
case CbMod:on_gateway_update(NewGateway, Gateway, GwState) of
|
||||||
{error, Reason} -> throw({callback_return_error, Reason});
|
{error, Reason} -> throw({callback_return_error, Reason});
|
||||||
{ok, ChildPidOrSpecs, NGwState} ->
|
{ok, ChildPidOrSpecs, NGwState} ->
|
||||||
|
|
|
@ -47,36 +47,36 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_link(Type) ->
|
start_link(GwName) ->
|
||||||
gen_server:start_link(?MODULE, [Type], []).
|
gen_server:start_link(?MODULE, [GwName], []).
|
||||||
|
|
||||||
-spec inc(gateway_type(), atom()) -> ok.
|
-spec inc(gateway_name(), atom()) -> ok.
|
||||||
inc(Type, Name) ->
|
inc(GwName, Name) ->
|
||||||
inc(Type, Name, 1).
|
inc(GwName, Name, 1).
|
||||||
|
|
||||||
-spec inc(gateway_type(), atom(), integer()) -> ok.
|
-spec inc(gateway_name(), atom(), integer()) -> ok.
|
||||||
inc(Type, Name, Oct) ->
|
inc(GwName, Name, Oct) ->
|
||||||
ets:update_counter(tabname(Type), Name, {2, Oct}, {Name, 0}),
|
ets:update_counter(tabname(GwName), Name, {2, Oct}, {Name, 0}),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
-spec dec(gateway_type(), atom()) -> ok.
|
-spec dec(gateway_name(), atom()) -> ok.
|
||||||
dec(Type, Name) ->
|
dec(GwName, Name) ->
|
||||||
inc(Type, Name, -1).
|
inc(GwName, Name, -1).
|
||||||
|
|
||||||
-spec dec(gateway_type(), atom(), non_neg_integer()) -> ok.
|
-spec dec(gateway_name(), atom(), non_neg_integer()) -> ok.
|
||||||
dec(Type, Name, Oct) ->
|
dec(GwName, Name, Oct) ->
|
||||||
inc(Type, Name, -Oct).
|
inc(GwName, Name, -Oct).
|
||||||
|
|
||||||
tabname(Type) ->
|
tabname(GwName) ->
|
||||||
list_to_atom(lists:concat([emqx_gateway_, Type, '_metrics'])).
|
list_to_atom(lists:concat([emqx_gateway_, GwName, '_metrics'])).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
init([Type]) ->
|
init([GwName]) ->
|
||||||
TabOpts = [public, {write_concurrency, true}],
|
TabOpts = [public, {write_concurrency, true}],
|
||||||
ok = emqx_tables:new(tabname(Type), [set|TabOpts]),
|
ok = emqx_tables:new(tabname(GwName), [set|TabOpts]),
|
||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc The Registry Centre of Gateway Type
|
%% @doc The Registry Centre of Gateway
|
||||||
-module(emqx_gateway_registry).
|
-module(emqx_gateway_registry).
|
||||||
|
|
||||||
-include("include/emqx_gateway.hrl").
|
-include("include/emqx_gateway.hrl").
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-record(state, {
|
-record(state, {
|
||||||
reged = #{} :: #{ gateway_type() => descriptor() }
|
reged = #{} :: #{ gateway_name() => descriptor() }
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type registry_options() :: [registry_option()].
|
-type registry_options() :: [registry_option()].
|
||||||
|
@ -64,33 +64,33 @@ start_link() ->
|
||||||
%% Mgmt
|
%% Mgmt
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-spec reg(gateway_type(), registry_options())
|
-spec reg(gateway_name(), registry_options())
|
||||||
-> ok
|
-> ok
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
reg(Type, RgOpts) ->
|
reg(Name, RgOpts) ->
|
||||||
CbMod = proplists:get_value(cbkmod, RgOpts, Type),
|
CbMod = proplists:get_value(cbkmod, RgOpts, Name),
|
||||||
Dscrptr = #{ cbkmod => CbMod
|
Dscrptr = #{ cbkmod => CbMod
|
||||||
, rgopts => RgOpts
|
, rgopts => RgOpts
|
||||||
},
|
},
|
||||||
call({reg, Type, Dscrptr}).
|
call({reg, Name, Dscrptr}).
|
||||||
|
|
||||||
-spec unreg(gateway_type()) -> ok | {error, any()}.
|
-spec unreg(gateway_name()) -> ok | {error, any()}.
|
||||||
unreg(Type) ->
|
unreg(Name) ->
|
||||||
%% TODO: Checking ALL INSTACE HAS STOPPED
|
%% TODO: Checking ALL INSTACE HAS STOPPED
|
||||||
call({unreg, Type}).
|
call({unreg, Name}).
|
||||||
|
|
||||||
%% TODO:
|
%% TODO:
|
||||||
%unreg(Type, Force) ->
|
%unreg(Name, Force) ->
|
||||||
% call({unreg, Type, Froce}).
|
% call({unreg, Name, Froce}).
|
||||||
|
|
||||||
%% @doc Return all registered protocol gateway implementation
|
%% @doc Return all registered protocol gateway implementation
|
||||||
-spec list() -> [{gateway_type(), descriptor()}].
|
-spec list() -> [{gateway_name(), descriptor()}].
|
||||||
list() ->
|
list() ->
|
||||||
call(all).
|
call(all).
|
||||||
|
|
||||||
-spec lookup(gateway_type()) -> undefined | descriptor().
|
-spec lookup(gateway_name()) -> undefined | descriptor().
|
||||||
lookup(Type) ->
|
lookup(Name) ->
|
||||||
call({lookup, Type}).
|
call({lookup, Name}).
|
||||||
|
|
||||||
call(Req) ->
|
call(Req) ->
|
||||||
gen_server:call(?MODULE, Req, 5000).
|
gen_server:call(?MODULE, Req, 5000).
|
||||||
|
@ -104,29 +104,29 @@ init([]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
{ok, #state{reged = #{}}}.
|
{ok, #state{reged = #{}}}.
|
||||||
|
|
||||||
handle_call({reg, Type, Dscrptr}, _From, State = #state{reged = Gateways}) ->
|
handle_call({reg, Name, Dscrptr}, _From, State = #state{reged = Gateways}) ->
|
||||||
case maps:get(Type, Gateways, notfound) of
|
case maps:get(Name, Gateways, notfound) of
|
||||||
notfound ->
|
notfound ->
|
||||||
NGateways = maps:put(Type, Dscrptr, Gateways),
|
NGateways = maps:put(Name, Dscrptr, Gateways),
|
||||||
{reply, ok, State#state{reged = NGateways}};
|
{reply, ok, State#state{reged = NGateways}};
|
||||||
_ ->
|
_ ->
|
||||||
{reply, {error, already_existed}, State}
|
{reply, {error, already_existed}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call({unreg, Type}, _From, State = #state{reged = Gateways}) ->
|
handle_call({unreg, Name}, _From, State = #state{reged = Gateways}) ->
|
||||||
case maps:get(Type, Gateways, undefined) of
|
case maps:get(Name, Gateways, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
_ ->
|
_ ->
|
||||||
_ = emqx_gateway_sup:unload_gateway(Type),
|
_ = emqx_gateway_sup:unload_gateway(Name),
|
||||||
{reply, ok, State#state{reged = maps:remove(Type, Gateways)}}
|
{reply, ok, State#state{reged = maps:remove(Name, Gateways)}}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(all, _From, State = #state{reged = Gateways}) ->
|
handle_call(all, _From, State = #state{reged = Gateways}) ->
|
||||||
{reply, maps:to_list(Gateways), State};
|
{reply, maps:to_list(Gateways), State};
|
||||||
|
|
||||||
handle_call({lookup, Type}, _From, State = #state{reged = Gateways}) ->
|
handle_call({lookup, Name}, _From, State = #state{reged = Gateways}) ->
|
||||||
Reply = maps:get(Type, Gateways, undefined),
|
Reply = maps:get(Name, Gateways, undefined),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
|
|
||||||
handle_call(Req, _From, State) ->
|
handle_call(Req, _From, State) ->
|
||||||
|
|
|
@ -44,27 +44,27 @@ start_link() ->
|
||||||
|
|
||||||
|
|
||||||
-spec load_gateway(gateway()) -> {ok, pid()} | {error, any()}.
|
-spec load_gateway(gateway()) -> {ok, pid()} | {error, any()}.
|
||||||
load_gateway(Gateway = #{type := GwType}) ->
|
load_gateway(Gateway = #{name := GwName}) ->
|
||||||
case emqx_gateway_registry:lookup(GwType) of
|
case emqx_gateway_registry:lookup(GwName) of
|
||||||
undefined -> {error, {unknown_gateway_type, GwType}};
|
undefined -> {error, {unknown_gateway_name, GwName}};
|
||||||
GwDscrptr ->
|
GwDscrptr ->
|
||||||
{ok, GwSup} = ensure_gateway_suptree_ready(GwType),
|
{ok, GwSup} = ensure_gateway_suptree_ready(GwName),
|
||||||
emqx_gateway_gw_sup:create_insta(GwSup, Gateway, GwDscrptr)
|
emqx_gateway_gw_sup:create_insta(GwSup, Gateway, GwDscrptr)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec unload_gateway(gateway_type()) -> ok | {error, not_found}.
|
-spec unload_gateway(gateway_name()) -> ok | {error, not_found}.
|
||||||
unload_gateway(GwType) ->
|
unload_gateway(GwName) ->
|
||||||
case lists:keyfind(GwType, 1, supervisor:which_children(?MODULE)) of
|
case lists:keyfind(GwName, 1, supervisor:which_children(?MODULE)) of
|
||||||
false -> {error, not_found};
|
false -> {error, not_found};
|
||||||
_ ->
|
_ ->
|
||||||
_ = supervisor:terminate_child(?MODULE, GwType),
|
_ = supervisor:terminate_child(?MODULE, GwName),
|
||||||
_ = supervisor:delete_child(?MODULE, GwType),
|
_ = supervisor:delete_child(?MODULE, GwName),
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec lookup_gateway(gateway_type()) -> gateway() | undefined.
|
-spec lookup_gateway(gateway_name()) -> gateway() | undefined.
|
||||||
lookup_gateway(GwType) ->
|
lookup_gateway(GwName) ->
|
||||||
case search_gateway_insta_proc(GwType) of
|
case search_gateway_insta_proc(GwName) of
|
||||||
{ok, {_, GwInstaPid}} ->
|
{ok, {_, GwInstaPid}} ->
|
||||||
emqx_gateway_insta_sup:info(GwInstaPid);
|
emqx_gateway_insta_sup:info(GwInstaPid);
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -74,25 +74,25 @@ lookup_gateway(GwType) ->
|
||||||
-spec update_gateway(gateway())
|
-spec update_gateway(gateway())
|
||||||
-> ok
|
-> ok
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
update_gateway(NewGateway = #{type := GwType}) ->
|
update_gateway(NewGateway = #{name := GwName}) ->
|
||||||
case emqx_gateway_utils:find_sup_child(?MODULE, GwType) of
|
case emqx_gateway_utils:find_sup_child(?MODULE, GwName) of
|
||||||
{ok, GwSup} ->
|
{ok, GwSup} ->
|
||||||
emqx_gateway_gw_sup:update_insta(GwSup, NewGateway);
|
emqx_gateway_gw_sup:update_insta(GwSup, NewGateway);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_gateway_insta(GwType) ->
|
start_gateway_insta(GwName) ->
|
||||||
case search_gateway_insta_proc(GwType) of
|
case search_gateway_insta_proc(GwName) of
|
||||||
{ok, {GwSup, _}} ->
|
{ok, {GwSup, _}} ->
|
||||||
emqx_gateway_gw_sup:start_insta(GwSup, GwType);
|
emqx_gateway_gw_sup:start_insta(GwSup, GwName);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec stop_gateway_insta(gateway_type()) -> ok | {error, any()}.
|
-spec stop_gateway_insta(gateway_name()) -> ok | {error, any()}.
|
||||||
stop_gateway_insta(GwType) ->
|
stop_gateway_insta(GwName) ->
|
||||||
case search_gateway_insta_proc(GwType) of
|
case search_gateway_insta_proc(GwName) of
|
||||||
{ok, {GwSup, _}} ->
|
{ok, {GwSup, _}} ->
|
||||||
emqx_gateway_gw_sup:stop_insta(GwSup, GwType);
|
emqx_gateway_gw_sup:stop_insta(GwSup, GwName);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -103,9 +103,9 @@ list_gateway_insta() ->
|
||||||
emqx_gateway_gw_sup:list_insta(SupId)
|
emqx_gateway_gw_sup:list_insta(SupId)
|
||||||
end, list_started_gateway())).
|
end, list_started_gateway())).
|
||||||
|
|
||||||
-spec list_started_gateway() -> [gateway_type()].
|
-spec list_started_gateway() -> [gateway_name()].
|
||||||
list_started_gateway() ->
|
list_started_gateway() ->
|
||||||
started_gateway_type().
|
started_gateway().
|
||||||
|
|
||||||
%% Supervisor callback
|
%% Supervisor callback
|
||||||
|
|
||||||
|
@ -122,14 +122,14 @@ init([]) ->
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
ensure_gateway_suptree_ready(GwType) ->
|
ensure_gateway_suptree_ready(GwName) ->
|
||||||
case lists:keyfind(GwType, 1, supervisor:which_children(?MODULE)) of
|
case lists:keyfind(GwName, 1, supervisor:which_children(?MODULE)) of
|
||||||
false ->
|
false ->
|
||||||
ChildSpec = emqx_gateway_utils:childspec(
|
ChildSpec = emqx_gateway_utils:childspec(
|
||||||
GwType,
|
GwName,
|
||||||
supervisor,
|
supervisor,
|
||||||
emqx_gateway_gw_sup,
|
emqx_gateway_gw_sup,
|
||||||
[GwType]
|
[GwName]
|
||||||
),
|
),
|
||||||
emqx_gateway_utils:supervisor_ret(
|
emqx_gateway_utils:supervisor_ret(
|
||||||
supervisor:start_child(?MODULE, ChildSpec)
|
supervisor:start_child(?MODULE, ChildSpec)
|
||||||
|
@ -150,7 +150,7 @@ search_gateway_insta_proc(InstaId, [SupPid|More]) ->
|
||||||
search_gateway_insta_proc(InstaId, More)
|
search_gateway_insta_proc(InstaId, More)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
started_gateway_type() ->
|
started_gateway() ->
|
||||||
lists:filtermap(
|
lists:filtermap(
|
||||||
fun({Id, _, _, _}) ->
|
fun({Id, _, _, _}) ->
|
||||||
is_a_gateway_id(Id) andalso {true, Id}
|
is_a_gateway_id(Id) andalso {true, Id}
|
||||||
|
|
|
@ -47,9 +47,9 @@ unreg() ->
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_grpc_server(_GwType, undefined) ->
|
start_grpc_server(_GwName, undefined) ->
|
||||||
undefined;
|
undefined;
|
||||||
start_grpc_server(GwType, Options = #{bind := ListenOn}) ->
|
start_grpc_server(GwName, Options = #{bind := ListenOn}) ->
|
||||||
Services = #{protos => [emqx_exproto_pb],
|
Services = #{protos => [emqx_exproto_pb],
|
||||||
services => #{
|
services => #{
|
||||||
'emqx.exproto.v1.ConnectionAdapter' => emqx_exproto_gsvr}
|
'emqx.exproto.v1.ConnectionAdapter' => emqx_exproto_gsvr}
|
||||||
|
@ -59,12 +59,12 @@ start_grpc_server(GwType, Options = #{bind := ListenOn}) ->
|
||||||
SslOpts ->
|
SslOpts ->
|
||||||
[{ssl_options, SslOpts}]
|
[{ssl_options, SslOpts}]
|
||||||
end,
|
end,
|
||||||
_ = grpc:start_server(GwType, ListenOn, Services, SvrOptions),
|
_ = grpc:start_server(GwName, ListenOn, Services, SvrOptions),
|
||||||
?ULOG("Start ~s gRPC server on ~p successfully.~n", [GwType, ListenOn]).
|
?ULOG("Start ~s gRPC server on ~p successfully.~n", [GwName, ListenOn]).
|
||||||
|
|
||||||
start_grpc_client_channel(_GwType, undefined) ->
|
start_grpc_client_channel(_GwType, undefined) ->
|
||||||
undefined;
|
undefined;
|
||||||
start_grpc_client_channel(GwType, Options = #{address := UriStr}) ->
|
start_grpc_client_channel(GwName, Options = #{address := UriStr}) ->
|
||||||
UriMap = uri_string:parse(UriStr),
|
UriMap = uri_string:parse(UriStr),
|
||||||
Scheme = maps:get(scheme, UriMap),
|
Scheme = maps:get(scheme, UriMap),
|
||||||
Host = maps:get(host, UriMap),
|
Host = maps:get(host, UriMap),
|
||||||
|
@ -81,36 +81,36 @@ start_grpc_client_channel(GwType, Options = #{address := UriStr}) ->
|
||||||
transport_opts => SslOpts}};
|
transport_opts => SslOpts}};
|
||||||
_ -> #{}
|
_ -> #{}
|
||||||
end,
|
end,
|
||||||
grpc_client_sup:create_channel_pool(GwType, SvrAddr, ClientOpts).
|
grpc_client_sup:create_channel_pool(GwName, SvrAddr, ClientOpts).
|
||||||
|
|
||||||
on_gateway_load(_Gateway = #{ type := GwType,
|
on_gateway_load(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx) ->
|
}, Ctx) ->
|
||||||
%% XXX: How to monitor it ?
|
%% XXX: How to monitor it ?
|
||||||
%% Start grpc client pool & client channel
|
%% Start grpc client pool & client channel
|
||||||
PoolName = pool_name(GwType),
|
PoolName = pool_name(GwName),
|
||||||
PoolSize = emqx_vm:schedulers() * 2,
|
PoolSize = emqx_vm:schedulers() * 2,
|
||||||
{ok, _} = emqx_pool_sup:start_link(PoolName, hash, PoolSize,
|
{ok, _} = emqx_pool_sup:start_link(PoolName, hash, PoolSize,
|
||||||
{emqx_exproto_gcli, start_link, []}),
|
{emqx_exproto_gcli, start_link, []}),
|
||||||
_ = start_grpc_client_channel(GwType, maps:get(handler, RawConf, undefined)),
|
_ = start_grpc_client_channel(GwName, maps:get(handler, RawConf, undefined)),
|
||||||
|
|
||||||
%% XXX: How to monitor it ?
|
%% XXX: How to monitor it ?
|
||||||
_ = start_grpc_server(GwType, maps:get(server, RawConf, undefined)),
|
_ = start_grpc_server(GwName, maps:get(server, RawConf, undefined)),
|
||||||
|
|
||||||
NRawConf = maps:without(
|
NRawConf = maps:without(
|
||||||
[server, handler],
|
[server, handler],
|
||||||
RawConf#{pool_name => PoolName}
|
RawConf#{pool_name => PoolName}
|
||||||
),
|
),
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(
|
Listeners = emqx_gateway_utils:normalize_rawconf(
|
||||||
NRawConf#{handler => GwType}
|
NRawConf#{handler => GwName}
|
||||||
),
|
),
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(GwType, Ctx, Lis)
|
start_listener(GwName, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
GwType = maps:get(type, NewGateway),
|
GwName = maps:get(name, NewGateway),
|
||||||
try
|
try
|
||||||
%% XXX: 1. How hot-upgrade the changes ???
|
%% XXX: 1. How hot-upgrade the changes ???
|
||||||
%% XXX: 2. Check the New confs first before destroy old instance ???
|
%% XXX: 2. Check the New confs first before destroy old instance ???
|
||||||
|
@ -120,40 +120,40 @@ on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[GwType, Class, Reason, Stk]),
|
[GwName, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_gateway_unload(_Gateway = #{ type := GwType,
|
on_gateway_unload(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwState) ->
|
}, _GwState) ->
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(GwType, Lis)
|
stop_listener(GwName, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
pool_name(GwType) ->
|
pool_name(GwName) ->
|
||||||
list_to_atom(lists:concat([GwType, "_gcli_pool"])).
|
list_to_atom(lists:concat([GwName, "_gcli_pool"])).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwName, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]),
|
[GwName, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason]),
|
[GwName, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_exproto_frame,
|
frame_mod => emqx_exproto_frame,
|
||||||
|
@ -172,8 +172,8 @@ do_start_listener(udp, Name, ListenOn, Opts, MFA) ->
|
||||||
do_start_listener(dtls, Name, ListenOn, Opts, MFA) ->
|
do_start_listener(dtls, Name, ListenOn, Opts, MFA) ->
|
||||||
esockd:open_dtls(Name, ListenOn, Opts, MFA).
|
esockd:open_dtls(Name, ListenOn, Opts, MFA).
|
||||||
|
|
||||||
name(GwType, Type) ->
|
name(GwName, Type) ->
|
||||||
list_to_atom(lists:concat([GwType, ":", Type])).
|
list_to_atom(lists:concat([GwName, ":", Type])).
|
||||||
|
|
||||||
merge_default_by_type(Type, Options) when Type =:= tcp;
|
merge_default_by_type(Type, Options) when Type =:= tcp;
|
||||||
Type =:= ssl ->
|
Type =:= ssl ->
|
||||||
|
@ -196,18 +196,18 @@ merge_default_by_type(Type, Options) when Type =:= udp;
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwName, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(GwType, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwName, Type, ListenOn, SocketOpts, Cfg),
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case StopRet of
|
case StopRet of
|
||||||
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]);
|
[GwName, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason])
|
[GwName, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwName, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -47,7 +47,7 @@ unreg() ->
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_gateway_load(_Gateway = #{ type := GwType,
|
on_gateway_load(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx) ->
|
}, Ctx) ->
|
||||||
|
|
||||||
|
@ -66,12 +66,12 @@ on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
|
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(GwType, Ctx, Lis)
|
start_listener(GwName, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
GwType = maps:get(type, NewGateway),
|
GwName = maps:get(name, NewGateway),
|
||||||
try
|
try
|
||||||
%% XXX: 1. How hot-upgrade the changes ???
|
%% XXX: 1. How hot-upgrade the changes ???
|
||||||
%% XXX: 2. Check the New confs first before destroy old instance ???
|
%% XXX: 2. Check the New confs first before destroy old instance ???
|
||||||
|
@ -81,11 +81,11 @@ on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[GwType, Class, Reason, Stk]),
|
[GwName, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_gateway_unload(_Gateway = #{ type := GwType,
|
on_gateway_unload(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwState) ->
|
}, _GwState) ->
|
||||||
%% XXX:
|
%% XXX:
|
||||||
|
@ -96,28 +96,28 @@ on_gateway_unload(_Gateway = #{ type := GwType,
|
||||||
|
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(GwType, Lis)
|
stop_listener(GwName, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwName, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]),
|
[GwName, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason]),
|
[GwName, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(GwType, udp),
|
Name = name(GwName, udp),
|
||||||
NCfg = Cfg#{ctx => Ctx},
|
NCfg = Cfg#{ctx => Ctx},
|
||||||
NSocketOpts = merge_default(SocketOpts),
|
NSocketOpts = merge_default(SocketOpts),
|
||||||
Options = [{config, NCfg}|NSocketOpts],
|
Options = [{config, NCfg}|NSocketOpts],
|
||||||
|
@ -128,8 +128,8 @@ start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
lwm2m_coap_server:start_dtls(Name, ListenOn, Options)
|
lwm2m_coap_server:start_dtls(Name, ListenOn, Options)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
name(GwType, Type) ->
|
name(GwName, Type) ->
|
||||||
list_to_atom(lists:concat([GwType, ":", Type])).
|
list_to_atom(lists:concat([GwName, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_udp_options(),
|
Default = emqx_gateway_utils:default_udp_options(),
|
||||||
|
@ -141,20 +141,20 @@ merge_default(Options) ->
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwName, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(GwType, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwName, Type, ListenOn, SocketOpts, Cfg),
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case StopRet of
|
case StopRet of
|
||||||
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]);
|
[GwName, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason])
|
[GwName, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwName, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
case Type of
|
case Type of
|
||||||
udp ->
|
udp ->
|
||||||
lwm2m_coap_server:stop_udp(Name, ListenOn);
|
lwm2m_coap_server:stop_udp(Name, ListenOn);
|
||||||
|
|
|
@ -47,7 +47,7 @@ unreg() ->
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_gateway_load(_Gateway = #{ type := GwType,
|
on_gateway_load(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx) ->
|
}, Ctx) ->
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
end,
|
end,
|
||||||
|
|
||||||
PredefTopics = maps:get(predefined, RawConf, []),
|
PredefTopics = maps:get(predefined, RawConf, []),
|
||||||
{ok, RegistrySvr} = emqx_sn_registry:start_link(GwType, PredefTopics),
|
{ok, RegistrySvr} = emqx_sn_registry:start_link(GwName, PredefTopics),
|
||||||
|
|
||||||
NRawConf = maps:without(
|
NRawConf = maps:without(
|
||||||
[broadcast, predefined],
|
[broadcast, predefined],
|
||||||
|
@ -73,11 +73,11 @@ on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(NRawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(NRawConf),
|
||||||
|
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(GwType, Ctx, Lis)
|
start_listener(GwName, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_gateway_update(NewGateway = #{type := GwType}, OldGateway,
|
on_gateway_update(NewGateway = #{name := GwName}, OldGateway,
|
||||||
GwState = #{ctx := Ctx}) ->
|
GwState = #{ctx := Ctx}) ->
|
||||||
try
|
try
|
||||||
%% XXX: 1. How hot-upgrade the changes ???
|
%% XXX: 1. How hot-upgrade the changes ???
|
||||||
|
@ -88,37 +88,37 @@ on_gateway_update(NewGateway = #{type := GwType}, OldGateway,
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[GwType, Class, Reason, Stk]),
|
[GwName, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_gateway_unload(_Insta = #{ type := GwType,
|
on_gateway_unload(_Insta = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwState) ->
|
}, _GwState) ->
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(GwType, Lis)
|
stop_listener(GwName, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwName, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]),
|
[GwName, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason]),
|
[GwName, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_sn_frame,
|
frame_mod => emqx_sn_frame,
|
||||||
|
@ -127,8 +127,8 @@ start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
esockd:open_udp(Name, ListenOn, merge_default(SocketOpts),
|
esockd:open_udp(Name, ListenOn, merge_default(SocketOpts),
|
||||||
{emqx_gateway_conn, start_link, [NCfg]}).
|
{emqx_gateway_conn, start_link, [NCfg]}).
|
||||||
|
|
||||||
name(GwType, Type) ->
|
name(GwName, Type) ->
|
||||||
list_to_atom(lists:concat([GwType, ":", Type])).
|
list_to_atom(lists:concat([GwName, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_udp_options(),
|
Default = emqx_gateway_utils:default_udp_options(),
|
||||||
|
@ -140,18 +140,18 @@ merge_default(Options) ->
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwName, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(GwType, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwName, Type, ListenOn, SocketOpts, Cfg),
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case StopRet of
|
case StopRet of
|
||||||
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]);
|
[GwName, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason])
|
[GwName, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwName, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -49,21 +49,21 @@ unreg() ->
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_gateway_load(_Gateway = #{ type := GwType,
|
on_gateway_load(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx) ->
|
}, Ctx) ->
|
||||||
%% Step1. Fold the rawconfs to listeners
|
%% Step1. Fold the rawconfs to listeners
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
%% Step2. Start listeners or escokd:specs
|
%% Step2. Start listeners or escokd:specs
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(GwType, Ctx, Lis)
|
start_listener(GwName, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
%% FIXME: How to throw an exception to interrupt the restart logic ?
|
%% FIXME: How to throw an exception to interrupt the restart logic ?
|
||||||
%% FIXME: Assign ctx to GwState
|
%% FIXME: Assign ctx to GwState
|
||||||
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
GwType = maps:get(type, NewGateway),
|
GwName = maps:get(name, NewGateway),
|
||||||
try
|
try
|
||||||
%% XXX: 1. How hot-upgrade the changes ???
|
%% XXX: 1. How hot-upgrade the changes ???
|
||||||
%% XXX: 2. Check the New confs first before destroy old state???
|
%% XXX: 2. Check the New confs first before destroy old state???
|
||||||
|
@ -73,37 +73,37 @@ on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[GwType, Class, Reason, Stk]),
|
[GwName, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_gateway_unload(_Gateway = #{ type := GwType,
|
on_gateway_unload(_Gateway = #{ name := GwName,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwState) ->
|
}, _GwState) ->
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(GwType, Lis)
|
stop_listener(GwName, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwName, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]),
|
[GwName, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason]),
|
[GwName, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwName, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_stomp_frame,
|
frame_mod => emqx_stomp_frame,
|
||||||
|
@ -112,8 +112,8 @@ start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
esockd:open(Name, ListenOn, merge_default(SocketOpts),
|
esockd:open(Name, ListenOn, merge_default(SocketOpts),
|
||||||
{emqx_gateway_conn, start_link, [NCfg]}).
|
{emqx_gateway_conn, start_link, [NCfg]}).
|
||||||
|
|
||||||
name(GwType, Type) ->
|
name(GwName, Type) ->
|
||||||
list_to_atom(lists:concat([GwType, ":", Type])).
|
list_to_atom(lists:concat([GwName, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_tcp_options(),
|
Default = emqx_gateway_utils:default_tcp_options(),
|
||||||
|
@ -125,18 +125,18 @@ merge_default(Options) ->
|
||||||
[{tcp_options, Default} | Options]
|
[{tcp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwName, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(GwType, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwName, Type, ListenOn, SocketOpts, Cfg),
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case StopRet of
|
case StopRet of
|
||||||
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[GwType, Type, ListenOnStr]);
|
[GwName, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[GwType, Type, ListenOnStr, Reason])
|
[GwName, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwName, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(GwType, Type),
|
Name = name(GwName, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
Loading…
Reference in New Issue