插件机制
目录结构
rebar3插件目录结构如下:
dgiot
|——lib
|-dgiot_demoplugin
|- ebin
|- dgiot_demopugin.app
- dgiot_demoplugin.beam
- dgiot_demoplugin_app.beam
- dgiot_demoplugin_sup.beam
- dgiot_demonplugin_channel.beam
- dgiot_demonplugin_handler.beam
-dgiot_otherplugin
|- ebin
|- dgiot_otherplugin.app
- dgiot_otherplugin.beam
- dgiot_otherplugin_app.beam
- dgiot_otherplugin_sup.beam
- dgiot_otherplugin_channel.beam
- dgiot_otherplugin_handler.beam
示例代码
%%%-------------------------------------------------------------------
%%% @author johnliu
%%% @copyright (C) 2021,
%%% @doc
%%%
%%% @end
%%% Created : 24. 3月 2021 10:17
%%%-------------------------------------------------------------------
-module(dgiot_demonplugin_channel).
-author("johnliu").
-behavior(dgiot_channelx).
-include("dgiot_demonplugin.hrl").
-define(TYPE, <<"demonplugin">>).
-record(state, {id}).
%% API
-export([
start/2
]).
%% Channel callback
-export([init/3, handle_init/1, handle_event/3, handle_message/2, stop/3]).
-channel(?TYPE).
-channel_type(#{
type => 1,
title => #{
zh => <<"demonplugin通道"/utf8>>
},
description => #{
zh => <<"demonplugin通道"/utf8>>
}
}).
%% 注册通道参数
-params(#{
<<"port">> => #{
order => 2,
type => integer,
required => true,
default => 51889,
title => #{
zh => <<"服务器端口"/utf8>>
},
description => #{
zh => <<"服务器端口"/utf8>>
}
}
}).
start(ChannelId, ChannelArgs) ->
dgiot_channelx:add(?TYPE, ChannelId, ?MODULE, ChannelArgs).
%% 通道初始化
init(?TYPE, ChannelId, Args) ->
#{
<<"ip">> := Ip,
<<"port">> := Port,
<<"total">> := Total} = Args,
do_something(<<"hello plugin">>),
State = #state{
id = ChannelId
},
{ok, State, []}.
handle_init(State) ->
{ok, State}.
%% 通道消息处理,注意:进程池调用
handle_event(_EventId, Event, State) ->
lager:info("channel ~p", [Event]),
{ok, State}.
handle_message(_Message, State) ->
{ok, State}.
stop(ChannelType, ChannelId, _State) ->
ok.
do_something(Msg) ->
io:format("Msg ~p",[Msg]).
加载机制
- 搜索到所有已经加载的插件
application:loaded_applications() - 通过App名称搜索ebin下面所有的beam文件
file:list_dir(Dir) - 搜素对应beam文件内的attributes是否包含channel
Mod:module_info(attributes) - 如果有channele的attributes则启动插件
Mod:start(ChannelId, ChannelArgs)
示例代码如下:
%%%-------------------------------------------------------------------
%%% @author johnliu
%%% @copyright (C) 2019,
%%% @doc
%%%
%%% @end
%%% Created : 06. 八月 2019 18:00
%%%-------------------------------------------------------------------
-module(dgiot_plugin).
-author("johnliu").
-define(SYS_APP, [
kernel, stdlib, sasl
]).
-export([start/0])
start() ->
check_module(
fun({_App, _Vsn, Mod}, Acc) ->
case code:is_loaded(Mod) =/= false of
true ->
case lists:keyfind(channel, 1, Mod:module_info(attributes)) of
false ->
Acc;
{channel, ChannelTypes} ->
do_somthing()
end;
false ->
Acc
end
end, []).
check_module(Check, Acc0) ->
Fun =
fun({App, _Desc, Vsn}, Acc) ->
Dir = lists:concat(["lib/", App, "-", Vsn, "/ebin"]),
case not lists:member(App, ?SYS_APP) andalso file:list_dir(Dir) of
{ok, FS} ->
lists:foldl(
fun(FileName, Acc1) ->
case filename:extension(FileName) == ".beam" of
true ->
Mod = list_to_atom(filename:basename(FileName, ".beam")),
Check({App, Vsn, Mod}, Acc1);
false ->
Acc1
end
end, Acc, FS);
_ ->
Acc
end
end,
lists:foldl(Fun, Acc0, application:loaded_applications()).
do_somthing() ->
ok
开源代码下载:https://gitee.com/dgiiot/dgiot
有问反馈给我们 https://gitee.com/dgiiot/dgiot/issues