refactor(gw): single instance support only
This commit is contained in:
parent
50ee840220
commit
be4d2495f0
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
gateway: {
|
gateway: {
|
||||||
|
|
||||||
stomp.1: {
|
stomp: {
|
||||||
|
|
||||||
frame: {
|
frame: {
|
||||||
max_headers: 10
|
max_headers: 10
|
||||||
max_headers_length: 1024
|
max_headers_length: 1024
|
||||||
|
@ -37,7 +38,8 @@ gateway: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
coap.1: {
|
coap: {
|
||||||
|
|
||||||
enable_stats: false
|
enable_stats: false
|
||||||
|
|
||||||
authentication: {
|
authentication: {
|
||||||
|
@ -63,7 +65,7 @@ gateway: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mqttsn.1: {
|
mqttsn: {
|
||||||
## The MQTT-SN Gateway ID in ADVERTISE message.
|
## The MQTT-SN Gateway ID in ADVERTISE message.
|
||||||
gateway_id: 1
|
gateway_id: 1
|
||||||
|
|
||||||
|
@ -107,8 +109,7 @@ gateway: {
|
||||||
}
|
}
|
||||||
|
|
||||||
## Extension Protocol Gateway
|
## Extension Protocol Gateway
|
||||||
exproto.1: {
|
exproto: {
|
||||||
|
|
||||||
## The gRPC server to accept requests
|
## The gRPC server to accept requests
|
||||||
server: {
|
server: {
|
||||||
bind: 9100
|
bind: 9100
|
||||||
|
@ -138,9 +139,10 @@ gateway: {
|
||||||
#listener.dtls.1: {}
|
#listener.dtls.1: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwm2m_xml_dir: "{{ platform_etc_dir }}/lwm2m_xml"
|
|
||||||
|
|
||||||
lwm2m.1: {
|
lwm2m: {
|
||||||
|
|
||||||
|
xml_dir: "{{ platform_etc_dir }}/lwm2m_xml"
|
||||||
|
|
||||||
lifetime_min: 1s
|
lifetime_min: 1s
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,13 @@
|
||||||
-type instance_id() :: atom().
|
-type instance_id() :: atom().
|
||||||
-type gateway_type() :: atom().
|
-type gateway_type() :: atom().
|
||||||
|
|
||||||
%% @doc The Gateway Instace defination
|
%% @doc The Gateway defination
|
||||||
-type instance() ::
|
-type gateway() ::
|
||||||
#{ id := instance_id()
|
#{ type := gateway_type()
|
||||||
, type := gateway_type()
|
|
||||||
, name := binary()
|
|
||||||
, descr => binary() | undefined
|
, descr => binary() | undefined
|
||||||
%% Appears only in creating or detailed info
|
%% Appears only in creating or detailed info
|
||||||
, rawconf => map()
|
, rawconf => map()
|
||||||
%% Appears only in getting instance status/info
|
%% Appears only in getting gateway status/info
|
||||||
, status => stopped | running
|
, status => stopped | running
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
|
|
@ -22,29 +22,21 @@
|
||||||
-type reason() :: any().
|
-type reason() :: any().
|
||||||
|
|
||||||
%% @doc
|
%% @doc
|
||||||
-callback init(Options :: list()) -> {error, reason()} | {ok, GwState :: state()}.
|
-callback on_gateway_load(Gateway :: gateway(),
|
||||||
|
Ctx :: emqx_gateway_ctx:context())
|
||||||
%% @doc
|
|
||||||
-callback on_insta_create(Insta :: instance(),
|
|
||||||
Ctx :: emqx_gateway_ctx:context(),
|
|
||||||
GwState :: state()
|
|
||||||
)
|
|
||||||
-> {error, reason()}
|
-> {error, reason()}
|
||||||
| {ok, [GwInstaPid :: pid()], GwInstaState :: state()}
|
| {ok, [ChildPid :: pid()], GwState :: state()}
|
||||||
%% TODO: v0.2 The child spec is better for restarting child process
|
%% TODO: v0.2 The child spec is better for restarting child process
|
||||||
| {ok, [Childspec :: supervisor:child_spec()], GwInstaState :: state()}.
|
| {ok, [Childspec :: supervisor:child_spec()], GwState :: state()}.
|
||||||
|
|
||||||
%% @doc
|
%% @doc
|
||||||
-callback on_insta_update(NewInsta :: instance(),
|
-callback on_gateway_update(NewGateway :: gateway(),
|
||||||
OldInsta :: instance(),
|
OldGateway :: gateway(),
|
||||||
GwInstaState :: state(),
|
|
||||||
GwState :: state())
|
GwState :: state())
|
||||||
-> ok
|
-> ok
|
||||||
| {ok, [GwInstaPid :: pid()], GwInstaState :: state()}
|
| {ok, [ChildPid :: pid()], NGwState :: state()}
|
||||||
| {ok, [Childspec :: supervisor:child_spec()], GwInstaState :: state()}
|
| {ok, [Childspec :: supervisor:child_spec()], NGwState :: state()}
|
||||||
| {error, reason()}.
|
| {error, reason()}.
|
||||||
|
|
||||||
%% @doc
|
%% @doc
|
||||||
-callback on_insta_destroy(Insta :: instance(),
|
-callback on_gateway_unload(Gateway :: gateway(), GwState :: state()) -> ok.
|
||||||
GwInstaState :: state(),
|
|
||||||
GwState :: state()) -> ok.
|
|
||||||
|
|
|
@ -21,95 +21,85 @@
|
||||||
-behavior(emqx_gateway_impl).
|
-behavior(emqx_gateway_impl).
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ load/0
|
-export([ reg/0
|
||||||
, unload/0
|
, unreg/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ init/1
|
-export([ on_gateway_load/2
|
||||||
, on_insta_create/3
|
, on_gateway_update/3
|
||||||
, on_insta_update/4
|
, on_gateway_unload/2
|
||||||
, on_insta_destroy/3
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
|
||||||
-dialyzer({nowarn_function, [load/0]}).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load() ->
|
reg() ->
|
||||||
RegistryOptions = [ {cbkmod, ?MODULE}
|
RegistryOptions = [ {cbkmod, ?MODULE}
|
||||||
],
|
],
|
||||||
Options = [],
|
emqx_gateway_registry:reg(coap, RegistryOptions).
|
||||||
emqx_gateway_registry:load(coap, RegistryOptions, Options).
|
|
||||||
|
|
||||||
unload() ->
|
unreg() ->
|
||||||
emqx_gateway_registry:unload(coap).
|
emqx_gateway_registry:unreg(coap).
|
||||||
|
|
||||||
init([]) ->
|
|
||||||
GwState = #{},
|
|
||||||
{ok, GwState}.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_insta_create(_Insta = #{id := InstaId,
|
on_gateway_load(_Gateway = #{type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx, _GwState) ->
|
}, 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(InstaId, Ctx, Lis)
|
start_listener(GwType, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
|
|
||||||
{ok, ListenerPids, #{ctx => Ctx}}.
|
{ok, ListenerPids, #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_insta_update(NewInsta, OldInsta, GwInstaState = #{ctx := Ctx}, GwState) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
InstaId = maps:get(id, NewInsta),
|
GwType = maps:get(type, 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 ???
|
||||||
on_insta_destroy(OldInsta, GwInstaState, GwState),
|
on_gateway_unload(OldGateway, GwState),
|
||||||
on_insta_create(NewInsta, Ctx, GwState)
|
on_gateway_load(NewGateway, Ctx)
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update coap instance ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[InstaId, Class, Reason, Stk]),
|
[GwType, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_insta_destroy(_Insta = #{ id := InstaId,
|
on_gateway_unload(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
},
|
}, _GwState) ->
|
||||||
_GwInstaState,
|
|
||||||
_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(InstaId, Lis)
|
stop_listener(GwType, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start coap ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]),
|
[GwType, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start coap ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason]),
|
[GwType, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_coap_frame,
|
frame_mod => emqx_coap_frame,
|
||||||
|
@ -124,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(InstaId, Type) ->
|
name(GwType, Type) ->
|
||||||
list_to_atom(lists:concat([InstaId, ":", Type])).
|
list_to_atom(lists:concat([GwType, ":", Type])).
|
||||||
|
|
||||||
stop_listener(InstaId, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(InstaId, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwType, 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 coap ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]);
|
[GwType, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop coap ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason])
|
[GwType, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(InstaId, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ registered_gateway/0
|
-export([ registered_gateway/0
|
||||||
, create/4
|
, load/2
|
||||||
, remove/1
|
, unload/1
|
||||||
, lookup/1
|
, lookup/1
|
||||||
, update/1
|
, update/1
|
||||||
, start/1
|
, start/1
|
||||||
|
@ -37,48 +37,40 @@ registered_gateway() ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Gateway Instace APIs
|
%% Gateway Instace APIs
|
||||||
|
|
||||||
-spec list() -> [instance()].
|
-spec list() -> [gateway()].
|
||||||
list() ->
|
list() ->
|
||||||
lists:append(lists:map(
|
emqx_gateway_sup:list_gateway_insta().
|
||||||
fun({_, Insta}) -> Insta end,
|
|
||||||
emqx_gateway_sup:list_gateway_insta()
|
|
||||||
)).
|
|
||||||
|
|
||||||
-spec create(gateway_type(), binary(), binary(), map())
|
-spec load(gateway_type(), map())
|
||||||
-> {ok, pid()}
|
-> {ok, pid()}
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
create(Type, Name, Descr, RawConf) ->
|
load(GwType, RawConf) ->
|
||||||
Insta = #{ id => clacu_insta_id(Type, Name)
|
Gateway = #{ type => GwType
|
||||||
, type => Type
|
, descr => undefined
|
||||||
, name => Name
|
|
||||||
, descr => Descr
|
|
||||||
, rawconf => RawConf
|
, rawconf => RawConf
|
||||||
},
|
},
|
||||||
emqx_gateway_sup:create_gateway_insta(Insta).
|
emqx_gateway_sup:load_gateway(Gateway).
|
||||||
|
|
||||||
-spec remove(instance_id()) -> ok | {error, any()}.
|
-spec unload(gateway_type()) -> ok | {error, any()}.
|
||||||
remove(InstaId) ->
|
unload(GwType) ->
|
||||||
emqx_gateway_sup:remove_gateway_insta(InstaId).
|
emqx_gateway_sup:unload_gateway(GwType).
|
||||||
|
|
||||||
-spec lookup(instance_id()) -> instance() | undefined.
|
-spec lookup(gateway_type()) -> gateway() | undefined.
|
||||||
lookup(InstaId) ->
|
lookup(GwType) ->
|
||||||
emqx_gateway_sup:lookup_gateway_insta(InstaId).
|
emqx_gateway_sup:lookup_gateway(GwType).
|
||||||
|
|
||||||
-spec update(instance()) -> ok | {error, any()}.
|
-spec update(gateway()) -> ok | {error, any()}.
|
||||||
update(NewInsta) ->
|
update(NewGateway) ->
|
||||||
emqx_gateway_sup:update_gateway_insta(NewInsta).
|
emqx_gateway_sup:update_gateway(NewGateway).
|
||||||
|
|
||||||
-spec start(instance_id()) -> ok | {error, any()}.
|
-spec start(gateway_type()) -> ok | {error, any()}.
|
||||||
start(InstaId) ->
|
start(GwType) ->
|
||||||
emqx_gateway_sup:start_gateway_insta(InstaId).
|
emqx_gateway_sup:start_gateway_insta(GwType).
|
||||||
|
|
||||||
-spec stop(instance_id()) -> ok | {error, any()}.
|
-spec stop(gateway_type()) -> ok | {error, any()}.
|
||||||
stop(InstaId) ->
|
stop(GwType) ->
|
||||||
emqx_gateway_sup:stop_gateway_insta(InstaId).
|
emqx_gateway_sup:stop_gateway_insta(GwType).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
clacu_insta_id(Type, Name) when is_binary(Name) ->
|
|
||||||
list_to_atom(lists:concat([Type, "#", binary_to_list(Name)])).
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = emqx_gateway_sup:start_link(),
|
{ok, Sup} = emqx_gateway_sup:start_link(),
|
||||||
emqx_gateway_cli:load(),
|
emqx_gateway_cli:load(),
|
||||||
load_default_gateway_applications(),
|
load_default_gateway_applications(),
|
||||||
create_gateway_by_default(),
|
load_gateway_by_default(),
|
||||||
{ok, Sup}.
|
{ok, Sup}.
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
|
@ -40,56 +40,43 @@ stop(_State) ->
|
||||||
load_default_gateway_applications() ->
|
load_default_gateway_applications() ->
|
||||||
Apps = gateway_type_searching(),
|
Apps = gateway_type_searching(),
|
||||||
?LOG(info, "Starting the default gateway types: ~p", [Apps]),
|
?LOG(info, "Starting the default gateway types: ~p", [Apps]),
|
||||||
lists:foreach(fun load/1, Apps).
|
lists:foreach(fun reg/1, Apps).
|
||||||
|
|
||||||
gateway_type_searching() ->
|
gateway_type_searching() ->
|
||||||
%% FIXME: Hardcoded apps
|
%% FIXME: Hardcoded apps
|
||||||
[emqx_stomp_impl, emqx_sn_impl, emqx_exproto_impl,
|
[emqx_stomp_impl, emqx_sn_impl, emqx_exproto_impl,
|
||||||
emqx_coap_impl, emqx_lwm2m_impl].
|
emqx_coap_impl, emqx_lwm2m_impl].
|
||||||
|
|
||||||
load(Mod) ->
|
reg(Mod) ->
|
||||||
try
|
try
|
||||||
Mod:load(),
|
Mod:reg(),
|
||||||
?LOG(info, "Load ~s gateway application successfully!", [Mod])
|
?LOG(info, "Register ~s gateway application successfully!", [Mod])
|
||||||
catch
|
catch
|
||||||
Class : Reason ->
|
Class : Reason : Stk ->
|
||||||
?LOG(error, "Load ~s gateway application failed: {~p, ~p}",
|
?LOG(error, "Failed to register ~s gateway application: {~p, ~p}\n"
|
||||||
[Mod, Class, Reason])
|
"Stacktrace: ~0p",
|
||||||
|
[Mod, Class, Reason, Stk])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_gateway_by_default() ->
|
load_gateway_by_default() ->
|
||||||
create_gateway_by_default(zipped_confs()).
|
load_gateway_by_default(confs()).
|
||||||
|
|
||||||
create_gateway_by_default([]) ->
|
load_gateway_by_default([]) ->
|
||||||
ok;
|
ok;
|
||||||
create_gateway_by_default([{Type, Name, Confs}|More]) ->
|
load_gateway_by_default([{Type, Confs}|More]) ->
|
||||||
case emqx_gateway_registry:lookup(Type) of
|
case emqx_gateway_registry:lookup(Type) of
|
||||||
undefined ->
|
undefined ->
|
||||||
?LOG(error, "Skip to start ~s#~s: not_registred_type",
|
?LOG(error, "Skip to load ~s gateway, because it is not registered",
|
||||||
[Type, Name]);
|
[Type]);
|
||||||
_ ->
|
_ ->
|
||||||
case emqx_gateway:create(Type,
|
case emqx_gateway:load(Type, Confs) of
|
||||||
atom_to_binary(Name, utf8),
|
|
||||||
<<>>,
|
|
||||||
Confs) of
|
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
?LOG(debug, "Start ~s#~s successfully!", [Type, Name]);
|
?LOG(debug, "Load ~s gateway successfully!", [Type]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?LOG(error, "Start ~s#~s failed: ~0p",
|
?LOG(error, "Failed to load ~s gateway: ~0p", [Type, Reason])
|
||||||
[Type, Name, Reason])
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
create_gateway_by_default(More).
|
load_gateway_by_default(More).
|
||||||
|
|
||||||
zipped_confs() ->
|
confs() ->
|
||||||
All = maps:to_list(
|
maps:to_list(emqx_config:get([gateway], [])).
|
||||||
maps:without(exclude_options(), emqx_config:get([gateway]))),
|
|
||||||
lists:append(lists:foldr(
|
|
||||||
fun({Type, Gws}, Acc) ->
|
|
||||||
{Names, Confs} = lists:unzip(maps:to_list(Gws)),
|
|
||||||
Types = [ Type || _ <- lists:seq(1, length(Names))],
|
|
||||||
[lists:zip3(Types, Names, Confs) | Acc]
|
|
||||||
end, [], All)).
|
|
||||||
|
|
||||||
exclude_options() ->
|
|
||||||
[lwm2m_xml_dir].
|
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc The Gateway Top supervisor.
|
%% @doc The Gateway Top supervisor.
|
||||||
|
%%
|
||||||
|
%% This supervisor has monitor a bunch of process/resources depended by
|
||||||
|
%% gateway runtime
|
||||||
|
%%
|
||||||
-module(emqx_gateway_gw_sup).
|
-module(emqx_gateway_gw_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
@ -41,64 +45,62 @@
|
||||||
start_link(Type) ->
|
start_link(Type) ->
|
||||||
supervisor:start_link({local, Type}, ?MODULE, [Type]).
|
supervisor:start_link({local, Type}, ?MODULE, [Type]).
|
||||||
|
|
||||||
-spec create_insta(pid(), instance(), map()) -> {ok, GwInstaPid :: pid()} | {error, any()}.
|
-spec create_insta(pid(), gateway(), map()) -> {ok, GwInstaPid :: pid()} | {error, any()}.
|
||||||
create_insta(Sup, Insta = #{id := InstaId}, GwDscrptr) ->
|
create_insta(Sup, Gateway = #{type := GwType}, GwDscrptr) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, InstaId) of
|
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
||||||
{ok, _GwInstaPid} -> {error, alredy_existed};
|
{ok, _GwInstaPid} -> {error, alredy_existed};
|
||||||
false ->
|
false ->
|
||||||
%% XXX: More instances options to it?
|
Ctx = ctx(Sup, GwType),
|
||||||
%%
|
|
||||||
Ctx = ctx(Sup, InstaId),
|
|
||||||
%%
|
%%
|
||||||
ChildSpec = emqx_gateway_utils:childspec(
|
ChildSpec = emqx_gateway_utils:childspec(
|
||||||
InstaId,
|
GwType,
|
||||||
worker,
|
worker,
|
||||||
emqx_gateway_insta_sup,
|
emqx_gateway_insta_sup,
|
||||||
[Insta, Ctx, GwDscrptr]
|
[Gateway, Ctx, GwDscrptr]
|
||||||
),
|
),
|
||||||
emqx_gateway_utils:supervisor_ret(
|
emqx_gateway_utils:supervisor_ret(
|
||||||
supervisor:start_child(Sup, ChildSpec)
|
supervisor:start_child(Sup, ChildSpec)
|
||||||
)
|
)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec remove_insta(pid(), InstaId :: atom()) -> ok | {error, any()}.
|
-spec remove_insta(pid(), GwType :: gateway_type()) -> ok | {error, any()}.
|
||||||
remove_insta(Sup, InstaId) ->
|
remove_insta(Sup, GwType) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, InstaId) of
|
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
||||||
false -> ok;
|
false -> ok;
|
||||||
{ok, _GwInstaPid} ->
|
{ok, _GwInstaPid} ->
|
||||||
ok = supervisor:terminate_child(Sup, InstaId),
|
ok = supervisor:terminate_child(Sup, GwType),
|
||||||
ok = supervisor:delete_child(Sup, InstaId)
|
ok = supervisor:delete_child(Sup, GwType)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec update_insta(pid(), NewInsta :: instance()) -> ok | {error, any()}.
|
-spec update_insta(pid(), NewGateway :: gateway()) -> ok | {error, any()}.
|
||||||
update_insta(Sup, NewInsta = #{id := InstaId}) ->
|
update_insta(Sup, NewGateway = #{type := GwType}) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, InstaId) of
|
case emqx_gateway_utils:find_sup_child(Sup, GwType) of
|
||||||
false -> {error, not_found};
|
false -> {error, not_found};
|
||||||
{ok, GwInstaPid} ->
|
{ok, GwInstaPid} ->
|
||||||
emqx_gateway_insta_sup:update(GwInstaPid, NewInsta)
|
emqx_gateway_insta_sup:update(GwInstaPid, NewGateway)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec start_insta(pid(), atom()) -> ok | {error, any()}.
|
-spec start_insta(pid(), gateway_type()) -> ok | {error, any()}.
|
||||||
start_insta(Sup, InstaId) ->
|
start_insta(Sup, GwType) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, InstaId) of
|
case emqx_gateway_utils:find_sup_child(Sup, GwType) 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(), atom()) -> ok | {error, any()}.
|
-spec stop_insta(pid(), gateway_type()) -> ok | {error, any()}.
|
||||||
stop_insta(Sup, InstaId) ->
|
stop_insta(Sup, GwType) ->
|
||||||
case emqx_gateway_utils:find_sup_child(Sup, InstaId) of
|
case emqx_gateway_utils:find_sup_child(Sup, GwType) 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)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec list_insta(pid()) -> [instance()].
|
-spec list_insta(pid()) -> [gateway()].
|
||||||
list_insta(Sup) ->
|
list_insta(Sup) ->
|
||||||
lists:filtermap(
|
lists:filtermap(
|
||||||
fun({InstaId, GwInstaPid, _Type, _Mods}) ->
|
fun({GwType, GwInstaPid, _Type, _Mods}) ->
|
||||||
is_gateway_insta_id(InstaId)
|
is_gateway_insta_id(GwType)
|
||||||
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)).
|
||||||
|
|
||||||
|
@ -119,10 +121,10 @@ init([Type]) ->
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
ctx(Sup, InstaId) ->
|
ctx(Sup, GwType) ->
|
||||||
{_, Type} = erlang:process_info(Sup, registered_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 => InstaId
|
#{ instid => GwType
|
||||||
, type => Type
|
, type => Type
|
||||||
, cm => CM
|
, cm => CM
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc The gateway instance management
|
%% @doc The gateway runtime
|
||||||
-module(emqx_gateway_insta_sup).
|
-module(emqx_gateway_insta_sup).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
@ -40,42 +40,42 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-record(state, {
|
-record(state, {
|
||||||
insta :: instance(),
|
gw :: gateway(),
|
||||||
ctx :: emqx_gateway_ctx:context(),
|
ctx :: emqx_gateway_ctx:context(),
|
||||||
status :: stopped | running,
|
status :: stopped | running,
|
||||||
child_pids :: [pid()],
|
child_pids :: [pid()],
|
||||||
insta_state :: emqx_gateway_impl:state() | undefined
|
gw_state :: emqx_gateway_impl:state() | undefined
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_link(Insta, Ctx, GwDscrptr) ->
|
start_link(Gateway, Ctx, GwDscrptr) ->
|
||||||
gen_server:start_link(
|
gen_server:start_link(
|
||||||
?MODULE,
|
?MODULE,
|
||||||
[Insta, Ctx, GwDscrptr],
|
[Gateway, Ctx, GwDscrptr],
|
||||||
[]
|
[]
|
||||||
).
|
).
|
||||||
|
|
||||||
-spec info(pid()) -> instance().
|
-spec info(pid()) -> gateway().
|
||||||
info(Pid) ->
|
info(Pid) ->
|
||||||
gen_server:call(Pid, info).
|
gen_server:call(Pid, info).
|
||||||
|
|
||||||
%% @doc Stop instance
|
%% @doc Stop gateway
|
||||||
-spec disable(pid()) -> ok | {error, any()}.
|
-spec disable(pid()) -> ok | {error, any()}.
|
||||||
disable(Pid) ->
|
disable(Pid) ->
|
||||||
call(Pid, disable).
|
call(Pid, disable).
|
||||||
|
|
||||||
%% @doc Start instance
|
%% @doc Start gateway
|
||||||
-spec enable(pid()) -> ok | {error, any()}.
|
-spec enable(pid()) -> ok | {error, any()}.
|
||||||
enable(Pid) ->
|
enable(Pid) ->
|
||||||
call(Pid, enable).
|
call(Pid, enable).
|
||||||
|
|
||||||
%% @doc Update the gateway instance configurations
|
%% @doc Update the gateway configurations
|
||||||
-spec update(pid(), instance()) -> ok | {error, any()}.
|
-spec update(pid(), gateway()) -> ok | {error, any()}.
|
||||||
update(Pid, NewInsta) ->
|
update(Pid, NewGateway) ->
|
||||||
call(Pid, {update, NewInsta}).
|
call(Pid, {update, NewGateway}).
|
||||||
|
|
||||||
call(Pid, Req) ->
|
call(Pid, Req) ->
|
||||||
gen_server:call(Pid, Req, 5000).
|
gen_server:call(Pid, Req, 5000).
|
||||||
|
@ -84,30 +84,29 @@ call(Pid, Req) ->
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
init([Insta, Ctx0, _GwDscrptr]) ->
|
init([Gateway, Ctx0, _GwDscrptr]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
#{id := InstaId, rawconf := RawConf} = Insta,
|
#{type := GwType, rawconf := RawConf} = Gateway,
|
||||||
Ctx = do_init_context(InstaId, RawConf, Ctx0),
|
Ctx = do_init_context(GwType, RawConf, Ctx0),
|
||||||
State = #state{
|
State = #state{
|
||||||
insta = Insta,
|
gw = Gateway,
|
||||||
ctx = Ctx,
|
ctx = Ctx,
|
||||||
child_pids = [],
|
child_pids = [],
|
||||||
status = stopped
|
status = stopped
|
||||||
},
|
},
|
||||||
case cb_insta_create(State) of
|
case cb_gateway_load(State) of
|
||||||
{error, _Reason} ->
|
{error, Reason} ->
|
||||||
do_deinit_context(Ctx),
|
do_deinit_context(Ctx),
|
||||||
%% XXX: Return Reason??
|
{stop, {load_gateway_failure, Reason}};
|
||||||
{stop, create_gateway_instance_failed};
|
|
||||||
{ok, NState} ->
|
{ok, NState} ->
|
||||||
{ok, NState}
|
{ok, NState}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_init_context(InstaId, RawConf, Ctx) ->
|
do_init_context(GwType, 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(InstaId, AuthCfgs);
|
create_authenticators_for_gateway_insta(GwType, AuthCfgs);
|
||||||
_ ->
|
_ ->
|
||||||
undefined
|
undefined
|
||||||
end,
|
end,
|
||||||
|
@ -117,13 +116,13 @@ 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{insta = Insta}) ->
|
handle_call(info, _From, State = #state{gw = Gateway}) ->
|
||||||
{reply, Insta, State};
|
{reply, Gateway, State};
|
||||||
|
|
||||||
handle_call(disable, _From, State = #state{status = Status}) ->
|
handle_call(disable, _From, State = #state{status = Status}) ->
|
||||||
case Status of
|
case Status of
|
||||||
running ->
|
running ->
|
||||||
case cb_insta_destroy(State) of
|
case cb_gateway_unload(State) of
|
||||||
{ok, NState} ->
|
{ok, NState} ->
|
||||||
{reply, ok, NState};
|
{reply, ok, NState};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -136,7 +135,7 @@ handle_call(disable, _From, State = #state{status = Status}) ->
|
||||||
handle_call(enable, _From, State = #state{status = Status}) ->
|
handle_call(enable, _From, State = #state{status = Status}) ->
|
||||||
case Status of
|
case Status of
|
||||||
stopped ->
|
stopped ->
|
||||||
case cb_insta_create(State) of
|
case cb_gateway_load(State) of
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{reply, {error, Reason}, State};
|
{reply, {error, Reason}, State};
|
||||||
{ok, NState} ->
|
{ok, NState} ->
|
||||||
|
@ -147,28 +146,30 @@ handle_call(enable, _From, State = #state{status = Status}) ->
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% Stopped -> update
|
%% Stopped -> update
|
||||||
handle_call({update, NewInsta}, _From, State = #state{insta = Insta,
|
handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
||||||
status = stopped}) ->
|
status = stopped}) ->
|
||||||
case maps:get(id, NewInsta, undefined) == maps:get(id, Insta, undefined) of
|
case maps:get(type, NewGateway, undefined)
|
||||||
|
== maps:get(type, Gateway, undefined) of
|
||||||
true ->
|
true ->
|
||||||
{reply, ok, State#state{insta = NewInsta}};
|
{reply, ok, State#state{gw = NewGateway}};
|
||||||
false ->
|
false ->
|
||||||
{reply, {error, bad_instan_id}, State}
|
{reply, {error, gateway_type_not_match}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% Running -> update
|
%% Running -> update
|
||||||
handle_call({update, NewInsta}, _From, State = #state{insta = Insta,
|
handle_call({update, NewGateway}, _From, State = #state{gw = Gateway,
|
||||||
status = running}) ->
|
status = running}) ->
|
||||||
case maps:get(id, NewInsta, undefined) == maps:get(id, Insta, undefined) of
|
case maps:get(type, NewGateway, undefined)
|
||||||
|
== maps:get(type, Gateway, undefined) of
|
||||||
true ->
|
true ->
|
||||||
case cb_insta_update(NewInsta, State) of
|
case cb_gateway_update(NewGateway, State) of
|
||||||
{ok, NState} ->
|
{ok, NState} ->
|
||||||
{reply, ok, NState};
|
{reply, ok, NState};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{reply, {error, Reason}, State}
|
{reply, {error, Reason}, State}
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
{reply, {error, bad_instan_id}, State}
|
{reply, {error, gateway_type_not_match}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
|
@ -187,7 +188,7 @@ handle_info({'EXIT', Pid, Reason}, State = #state{child_pids = Pids}) ->
|
||||||
logger:error("All child process exited!"),
|
logger:error("All child process exited!"),
|
||||||
{noreply, State#state{status = stopped,
|
{noreply, State#state{status = stopped,
|
||||||
child_pids = [],
|
child_pids = [],
|
||||||
insta_state = undefined}};
|
gw_state = undefined}};
|
||||||
RemainPids ->
|
RemainPids ->
|
||||||
{noreply, State#state{child_pids = RemainPids}}
|
{noreply, State#state{child_pids = RemainPids}}
|
||||||
end;
|
end;
|
||||||
|
@ -201,10 +202,7 @@ handle_info(Info, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
terminate(_Reason, State = #state{ctx = Ctx, child_pids = Pids}) ->
|
terminate(_Reason, State = #state{ctx = Ctx, child_pids = Pids}) ->
|
||||||
%% Cleanup instances
|
Pids /= [] andalso (_ = cb_gateway_unload(State)),
|
||||||
%% Step1. Destory instance
|
|
||||||
Pids /= [] andalso (_ = cb_insta_destroy(State)),
|
|
||||||
%% Step2. Delete authenticator resources
|
|
||||||
_ = do_deinit_context(Ctx),
|
_ = do_deinit_context(Ctx),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
@ -217,8 +215,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(InstaId0, AuthCfgs) ->
|
create_authenticators_for_gateway_insta(GwType, AuthCfgs) ->
|
||||||
ChainId = atom_to_binary(InstaId0, utf8),
|
ChainId = atom_to_binary(GwType, 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}) ->
|
||||||
|
@ -245,88 +243,85 @@ cleanup_authenticators_for_gateway_insta(ChainId) ->
|
||||||
case emqx_authn:delete_chain(ChainId) of
|
case emqx_authn:delete_chain(ChainId) of
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
{error, {not_found, _}} ->
|
{error, {not_found, _}} ->
|
||||||
logger:warning("Failed clean authenticator chain: ~s, "
|
logger:warning("Failed to clean authenticator chain: ~s, "
|
||||||
"reason: not_found", [ChainId]);
|
"reason: not_found", [ChainId]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
logger:error("Failed clean authenticator chain: ~s, "
|
logger:error("Failed to clean authenticator chain: ~s, "
|
||||||
"reason: ~p", [ChainId, Reason])
|
"reason: ~p", [ChainId, Reason])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_insta_destroy(State = #state{insta = Insta = #{type := Type},
|
cb_gateway_unload(State = #state{gw = Gateway = #{type := GwType},
|
||||||
insta_state = InstaState}) ->
|
gw_state = GwState}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod,
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
||||||
state := GwState} = emqx_gateway_registry:lookup(Type),
|
CbMod:on_gateway_unload(Gateway, GwState, GwState),
|
||||||
CbMod:on_insta_destroy(Insta, InstaState, GwState),
|
|
||||||
{ok, State#state{child_pids = [],
|
{ok, State#state{child_pids = [],
|
||||||
insta_state = undefined,
|
gw_state = undefined,
|
||||||
status = stopped}}
|
status = stopped}}
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Destroy instance (~0p, ~0p, _) crashed: "
|
logger:error("Failed to unload gateway (~0p, ~0p) crashed: "
|
||||||
"{~p, ~p}, stacktrace: ~0p",
|
"{~p, ~p}, stacktrace: ~0p",
|
||||||
[Insta, InstaState,
|
[Gateway, GwState,
|
||||||
Class, Reason, Stk]),
|
Class, Reason, Stk]),
|
||||||
{error, {Class, Reason, Stk}}
|
{error, {Class, Reason, Stk}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_insta_create(State = #state{insta = Insta = #{type := Type},
|
cb_gateway_load(State = #state{gw = Gateway = #{type := GwType},
|
||||||
ctx = Ctx}) ->
|
ctx = Ctx}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod,
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
||||||
state := GwState} = emqx_gateway_registry:lookup(Type),
|
case CbMod:on_gateway_load(Gateway, Ctx) of
|
||||||
case CbMod:on_insta_create(Insta, Ctx, GwState) of
|
|
||||||
{error, Reason} -> throw({callback_return_error, Reason});
|
{error, Reason} -> throw({callback_return_error, Reason});
|
||||||
{ok, InstaPidOrSpecs, InstaState} ->
|
{ok, ChildPidOrSpecs, GwState} ->
|
||||||
ChildPids = start_child_process(InstaPidOrSpecs),
|
ChildPids = start_child_process(ChildPidOrSpecs),
|
||||||
{ok, State#state{
|
{ok, State#state{
|
||||||
status = running,
|
status = running,
|
||||||
child_pids = ChildPids,
|
child_pids = ChildPids,
|
||||||
insta_state = InstaState
|
gw_state = GwState
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
Class : Reason1 : Stk ->
|
Class : Reason1 : Stk ->
|
||||||
logger:error("Create instance (~0p, ~0p, _) crashed: "
|
logger:error("Failed to load ~s gateway (~0p, ~0p) crashed: "
|
||||||
"{~p, ~p}, stacktrace: ~0p",
|
"{~p, ~p}, stacktrace: ~0p",
|
||||||
[Insta, Ctx,
|
[GwType, Gateway, Ctx,
|
||||||
Class, Reason1, Stk]),
|
Class, Reason1, Stk]),
|
||||||
{error, {Class, Reason1, Stk}}
|
{error, {Class, Reason1, Stk}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cb_insta_update(NewInsta,
|
cb_gateway_update(NewGateway,
|
||||||
State = #state{insta = Insta = #{type := Type},
|
State = #state{gw = Gateway = #{type := GwType},
|
||||||
ctx = Ctx,
|
ctx = Ctx,
|
||||||
insta_state = GwInstaState}) ->
|
gw_state = GwState}) ->
|
||||||
try
|
try
|
||||||
#{cbkmod := CbMod,
|
#{cbkmod := CbMod} = emqx_gateway_registry:lookup(GwType),
|
||||||
state := GwState} = emqx_gateway_registry:lookup(Type),
|
case CbMod:on_gateway_update(NewGateway, Gateway, GwState) of
|
||||||
case CbMod:on_insta_update(NewInsta, Insta, GwInstaState, GwState) of
|
|
||||||
{error, Reason} -> throw({callback_return_error, Reason});
|
{error, Reason} -> throw({callback_return_error, Reason});
|
||||||
{ok, InstaPidOrSpecs, InstaState} ->
|
{ok, ChildPidOrSpecs, NGwState} ->
|
||||||
%% XXX: Hot-upgrade ???
|
%% XXX: Hot-upgrade ???
|
||||||
ChildPids = start_child_process(InstaPidOrSpecs),
|
ChildPids = start_child_process(ChildPidOrSpecs),
|
||||||
{ok, State#state{
|
{ok, State#state{
|
||||||
status = running,
|
status = running,
|
||||||
child_pids = ChildPids,
|
child_pids = ChildPids,
|
||||||
insta_state = InstaState
|
gw_state = NGwState
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
Class : Reason1 : Stk ->
|
Class : Reason1 : Stk ->
|
||||||
logger:error("Update instance (~0p, ~0p, ~0p, _) crashed: "
|
logger:error("Failed to update gateway (~0p, ~0p, ~0p) crashed: "
|
||||||
"{~p, ~p}, stacktrace: ~0p",
|
"{~p, ~p}, stacktrace: ~0p",
|
||||||
[NewInsta, Insta, Ctx,
|
[NewGateway, Gateway, Ctx,
|
||||||
Class, Reason1, Stk]),
|
Class, Reason1, Stk]),
|
||||||
{error, {Class, Reason1, Stk}}
|
{error, {Class, Reason1, Stk}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_child_process([Indictor|_] = InstaPidOrSpecs) ->
|
start_child_process([Indictor|_] = ChildPidOrSpecs) ->
|
||||||
case erlang:is_pid(Indictor) of
|
case erlang:is_pid(Indictor) of
|
||||||
true ->
|
true ->
|
||||||
InstaPidOrSpecs;
|
ChildPidOrSpecs;
|
||||||
_ ->
|
_ ->
|
||||||
do_start_child_process(InstaPidOrSpecs)
|
do_start_child_process(ChildPidOrSpecs)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_start_child_process(ChildSpecs) when is_list(ChildSpecs) ->
|
do_start_child_process(ChildSpecs) when is_list(ChildSpecs) ->
|
||||||
|
|
|
@ -23,11 +23,9 @@
|
||||||
-behavior(gen_server).
|
-behavior(gen_server).
|
||||||
|
|
||||||
%% APIs for Impl.
|
%% APIs for Impl.
|
||||||
-export([ load/3
|
-export([ reg/2
|
||||||
, unload/1
|
, unreg/1
|
||||||
]).
|
, list/0
|
||||||
|
|
||||||
-export([ list/0
|
|
||||||
, lookup/1
|
, lookup/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -44,9 +42,17 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-record(state, {
|
-record(state, {
|
||||||
loaded = #{} :: #{ gateway_type() => descriptor() }
|
reged = #{} :: #{ gateway_type() => descriptor() }
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
-type registry_options() :: [registry_option()].
|
||||||
|
|
||||||
|
-type registry_option() :: {cbkmod, atom()}.
|
||||||
|
|
||||||
|
-type descriptor() :: #{ cbkmod := atom()
|
||||||
|
, rgopts := registry_options()
|
||||||
|
}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -58,37 +64,24 @@ start_link() ->
|
||||||
%% Mgmt
|
%% Mgmt
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-type registry_options() :: [registry_option()].
|
-spec reg(gateway_type(), registry_options())
|
||||||
|
|
||||||
-type registry_option() :: {cbkmod, atom()}.
|
|
||||||
|
|
||||||
-type gateway_options() :: list().
|
|
||||||
|
|
||||||
-type descriptor() :: #{ cbkmod := atom()
|
|
||||||
, rgopts := registry_options()
|
|
||||||
, gwopts := gateway_options()
|
|
||||||
, state => any()
|
|
||||||
}.
|
|
||||||
|
|
||||||
-spec load(gateway_type(), registry_options(), gateway_options())
|
|
||||||
-> ok
|
-> ok
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
load(Type, RgOpts, GwOpts) ->
|
reg(Type, RgOpts) ->
|
||||||
CbMod = proplists:get_value(cbkmod, RgOpts, Type),
|
CbMod = proplists:get_value(cbkmod, RgOpts, Type),
|
||||||
Dscrptr = #{ cbkmod => CbMod
|
Dscrptr = #{ cbkmod => CbMod
|
||||||
, rgopts => RgOpts
|
, rgopts => RgOpts
|
||||||
, gwopts => GwOpts
|
|
||||||
},
|
},
|
||||||
call({load, Type, Dscrptr}).
|
call({reg, Type, Dscrptr}).
|
||||||
|
|
||||||
-spec unload(gateway_type()) -> ok | {error, any()}.
|
-spec unreg(gateway_type()) -> ok | {error, any()}.
|
||||||
unload(Type) ->
|
unreg(Type) ->
|
||||||
%% TODO: Checking ALL INSTACE HAS STOPPED
|
%% TODO: Checking ALL INSTACE HAS STOPPED
|
||||||
call({unload, Type}).
|
call({unreg, Type}).
|
||||||
|
|
||||||
%% TODO:
|
%% TODO:
|
||||||
%unload(Type, Force) ->
|
%unreg(Type, Force) ->
|
||||||
% call({unload, Type, Froce}).
|
% call({unreg, Type, Froce}).
|
||||||
|
|
||||||
%% @doc Return all registered protocol gateway implementation
|
%% @doc Return all registered protocol gateway implementation
|
||||||
-spec list() -> [{gateway_type(), descriptor()}].
|
-spec list() -> [{gateway_type(), descriptor()}].
|
||||||
|
@ -109,41 +102,30 @@ call(Req) ->
|
||||||
init([]) ->
|
init([]) ->
|
||||||
%% TODO: Metrics ???
|
%% TODO: Metrics ???
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
{ok, #state{loaded = #{}}}.
|
{ok, #state{reged = #{}}}.
|
||||||
|
|
||||||
handle_call({load, Type, Dscrptr}, _From, State = #state{loaded = Gateways}) ->
|
handle_call({reg, Type, Dscrptr}, _From, State = #state{reged = Gateways}) ->
|
||||||
case maps:get(Type, Gateways, notfound) of
|
case maps:get(Type, Gateways, notfound) of
|
||||||
notfound ->
|
notfound ->
|
||||||
try
|
NGateways = maps:put(Type, Dscrptr, Gateways),
|
||||||
GwOpts = maps:get(gwopts, Dscrptr),
|
{reply, ok, State#state{reged = NGateways}};
|
||||||
CbMod = maps:get(cbkmod, Dscrptr),
|
|
||||||
{ok, GwState} = CbMod:init(GwOpts),
|
|
||||||
NDscrptr = maps:put(state, GwState, Dscrptr),
|
|
||||||
NGateways = maps:put(Type, NDscrptr, Gateways),
|
|
||||||
{reply, ok, State#state{loaded = NGateways}}
|
|
||||||
catch
|
|
||||||
Class : Reason : Stk ->
|
|
||||||
logger:error("Load ~s crashed {~p, ~p}; stacktrace: ~0p",
|
|
||||||
[Type, Class, Reason, Stk]),
|
|
||||||
{reply, {error, {Class, Reason}}, State}
|
|
||||||
end;
|
|
||||||
_ ->
|
_ ->
|
||||||
{reply, {error, already_existed}, State}
|
{reply, {error, already_existed}, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call({unload, Type}, _From, State = #state{loaded = Gateways}) ->
|
handle_call({unreg, Type}, _From, State = #state{reged = Gateways}) ->
|
||||||
case maps:get(Type, Gateways, undefined) of
|
case maps:get(Type, Gateways, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
_ ->
|
_ ->
|
||||||
emqx_gateway_sup:stop_all_suptree(Type),
|
emqx_gateway_sup:unload_gateway(Type),
|
||||||
{reply, ok, State#state{loaded = maps:remove(Type, Gateways)}}
|
{reply, ok, State#state{reged = maps:remove(Type, Gateways)}}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(all, _From, State = #state{loaded = 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{loaded = Gateways}) ->
|
handle_call({lookup, Type}, _From, State = #state{reged = Gateways}) ->
|
||||||
Reply = maps:get(Type, Gateways, undefined),
|
Reply = maps:get(Type, Gateways, undefined),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,13 @@
|
||||||
structs() -> ["gateway"].
|
structs() -> ["gateway"].
|
||||||
|
|
||||||
fields("gateway") ->
|
fields("gateway") ->
|
||||||
[{stomp, t(ref(stomp))},
|
[{stomp, t(ref(stomp_structs))},
|
||||||
{mqttsn, t(ref(mqttsn))},
|
{mqttsn, t(ref(mqttsn_structs))},
|
||||||
{coap, t(ref(coap))},
|
{coap, t(ref(coap_structs))},
|
||||||
{lwm2m, t(ref(lwm2m))},
|
{lwm2m, t(ref(lwm2m_structs))},
|
||||||
{lwm2m_xml_dir, t(string())},
|
{exproto, t(ref(exproto_structs))}
|
||||||
{exproto, t(ref(exproto))}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(stomp) ->
|
|
||||||
[{"$id", t(ref(stomp_structs))}];
|
|
||||||
|
|
||||||
fields(stomp_structs) ->
|
fields(stomp_structs) ->
|
||||||
[ {frame, t(ref(stomp_frame))}
|
[ {frame, t(ref(stomp_frame))}
|
||||||
, {clientinfo_override, t(ref(clientinfo_override))}
|
, {clientinfo_override, t(ref(clientinfo_override))}
|
||||||
|
@ -56,9 +52,6 @@ fields(stomp_frame) ->
|
||||||
, {max_body_length, t(integer(), undefined, 8192)}
|
, {max_body_length, t(integer(), undefined, 8192)}
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(mqttsn) ->
|
|
||||||
[{"$id", t(ref(mqttsn_structs))}];
|
|
||||||
|
|
||||||
fields(mqttsn_structs) ->
|
fields(mqttsn_structs) ->
|
||||||
[ {gateway_id, t(integer())}
|
[ {gateway_id, t(integer())}
|
||||||
, {broadcast, t(boolean())}
|
, {broadcast, t(boolean())}
|
||||||
|
@ -76,12 +69,9 @@ fields(mqttsn_predefined) ->
|
||||||
, {topic, t(string())}
|
, {topic, t(string())}
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(lwm2m) ->
|
|
||||||
[{"$id", t(ref(lwm2m_structs))}
|
|
||||||
];
|
|
||||||
|
|
||||||
fields(lwm2m_structs) ->
|
fields(lwm2m_structs) ->
|
||||||
[ {lifetime_min, t(duration())}
|
[ {xml_dir, t(string())}
|
||||||
|
, {lifetime_min, t(duration())}
|
||||||
, {lifetime_max, t(duration())}
|
, {lifetime_max, t(duration())}
|
||||||
, {qmode_time_windonw, t(integer())}
|
, {qmode_time_windonw, t(integer())}
|
||||||
, {auto_observe, t(boolean())}
|
, {auto_observe, t(boolean())}
|
||||||
|
@ -91,9 +81,6 @@ fields(lwm2m_structs) ->
|
||||||
, {listener, t(ref(udp_listener_group))}
|
, {listener, t(ref(udp_listener_group))}
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(exproto) ->
|
|
||||||
[{"$id", t(ref(exproto_structs))}];
|
|
||||||
|
|
||||||
fields(exproto_structs) ->
|
fields(exproto_structs) ->
|
||||||
[ {server, t(ref(exproto_grpc_server))}
|
[ {server, t(ref(exproto_grpc_server))}
|
||||||
, {handler, t(ref(exproto_grpc_handler))}
|
, {handler, t(ref(exproto_grpc_handler))}
|
||||||
|
|
|
@ -22,22 +22,16 @@
|
||||||
|
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
|
|
||||||
%% Gateway Instance APIs
|
%% Gateway APIs
|
||||||
-export([ create_gateway_insta/1
|
-export([ load_gateway/1
|
||||||
, remove_gateway_insta/1
|
, unload_gateway/1
|
||||||
, lookup_gateway_insta/1
|
, lookup_gateway/1
|
||||||
, update_gateway_insta/1
|
, update_gateway/1
|
||||||
, start_gateway_insta/1
|
, start_gateway_insta/1
|
||||||
, stop_gateway_insta/1
|
, stop_gateway_insta/1
|
||||||
, list_gateway_insta/1
|
|
||||||
, list_gateway_insta/0
|
, list_gateway_insta/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Gateway APs
|
|
||||||
-export([ list_started_gateway/0
|
|
||||||
, stop_all_suptree/1
|
|
||||||
]).
|
|
||||||
|
|
||||||
%% supervisor callbacks
|
%% supervisor callbacks
|
||||||
-export([init/1]).
|
-export([init/1]).
|
||||||
|
|
||||||
|
@ -48,88 +42,71 @@
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
-spec create_gateway_insta(instance()) -> {ok, pid()} | {error, any()}.
|
|
||||||
create_gateway_insta(Insta = #{type := Type}) ->
|
-spec load_gateway(gateway()) -> {ok, pid()} | {error, any()}.
|
||||||
case emqx_gateway_registry:lookup(Type) of
|
load_gateway(Gateway = #{type := GwType}) ->
|
||||||
undefined -> {error, {unknown_gateway_id, Type}};
|
case emqx_gateway_registry:lookup(GwType) of
|
||||||
|
undefined -> {error, {unknown_gateway_type, GwType}};
|
||||||
GwDscrptr ->
|
GwDscrptr ->
|
||||||
{ok, GwSup} = ensure_gateway_suptree_ready(gatewayid(Type)),
|
{ok, GwSup} = ensure_gateway_suptree_ready(GwType),
|
||||||
emqx_gateway_gw_sup:create_insta(GwSup, Insta, GwDscrptr)
|
emqx_gateway_gw_sup:create_insta(GwSup, Gateway, GwDscrptr)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec remove_gateway_insta(instance_id()) -> ok | {error, any()}.
|
-spec unload_gateway(gateway_type()) -> ok | {error, not_found}.
|
||||||
remove_gateway_insta(InstaId) ->
|
unload_gateway(GwType) ->
|
||||||
case search_gateway_insta_proc(InstaId) of
|
case lists:keyfind(GwType, 1, supervisor:which_children(?MODULE)) of
|
||||||
{ok, {GwSup, _}} ->
|
false -> {error, not_found};
|
||||||
emqx_gateway_gw_sup:remove_insta(GwSup, InstaId);
|
|
||||||
_ ->
|
_ ->
|
||||||
|
_ = supervisor:terminate_child(?MODULE, GwType),
|
||||||
|
_ = supervisor:delete_child(?MODULE, GwType),
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec lookup_gateway_insta(instance_id()) -> instance() | undefined.
|
-spec lookup_gateway(gateway_type()) -> gateway() | undefined.
|
||||||
lookup_gateway_insta(InstaId) ->
|
lookup_gateway(GwType) ->
|
||||||
case search_gateway_insta_proc(InstaId) of
|
case search_gateway_insta_proc(GwType) of
|
||||||
{ok, {_, GwInstaPid}} ->
|
{ok, {_, GwInstaPid}} ->
|
||||||
emqx_gateway_insta_sup:info(GwInstaPid);
|
emqx_gateway_insta_sup:info(GwInstaPid);
|
||||||
_ ->
|
_ ->
|
||||||
undefined
|
undefined
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec update_gateway_insta(instance())
|
-spec update_gateway(gateway_type())
|
||||||
-> ok
|
-> ok
|
||||||
| {error, any()}.
|
| {error, any()}.
|
||||||
update_gateway_insta(NewInsta = #{type := Type}) ->
|
update_gateway(NewGateway = #{type := GwType}) ->
|
||||||
case emqx_gateway_utils:find_sup_child(?MODULE, gatewayid(Type)) of
|
case emqx_gateway_utils:find_sup_child(?MODULE, GwType) of
|
||||||
{ok, GwSup} ->
|
{ok, GwSup} ->
|
||||||
emqx_gateway_gw_sup:update_insta(GwSup, NewInsta);
|
emqx_gateway_gw_sup:update_insta(GwSup, NewGateway);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_gateway_insta(InstaId) ->
|
start_gateway_insta(GwType) ->
|
||||||
case search_gateway_insta_proc(InstaId) of
|
case search_gateway_insta_proc(GwType) of
|
||||||
{ok, {GwSup, _}} ->
|
{ok, {GwSup, _}} ->
|
||||||
emqx_gateway_gw_sup:start_insta(GwSup, InstaId);
|
emqx_gateway_gw_sup:start_insta(GwSup, GwType);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec stop_gateway_insta(instance_id()) -> ok | {error, any()}.
|
-spec stop_gateway_insta(gateway_type()) -> ok | {error, any()}.
|
||||||
stop_gateway_insta(InstaId) ->
|
stop_gateway_insta(GwType) ->
|
||||||
case search_gateway_insta_proc(InstaId) of
|
case search_gateway_insta_proc(GwType) of
|
||||||
{ok, {GwSup, _}} ->
|
{ok, {GwSup, _}} ->
|
||||||
emqx_gateway_gw_sup:stop_insta(GwSup, InstaId);
|
emqx_gateway_gw_sup:stop_insta(GwSup, GwType);
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec list_gateway_insta(gateway_type()) -> {ok, [instance()]} | {error, any()}.
|
-spec list_gateway_insta() -> [gateway()].
|
||||||
list_gateway_insta(Type) ->
|
|
||||||
case emqx_gateway_utils:find_sup_child(?MODULE, gatewayid(Type)) of
|
|
||||||
{ok, GwSup} ->
|
|
||||||
{ok, emqx_gateway_gw_sup:list_insta(GwSup)};
|
|
||||||
_ -> {error, not_found}
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec list_gateway_insta() -> [{gateway_type(), instance()}].
|
|
||||||
list_gateway_insta() ->
|
list_gateway_insta() ->
|
||||||
lists:map(
|
lists:append(lists:map(
|
||||||
fun(SupId) ->
|
fun(SupId) ->
|
||||||
Instas = emqx_gateway_gw_sup:list_insta(SupId),
|
emqx_gateway_gw_sup:list_insta(SupId)
|
||||||
{SupId, Instas}
|
end, list_started_gateway())).
|
||||||
end, list_started_gateway()).
|
|
||||||
|
|
||||||
-spec list_started_gateway() -> [gateway_type()].
|
-spec list_started_gateway() -> [gateway_type()].
|
||||||
list_started_gateway() ->
|
list_started_gateway() ->
|
||||||
started_gateway_type().
|
started_gateway_type().
|
||||||
|
|
||||||
-spec stop_all_suptree(atom()) -> ok.
|
|
||||||
stop_all_suptree(Type) ->
|
|
||||||
case lists:keyfind(Type, 1, supervisor:which_children(?MODULE)) of
|
|
||||||
false -> ok;
|
|
||||||
_ ->
|
|
||||||
_ = supervisor:terminate_child(?MODULE, Type),
|
|
||||||
_ = supervisor:delete_child(?MODULE, Type),
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% Supervisor callback
|
%% Supervisor callback
|
||||||
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
|
@ -145,17 +122,14 @@ init([]) ->
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
gatewayid(Type) ->
|
ensure_gateway_suptree_ready(GwType) ->
|
||||||
list_to_atom(lists:concat([Type])).
|
case lists:keyfind(GwType, 1, supervisor:which_children(?MODULE)) of
|
||||||
|
|
||||||
ensure_gateway_suptree_ready(Type) ->
|
|
||||||
case lists:keyfind(Type, 1, supervisor:which_children(?MODULE)) of
|
|
||||||
false ->
|
false ->
|
||||||
ChildSpec = emqx_gateway_utils:childspec(
|
ChildSpec = emqx_gateway_utils:childspec(
|
||||||
Type,
|
GwType,
|
||||||
supervisor,
|
supervisor,
|
||||||
emqx_gateway_gw_sup,
|
emqx_gateway_gw_sup,
|
||||||
[Type]
|
[GwType]
|
||||||
),
|
),
|
||||||
emqx_gateway_utils:supervisor_ret(
|
emqx_gateway_utils:supervisor_ret(
|
||||||
supervisor:start_child(?MODULE, ChildSpec)
|
supervisor:start_child(?MODULE, ChildSpec)
|
||||||
|
@ -190,4 +164,3 @@ started_gateway_pid() ->
|
||||||
|
|
||||||
is_a_gateway_id(Id) ->
|
is_a_gateway_id(Id) ->
|
||||||
Id /= emqx_gateway_registry.
|
Id /= emqx_gateway_registry.
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,13 @@
|
||||||
-behavior(emqx_gateway_impl).
|
-behavior(emqx_gateway_impl).
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ load/0
|
-export([ reg/0
|
||||||
, unload/0
|
, unreg/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([]).
|
-export([ on_gateway_load/2
|
||||||
|
, on_gateway_update/3
|
||||||
-export([ init/1
|
, on_gateway_unload/2
|
||||||
, on_insta_create/3
|
|
||||||
, on_insta_update/4
|
|
||||||
, on_insta_destroy/3
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
@ -38,24 +35,19 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load() ->
|
reg() ->
|
||||||
RegistryOptions = [ {cbkmod, ?MODULE}
|
RegistryOptions = [ {cbkmod, ?MODULE}
|
||||||
],
|
],
|
||||||
emqx_gateway_registry:load(exproto, RegistryOptions, []).
|
emqx_gateway_registry:reg(exproto, RegistryOptions).
|
||||||
|
|
||||||
unload() ->
|
|
||||||
emqx_gateway_registry:unload(exproto).
|
|
||||||
|
|
||||||
init(_) ->
|
|
||||||
GwState = #{},
|
|
||||||
{ok, GwState}.
|
|
||||||
|
|
||||||
|
unreg() ->
|
||||||
|
emqx_gateway_registry:unreg(exproto).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_grpc_server(InstaId, Options = #{bind := ListenOn}) ->
|
start_grpc_server(GwType, 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}
|
||||||
|
@ -65,10 +57,10 @@ start_grpc_server(InstaId, Options = #{bind := ListenOn}) ->
|
||||||
SslOpts ->
|
SslOpts ->
|
||||||
[{ssl_options, SslOpts}]
|
[{ssl_options, SslOpts}]
|
||||||
end,
|
end,
|
||||||
_ = grpc:start_server(InstaId, ListenOn, Services, SvrOptions),
|
_ = grpc:start_server(GwType, ListenOn, Services, SvrOptions),
|
||||||
?ULOG("Start ~s gRPC server on ~p successfully.~n", [InstaId, ListenOn]).
|
?ULOG("Start ~s gRPC server on ~p successfully.~n", [GwType, ListenOn]).
|
||||||
|
|
||||||
start_grpc_client_channel(InstaId, Options = #{address := UriStr}) ->
|
start_grpc_client_channel(GwType, 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),
|
||||||
|
@ -85,79 +77,79 @@ start_grpc_client_channel(InstaId, Options = #{address := UriStr}) ->
|
||||||
transport_opts => SslOpts}};
|
transport_opts => SslOpts}};
|
||||||
_ -> #{}
|
_ -> #{}
|
||||||
end,
|
end,
|
||||||
grpc_client_sup:create_channel_pool(InstaId, SvrAddr, ClientOpts).
|
grpc_client_sup:create_channel_pool(GwType, SvrAddr, ClientOpts).
|
||||||
|
|
||||||
on_insta_create(_Insta = #{ id := InstaId,
|
on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx, _GwState) ->
|
}, 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(InstaId),
|
PoolName = pool_name(GwType),
|
||||||
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(InstaId, maps:get(handler, RawConf)),
|
_ = start_grpc_client_channel(GwType, maps:get(handler, RawConf)),
|
||||||
|
|
||||||
%% XXX: How to monitor it ?
|
%% XXX: How to monitor it ?
|
||||||
_ = start_grpc_server(InstaId, maps:get(server, RawConf)),
|
_ = start_grpc_server(GwType, maps:get(server, RawConf)),
|
||||||
|
|
||||||
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 => InstaId}
|
NRawConf#{handler => GwType}
|
||||||
),
|
),
|
||||||
ListenerPids = lists:map(fun(Lis) ->
|
ListenerPids = lists:map(fun(Lis) ->
|
||||||
start_listener(InstaId, Ctx, Lis)
|
start_listener(GwType, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_insta_update(NewInsta, OldInsta, GwInstaState = #{ctx := Ctx}, GwState) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
InstaId = maps:get(id, NewInsta),
|
GwType = maps:get(type, 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 ???
|
||||||
on_insta_destroy(OldInsta, GwInstaState, GwState),
|
on_gateway_unload(OldGateway, GwState),
|
||||||
on_insta_create(NewInsta, Ctx, GwState)
|
on_gateway_load(NewGateway, Ctx)
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update exproto instance ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[InstaId, Class, Reason, Stk]),
|
[GwType, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_insta_destroy(_Insta = #{ id := InstaId,
|
on_gateway_unload(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwInstaState, _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(InstaId, Lis)
|
stop_listener(GwType, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
pool_name(InstaId) ->
|
pool_name(GwType) ->
|
||||||
list_to_atom(lists:concat([InstaId, "_gcli_pool"])).
|
list_to_atom(lists:concat([GwType, "_gcli_pool"])).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start exproto ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]),
|
[GwType, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start exproto ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason]),
|
[GwType, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_exproto_frame,
|
frame_mod => emqx_exproto_frame,
|
||||||
|
@ -176,8 +168,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(InstaId, Type) ->
|
name(GwType, Type) ->
|
||||||
list_to_atom(lists:concat([InstaId, ":", Type])).
|
list_to_atom(lists:concat([GwType, ":", Type])).
|
||||||
|
|
||||||
merge_default_by_type(Type, Options) when Type =:= tcp;
|
merge_default_by_type(Type, Options) when Type =:= tcp;
|
||||||
Type =:= ssl ->
|
Type =:= ssl ->
|
||||||
|
@ -200,18 +192,18 @@ merge_default_by_type(Type, Options) when Type =:= udp;
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(InstaId, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(InstaId, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwType, 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 exproto ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]);
|
[GwType, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop exproto ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason])
|
[GwType, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(InstaId, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -20,36 +20,37 @@
|
||||||
-behavior(emqx_gateway_impl).
|
-behavior(emqx_gateway_impl).
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ load/0
|
-export([ reg/0
|
||||||
, unload/0
|
, unreg/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([]).
|
-export([ on_gateway_load/2
|
||||||
|
, on_gateway_update/3
|
||||||
-export([ init/1
|
, on_gateway_unload/2
|
||||||
, on_insta_create/3
|
|
||||||
, on_insta_update/4
|
|
||||||
, on_insta_destroy/3
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load() ->
|
reg() ->
|
||||||
RegistryOptions = [ {cbkmod, ?MODULE}
|
RegistryOptions = [ {cbkmod, ?MODULE}
|
||||||
],
|
],
|
||||||
emqx_gateway_registry:load(lwm2m, RegistryOptions, []).
|
emqx_gateway_registry:reg(lwm2m, RegistryOptions).
|
||||||
|
|
||||||
unload() ->
|
unreg() ->
|
||||||
%% XXX:
|
emqx_gateway_registry:unreg(lwm2m).
|
||||||
lwm2m_coap_server_registry:remove_handler(
|
|
||||||
[<<"rd">>],
|
%%--------------------------------------------------------------------
|
||||||
emqx_lwm2m_coap_resource, undefined
|
%% emqx_gateway_registry callbacks
|
||||||
),
|
%%--------------------------------------------------------------------
|
||||||
emqx_gateway_registry:unload(lwm2m).
|
|
||||||
|
on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
|
rawconf := RawConf
|
||||||
|
}, Ctx) ->
|
||||||
|
|
||||||
init(_) ->
|
|
||||||
%% Handler
|
%% Handler
|
||||||
_ = lwm2m_coap_server:start_registry(),
|
_ = lwm2m_coap_server:start_registry(),
|
||||||
lwm2m_coap_server_registry:add_handler(
|
lwm2m_coap_server_registry:add_handler(
|
||||||
|
@ -57,75 +58,66 @@ init(_) ->
|
||||||
emqx_lwm2m_coap_resource, undefined
|
emqx_lwm2m_coap_resource, undefined
|
||||||
),
|
),
|
||||||
%% Xml registry
|
%% Xml registry
|
||||||
{ok, _} = emqx_lwm2m_xml_object_db:start_link(
|
{ok, _} = emqx_lwm2m_xml_object_db:start_link(maps:get(xml_dir, RawConf)),
|
||||||
emqx_config:get([gateway, lwm2m_xml_dir])
|
|
||||||
),
|
|
||||||
|
|
||||||
%% XXX: Self managed table?
|
%% XXX: Self managed table?
|
||||||
%% TODO: Improve it later
|
%% TODO: Improve it later
|
||||||
{ok, _} = emqx_lwm2m_cm:start_link(),
|
{ok, _} = emqx_lwm2m_cm:start_link(),
|
||||||
|
|
||||||
GwState = #{},
|
|
||||||
{ok, GwState}.
|
|
||||||
|
|
||||||
%% TODO: deinit
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% emqx_gateway_registry callbacks
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
on_insta_create(_Insta = #{ id := InstaId,
|
|
||||||
rawconf := RawConf
|
|
||||||
}, Ctx, _GwState) ->
|
|
||||||
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(InstaId, Ctx, Lis)
|
start_listener(GwType, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_insta_update(NewInsta, OldInsta, GwInstaState = #{ctx := Ctx}, GwState) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
InstaId = maps:get(id, NewInsta),
|
GwType = maps:get(type, 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 ???
|
||||||
on_insta_destroy(OldInsta, GwInstaState, GwState),
|
on_gateway_unload(OldGateway, GwState),
|
||||||
on_insta_create(NewInsta, Ctx, GwState)
|
on_gateway_load(NewGateway, Ctx)
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update stomp instance ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[InstaId, Class, Reason, Stk]),
|
[GwType, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_insta_destroy(_Insta = #{ id := InstaId,
|
on_gateway_unload(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwInstaState, _GwState) ->
|
}, _GwState) ->
|
||||||
|
%% XXX:
|
||||||
|
lwm2m_coap_server_registry:remove_handler(
|
||||||
|
[<<"rd">>],
|
||||||
|
emqx_lwm2m_coap_resource, undefined
|
||||||
|
),
|
||||||
|
|
||||||
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
Listeners = emqx_gateway_utils:normalize_rawconf(RawConf),
|
||||||
lists:foreach(fun(Lis) ->
|
lists:foreach(fun(Lis) ->
|
||||||
stop_listener(InstaId, Lis)
|
stop_listener(GwType, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
io:format("Start lwm2m ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]),
|
[GwType, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format(standard_error,
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
"Failed to start lwm2m ~s:~s listener on ~s: ~0p~n",
|
[GwType, Type, ListenOnStr, Reason]),
|
||||||
[InstaId, Type, ListenOnStr, Reason]),
|
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(InstaId, udp),
|
Name = name(GwType, 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],
|
||||||
|
@ -136,8 +128,8 @@ start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
lwm2m_coap_server:start_dtls(Name, ListenOn, Options)
|
lwm2m_coap_server:start_dtls(Name, ListenOn, Options)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
name(InstaId, Type) ->
|
name(GwType, Type) ->
|
||||||
list_to_atom(lists:concat([InstaId, ":", Type])).
|
list_to_atom(lists:concat([GwType, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_udp_options(),
|
Default = emqx_gateway_utils:default_udp_options(),
|
||||||
|
@ -149,22 +141,20 @@ merge_default(Options) ->
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(InstaId, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(InstaId, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwType, 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 -> io:format("Stop lwm2m ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]);
|
[GwType, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format(standard_error,
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
"Failed to stop lwm2m ~s:~s listener on ~s: ~0p~n",
|
[GwType, Type, ListenOnStr, Reason])
|
||||||
[InstaId, Type, ListenOnStr, Reason]
|
|
||||||
)
|
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(InstaId, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
case Type of
|
case Type of
|
||||||
udp ->
|
udp ->
|
||||||
lwm2m_coap_server:stop_udp(Name, ListenOn);
|
lwm2m_coap_server:stop_udp(Name, ListenOn);
|
||||||
|
|
|
@ -20,16 +20,13 @@
|
||||||
-behavior(emqx_gateway_impl).
|
-behavior(emqx_gateway_impl).
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ load/0
|
-export([ reg/0
|
||||||
, unload/0
|
, unreg/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([]).
|
-export([ on_gateway_load/2
|
||||||
|
, on_gateway_update/3
|
||||||
-export([ init/1
|
, on_gateway_unload/2
|
||||||
, on_insta_create/3
|
|
||||||
, on_insta_update/4
|
|
||||||
, on_insta_destroy/3
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
@ -38,25 +35,21 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
load() ->
|
reg() ->
|
||||||
RegistryOptions = [ {cbkmod, ?MODULE}
|
RegistryOptions = [ {cbkmod, ?MODULE}
|
||||||
],
|
],
|
||||||
emqx_gateway_registry:load(mqttsn, RegistryOptions, []).
|
emqx_gateway_registry:reg(mqttsn, RegistryOptions).
|
||||||
|
|
||||||
unload() ->
|
unreg() ->
|
||||||
emqx_gateway_registry:unload(mqttsn).
|
emqx_gateway_registry:unreg(mqttsn).
|
||||||
|
|
||||||
init(_) ->
|
|
||||||
GwState = #{},
|
|
||||||
{ok, GwState}.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_insta_create(_Insta = #{ id := InstaId,
|
on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx, _GwState) ->
|
}, Ctx) ->
|
||||||
|
|
||||||
%% We Also need to start `emqx_sn_broadcast` &
|
%% We Also need to start `emqx_sn_broadcast` &
|
||||||
%% `emqx_sn_registry` process
|
%% `emqx_sn_registry` process
|
||||||
|
@ -71,7 +64,7 @@ on_insta_create(_Insta = #{ id := InstaId,
|
||||||
end,
|
end,
|
||||||
|
|
||||||
PredefTopics = maps:get(predefined, RawConf),
|
PredefTopics = maps:get(predefined, RawConf),
|
||||||
{ok, RegistrySvr} = emqx_sn_registry:start_link(InstaId, PredefTopics),
|
{ok, RegistrySvr} = emqx_sn_registry:start_link(GwType, PredefTopics),
|
||||||
|
|
||||||
NRawConf = maps:without(
|
NRawConf = maps:without(
|
||||||
[broadcast, predefined],
|
[broadcast, predefined],
|
||||||
|
@ -80,52 +73,52 @@ on_insta_create(_Insta = #{ id := InstaId,
|
||||||
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(InstaId, Ctx, Lis)
|
start_listener(GwType, Ctx, Lis)
|
||||||
end, Listeners),
|
end, Listeners),
|
||||||
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_insta_update(NewInsta, OldInsta, GwInstaState = #{ctx := Ctx}, GwState) ->
|
on_gateway_update(NewGateway = #{type := GwType}, OldGateway,
|
||||||
InstaId = maps:get(id, NewInsta),
|
GwState = #{ctx := Ctx}) ->
|
||||||
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 ???
|
||||||
on_insta_destroy(OldInsta, GwInstaState, GwState),
|
on_gateway_unload(OldGateway, GwState),
|
||||||
on_insta_create(NewInsta, Ctx, GwState)
|
on_gateway_load(NewGateway, Ctx)
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update stomp instance ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[InstaId, Class, Reason, Stk]),
|
[GwType, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_insta_destroy(_Insta = #{ id := InstaId,
|
on_gateway_unload(_Insta = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwInstaState, _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(InstaId, Lis)
|
stop_listener(GwType, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start mqttsn ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]),
|
[GwType, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start mqttsn ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason]),
|
[GwType, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_sn_frame,
|
frame_mod => emqx_sn_frame,
|
||||||
|
@ -134,8 +127,8 @@ start_listener(InstaId, 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(InstaId, Type) ->
|
name(GwType, Type) ->
|
||||||
list_to_atom(lists:concat([InstaId, ":", Type])).
|
list_to_atom(lists:concat([GwType, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_udp_options(),
|
Default = emqx_gateway_utils:default_udp_options(),
|
||||||
|
@ -147,18 +140,18 @@ merge_default(Options) ->
|
||||||
[{udp_options, Default} | Options]
|
[{udp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(InstaId, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(InstaId, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwType, 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 mqttsn ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]);
|
[GwType, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop mqttsn ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason])
|
[GwType, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(InstaId, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -19,14 +19,13 @@
|
||||||
-behavior(emqx_gateway_impl).
|
-behavior(emqx_gateway_impl).
|
||||||
|
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([ load/0
|
-export([ reg/0
|
||||||
, unload/0
|
, unreg/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ init/1
|
-export([ on_gateway_load/2
|
||||||
, on_insta_create/3
|
, on_gateway_update/3
|
||||||
, on_insta_update/4
|
, on_gateway_unload/2
|
||||||
, on_insta_destroy/3
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("emqx_gateway/include/emqx_gateway.hrl").
|
-include_lib("emqx_gateway/include/emqx_gateway.hrl").
|
||||||
|
@ -36,79 +35,75 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-spec load() -> ok | {error, any()}.
|
-spec reg() -> ok | {error, any()}.
|
||||||
load() ->
|
reg() ->
|
||||||
RegistryOptions = [ {cbkmod, ?MODULE}
|
RegistryOptions = [ {cbkmod, ?MODULE}
|
||||||
],
|
],
|
||||||
emqx_gateway_registry:load(stomp, RegistryOptions, []).
|
emqx_gateway_registry:reg(stomp, RegistryOptions).
|
||||||
|
|
||||||
-spec unload() -> ok | {error, any()}.
|
-spec unreg() -> ok | {error, any()}.
|
||||||
unload() ->
|
unreg() ->
|
||||||
emqx_gateway_registry:unload(stomp).
|
emqx_gateway_registry:unreg(stomp).
|
||||||
|
|
||||||
init(_) ->
|
|
||||||
GwState = #{},
|
|
||||||
{ok, GwState}.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% emqx_gateway_registry callbacks
|
%% emqx_gateway_registry callbacks
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
on_insta_create(_Insta = #{ id := InstaId,
|
on_gateway_load(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, Ctx, _GwState) ->
|
}, 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(InstaId, Ctx, Lis)
|
start_listener(GwType, 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 InstaState
|
%% FIXME: Assign ctx to GwState
|
||||||
{ok, ListenerPids, _InstaState = #{ctx => Ctx}}.
|
{ok, ListenerPids, _GwState = #{ctx => Ctx}}.
|
||||||
|
|
||||||
on_insta_update(NewInsta, OldInsta, GwInstaState = #{ctx := Ctx}, GwState) ->
|
on_gateway_update(NewGateway, OldGateway, GwState = #{ctx := Ctx}) ->
|
||||||
InstaId = maps:get(id, NewInsta),
|
GwType = maps:get(type, 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 state???
|
||||||
on_insta_destroy(OldInsta, GwInstaState, GwState),
|
on_gateway_unload(OldGateway, GwState),
|
||||||
on_insta_create(NewInsta, Ctx, GwState)
|
on_gateway_load(NewGateway, Ctx)
|
||||||
catch
|
catch
|
||||||
Class : Reason : Stk ->
|
Class : Reason : Stk ->
|
||||||
logger:error("Failed to update stomp instance ~s; "
|
logger:error("Failed to update ~s; "
|
||||||
"reason: {~0p, ~0p} stacktrace: ~0p",
|
"reason: {~0p, ~0p} stacktrace: ~0p",
|
||||||
[InstaId, Class, Reason, Stk]),
|
[GwType, Class, Reason, Stk]),
|
||||||
{error, {Class, Reason}}
|
{error, {Class, Reason}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
on_insta_destroy(_Insta = #{ id := InstaId,
|
on_gateway_unload(_Gateway = #{ type := GwType,
|
||||||
rawconf := RawConf
|
rawconf := RawConf
|
||||||
}, _GwInstaState, _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(InstaId, Lis)
|
stop_listener(GwType, Lis)
|
||||||
end, Listeners).
|
end, Listeners).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal funcs
|
%% Internal funcs
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
start_listener(GwType, Ctx, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
ListenOnStr = emqx_gateway_utils:format_listenon(ListenOn),
|
||||||
case start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
case start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
?ULOG("Start stomp ~s:~s listener on ~s successfully.~n",
|
?ULOG("Start ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]),
|
[GwType, Type, ListenOnStr]),
|
||||||
Pid;
|
Pid;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to start stomp ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to start ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason]),
|
[GwType, Type, ListenOnStr, Reason]),
|
||||||
throw({badconf, Reason})
|
throw({badconf, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
start_listener(InstaId, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
start_listener(GwType, Ctx, Type, ListenOn, SocketOpts, Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
NCfg = Cfg#{
|
NCfg = Cfg#{
|
||||||
ctx => Ctx,
|
ctx => Ctx,
|
||||||
frame_mod => emqx_stomp_frame,
|
frame_mod => emqx_stomp_frame,
|
||||||
|
@ -117,8 +112,8 @@ start_listener(InstaId, 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(InstaId, Type) ->
|
name(GwType, Type) ->
|
||||||
list_to_atom(lists:concat([InstaId, ":", Type])).
|
list_to_atom(lists:concat([GwType, ":", Type])).
|
||||||
|
|
||||||
merge_default(Options) ->
|
merge_default(Options) ->
|
||||||
Default = emqx_gateway_utils:default_tcp_options(),
|
Default = emqx_gateway_utils:default_tcp_options(),
|
||||||
|
@ -130,18 +125,18 @@ merge_default(Options) ->
|
||||||
[{tcp_options, Default} | Options]
|
[{tcp_options, Default} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop_listener(InstaId, {Type, ListenOn, SocketOpts, Cfg}) ->
|
stop_listener(GwType, {Type, ListenOn, SocketOpts, Cfg}) ->
|
||||||
StopRet = stop_listener(InstaId, Type, ListenOn, SocketOpts, Cfg),
|
StopRet = stop_listener(GwType, 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 stomp ~s:~s listener on ~s successfully.~n",
|
ok -> ?ULOG("Stop ~s:~s listener on ~s successfully.~n",
|
||||||
[InstaId, Type, ListenOnStr]);
|
[GwType, Type, ListenOnStr]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ELOG("Failed to stop stomp ~s:~s listener on ~s: ~0p~n",
|
?ELOG("Failed to stop ~s:~s listener on ~s: ~0p~n",
|
||||||
[InstaId, Type, ListenOnStr, Reason])
|
[GwType, Type, ListenOnStr, Reason])
|
||||||
end,
|
end,
|
||||||
StopRet.
|
StopRet.
|
||||||
|
|
||||||
stop_listener(InstaId, Type, ListenOn, _SocketOpts, _Cfg) ->
|
stop_listener(GwType, Type, ListenOn, _SocketOpts, _Cfg) ->
|
||||||
Name = name(InstaId, Type),
|
Name = name(GwType, Type),
|
||||||
esockd:close(Name, ListenOn).
|
esockd:close(Name, ListenOn).
|
||||||
|
|
|
@ -67,18 +67,17 @@ set_special_cfg(emqx_gateway) ->
|
||||||
LisType = get(grpname),
|
LisType = get(grpname),
|
||||||
emqx_config:put(
|
emqx_config:put(
|
||||||
[gateway, exproto],
|
[gateway, exproto],
|
||||||
#{'1' =>
|
|
||||||
#{authenticator => allow_anonymous,
|
#{authenticator => allow_anonymous,
|
||||||
server => #{bind => 9100},
|
server => #{bind => 9100},
|
||||||
handler => #{address => "http://127.0.0.1:9001"},
|
handler => #{address => "http://127.0.0.1:9001"},
|
||||||
listener => listener_confs(LisType)
|
listener => listener_confs(LisType)
|
||||||
}});
|
});
|
||||||
set_special_cfg(_App) ->
|
set_special_cfg(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
listener_confs(Type) ->
|
listener_confs(Type) ->
|
||||||
Default = #{bind => 7993, acceptors => 8},
|
Default = #{bind => 7993, acceptors => 8},
|
||||||
#{Type => #{'1' => maps:merge(Default, maps:from_list(socketopts(Type)))}}.
|
#{Type => maps:merge(Default, maps:from_list(socketopts(Type)))}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Tests cases
|
%% Tests cases
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
-define(CONF_DEFAULT, <<"""
|
-define(CONF_DEFAULT, <<"""
|
||||||
gateway: {
|
gateway: {
|
||||||
stomp.1 {}
|
stomp {}
|
||||||
}
|
}
|
||||||
""">>).
|
""">>).
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
|
|
||||||
-define(CONF_DEFAULT, <<"
|
-define(CONF_DEFAULT, <<"
|
||||||
gateway: {
|
gateway: {
|
||||||
lwm2m_xml_dir: \"../../lib/emqx_gateway/src/lwm2m/lwm2m_xml\"
|
lwm2m: {
|
||||||
lwm2m.1: {
|
xml_dir: \"../../lib/emqx_gateway/src/lwm2m/lwm2m_xml\"
|
||||||
lifetime_min: 1s
|
lifetime_min: 1s
|
||||||
lifetime_max: 86400s
|
lifetime_max: 86400s
|
||||||
qmode_time_windonw: 22
|
qmode_time_windonw: 22
|
||||||
|
|
|
@ -51,9 +51,9 @@
|
||||||
-define(CLIENTID, iolist_to_binary([atom_to_list(?FUNCTION_NAME), "-",
|
-define(CLIENTID, iolist_to_binary([atom_to_list(?FUNCTION_NAME), "-",
|
||||||
integer_to_list(erlang:system_time())])).
|
integer_to_list(erlang:system_time())])).
|
||||||
|
|
||||||
-define(CONF_DEFAULT, <<"""
|
-define(CONF_DEFAULT, <<"
|
||||||
gateway: {
|
gateway: {
|
||||||
mqttsn.1: {
|
mqttsn: {
|
||||||
gateway_id: 1
|
gateway_id: 1
|
||||||
broadcast: true
|
broadcast: true
|
||||||
enable_stats: true
|
enable_stats: true
|
||||||
|
@ -73,7 +73,7 @@ gateway: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""">>).
|
">>).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Setups
|
%% Setups
|
||||||
|
@ -90,35 +90,6 @@ init_per_suite(Config) ->
|
||||||
end_per_suite(_) ->
|
end_per_suite(_) ->
|
||||||
emqx_ct_helpers:stop_apps([emqx_gateway]).
|
emqx_ct_helpers:stop_apps([emqx_gateway]).
|
||||||
|
|
||||||
set_special_confs(emqx_gateway) ->
|
|
||||||
emqx_config:put(
|
|
||||||
[gateway],
|
|
||||||
#{ mqttsn =>
|
|
||||||
#{'1' =>
|
|
||||||
#{broadcast => true,
|
|
||||||
clientinfo_override =>
|
|
||||||
#{password => "pw123",
|
|
||||||
username => "user1"
|
|
||||||
},
|
|
||||||
enable_qos3 => true,
|
|
||||||
enable_stats => true,
|
|
||||||
gateway_id => 1,
|
|
||||||
idle_timeout => 30000,
|
|
||||||
listener =>
|
|
||||||
#{udp =>
|
|
||||||
#{'1' =>
|
|
||||||
#{acceptors => 8,active_n => 100,backlog => 1024,bind => 1884,
|
|
||||||
high_watermark => 1048576,max_conn_rate => 1000,
|
|
||||||
max_connections => 10240000,send_timeout => 15000,
|
|
||||||
send_timeout_close => true}}},
|
|
||||||
predefined =>
|
|
||||||
[#{id => ?PREDEF_TOPIC_ID1, topic => ?PREDEF_TOPIC_NAME1},
|
|
||||||
#{id => ?PREDEF_TOPIC_ID2, topic => ?PREDEF_TOPIC_NAME2}]}}
|
|
||||||
});
|
|
||||||
|
|
||||||
set_special_confs(_App) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Test cases
|
%% Test cases
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
-define(PREDEF_TOPICS, [#{id => 1, topic => <<"/predefined/topic/name/hello">>},
|
-define(PREDEF_TOPICS, [#{id => 1, topic => <<"/predefined/topic/name/hello">>},
|
||||||
#{id => 2, topic => <<"/predefined/topic/name/nice">>}]).
|
#{id => 2, topic => <<"/predefined/topic/name/nice">>}]).
|
||||||
|
|
||||||
-define(INSTA_ID, 'mqttsn#1').
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Setups
|
%% Setups
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -45,7 +43,7 @@ end_per_suite(_Config) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
init_per_testcase(_TestCase, Config) ->
|
init_per_testcase(_TestCase, Config) ->
|
||||||
{ok, Pid} = ?REGISTRY:start_link(?INSTA_ID, ?PREDEF_TOPICS),
|
{ok, Pid} = ?REGISTRY:start_link('mqttsn', ?PREDEF_TOPICS),
|
||||||
{Tab, Pid} = ?REGISTRY:lookup_name(Pid),
|
{Tab, Pid} = ?REGISTRY:lookup_name(Pid),
|
||||||
[{reg, {Tab, Pid}} | Config].
|
[{reg, {Tab, Pid}} | Config].
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
|
|
||||||
-define(HEARTBEAT, <<$\n>>).
|
-define(HEARTBEAT, <<$\n>>).
|
||||||
|
|
||||||
-define(CONF_DEFAULT, <<"""
|
-define(CONF_DEFAULT, <<"
|
||||||
gateway: {
|
gateway: {
|
||||||
stomp.1: {
|
stomp: {
|
||||||
clientinfo_override: {
|
clientinfo_override: {
|
||||||
username: \"${Packet.headers.login}\"
|
username: \"${Packet.headers.login}\"
|
||||||
password: \"${Packet.headers.passcode}\"
|
password: \"${Packet.headers.passcode}\"
|
||||||
|
@ -35,7 +35,7 @@ gateway: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""">>).
|
">>).
|
||||||
|
|
||||||
all() -> emqx_ct:all(?MODULE).
|
all() -> emqx_ct:all(?MODULE).
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue