Current section
Files
Jump to
Current section
Files
src/gpb_rpc_compile.erl
-module(gpb_rpc_compile).
-include_lib("gpb/include/gpb.hrl").
-define(rpc_data(Input, InputUpper, Output, OutputUpper, Func, BaseData),
[
{input, Input}, {input_upper, InputUpper},
{output, Output}, {output_upper, OutputUpper},
{handle_func, Func} | BaseData
]).
-define(input_data(Input, InputUpper, Func, BaseData), [
{input, Input}, {input_upper, InputUpper},
{handle_func, Func} | BaseData
]).
-define(output_data(Output, OutputUpper, BaseData),
[
{output, Output}, {output_upper, OutputUpper} | BaseData
]).
%% API
-export([file/4]).
file(ProtoFile, ErlTpl, HrlTpl, GpbRpcOpts) ->
SourceDirsOpts = proplists:lookup_all(i, GpbRpcOpts),
{ok, Binary} = file:read_file(ProtoFile),
String = binary_to_list(Binary),
case gpb_compile:string(mod, String, [to_proto_defs | SourceDirsOpts]) of
{ok, Defs} ->
ProtoName = filename:rootname(filename:basename(ProtoFile)),
file(ProtoName, ErlTpl, HrlTpl, GpbRpcOpts, Defs);
Err -> Err
end.
file(ProtoName, ErlTpl, HrlTpl, GpbRpcOpts, Defs) ->
ModuleNameSuffix = proplists:get_value(module_name_suffix, GpbRpcOpts),
PrefixLen = length(proplists:get_value(msg_prefix, GpbRpcOpts)),
ModPrefix = proplists:get_value(mod_prefix, GpbRpcOpts),
TargetHrlDir = proplists:get_value(o_hrl, GpbRpcOpts),
HrlTarget = filename:join([TargetHrlDir, ProtoName ++ ".hrl"]),
Head = <<"%% -*- coding: utf-8 -*-\n%% Automatically generated, do not edit\n%% Generated by gpb_rpc_compile\n">>,
case {gen_mod(ProtoName, ModuleNameSuffix, PrefixLen, ModPrefix, Defs),
gen_hrl(ProtoName, Defs)} of
{skip, HrlRenderData} ->
HrlIoData = bbmustache:compile(HrlTpl, HrlRenderData, [{key_type, atom}]),
ok = file:write_file(HrlTarget, [Head, HrlIoData]),
rebar_api:debug("skipped gen gpb rpc : ~p", [ProtoName]);
{ErlRenderData, HrlRenderData} ->
HrlIoData = bbmustache:compile(HrlTpl, HrlRenderData, [{key_type, atom}]),
ok = file:write_file(HrlTarget, [Head, HrlIoData]),
TargetErlDir = proplists:get_value(o_erl, GpbRpcOpts),
ErlTarget = filename:join([TargetErlDir, ProtoName ++ ".erl"]),
ErlIoData = bbmustache:compile(ErlTpl, ErlRenderData, [{key_type, atom}]),
ok = file:write_file(ErlTarget, [Head, ErlIoData])
end,
ok.
%%--------------------------------------------------------------------
gen_mod(ProtoName, ModuleNameSuffix, PrefixLen, ModPrefix, ScanProtoResult) ->
Service = list_to_atom(ProtoName ++ "_service"),
case lists:keyfind({service, Service}, 1, ScanProtoResult) of
{_, RpcList} ->
gen_mod_do(ProtoName, ModuleNameSuffix, PrefixLen, ModPrefix, RpcList);
false -> skip
end.
gen_mod_do(ProtoName, ModuleNameSuffix, PrefixLen, ModPrefix, RpcList0) ->
GpbProto = ProtoName ++ ModuleNameSuffix,
HandleMod = ModPrefix ++ string:substr(ProtoName, PrefixLen + 1),
ProtoNameUpper = string:to_upper(ProtoName),
BaseData = [
{proto_name, ProtoName},
{proto_name_upper, ProtoNameUpper},
{gpb_proto, GpbProto},
{handle_mod, HandleMod}
],
{CallbackList, RpcList, InputList, OutputList, _} =
lists:foldl(
fun(Rpc, Acc) ->
erl_rpc(Rpc, Acc, BaseData)
end, {[], [], [], [], []}, RpcList0),
[
{proto_name, ProtoName},
{proto_name_upper, ProtoNameUpper},
{gpb_proto, GpbProto},
{handle_mod, HandleMod},
{callback_list, lists:reverse(CallbackList)},
{rpc_list, lists:reverse(RpcList)},
{input_list, lists:reverse(InputList)},
{output_list, lists:reverse(OutputList)} | BaseData
].
erl_rpc(#?gpb_rpc{input = Input, output = Output0},
{CallbackList, RpcList, InputList, OutputList, OutputNames}, BaseData)
when (Input =:= 'Empty' orelse Input =:= undefined)
andalso Output0 =/= 'Empty' andalso Output0 =/= undefined ->
Output = atom_to_list(Output0),
case lists:member(Output0, OutputNames) of
true ->
{
CallbackList,
RpcList,
InputList,
OutputList,
OutputNames
};
false ->
OutputUpper = string:to_upper(Output),
OutputData = ?output_data(Output, OutputUpper, BaseData),
{
CallbackList,
RpcList,
InputList,
[OutputData | OutputList],
[Output0 | OutputNames]
}
end;
erl_rpc(#?gpb_rpc{name = Func0, input = Input0, output = Output},
{CallbackList, RpcList, InputList, OutputList, OutputNames}, BaseData)
when (Output =:= 'Empty' orelse Output =:= undefined)
andalso Input0 =/= 'Empty' andalso Input0 =/= undefined ->
Func = atom_to_list(Func0),
Input = atom_to_list(Input0),
InputUpper = string:to_upper(Input),
NewCallbackList = [[{handle_func, Func}] | CallbackList],
InputData = ?input_data(Input, InputUpper, Func, BaseData),
{
NewCallbackList,
RpcList,
[InputData | InputList],
OutputList,
OutputNames
};
erl_rpc(#?gpb_rpc{name = Func0, input = Input0, output = Output0},
{CallbackList, RpcList, InputList, OutputList, OutputNames}, BaseData)
when Input0 =/= 'Empty' andalso Input0 =/= undefined
andalso Output0 =/= 'Empty' andalso Output0 =/= undefined ->
Func = atom_to_list(Func0),
Input = atom_to_list(Input0),
InputUpper = string:to_upper(Input),
Output = atom_to_list(Output0),
OutputUpper = string:to_upper(Output),
NewCallbackList = [[{handle_func, Func}] | CallbackList],
RpcData = ?rpc_data(Input, InputUpper, Output, OutputUpper, Func, BaseData),
case lists:member(Output0, OutputNames) of
true ->
{
NewCallbackList,
[RpcData | RpcList],
InputList,
OutputList,
OutputNames
};
false ->
OutputData = ?output_data(Output, OutputUpper, BaseData),
{
NewCallbackList,
[RpcData | RpcList],
InputList,
[OutputData | OutputList],
[Output0 | OutputNames]
}
end.
%%--------------------------------------------------------------------
gen_hrl(ProtoName, Result) ->
ProtoNameUpper = string:to_upper(ProtoName),
BaseData = [
{proto_name, ProtoName},
{proto_name_upper, ProtoNameUpper}
],
EnumsList = [hrl_enums_list(EnumName, EnumList, BaseData) || {{enum, EnumName}, EnumList} <- Result],
[{enums_list, EnumsList} | BaseData].
hrl_enums_list(EnumName, EnumList0, BaseData0) ->
EnumNameUpper = string:to_upper(atom_to_list(EnumName)),
BaseData = [
{enum_name, EnumName},
{enum_name_upper, EnumNameUpper} | BaseData0
],
EnumList = [hrl_enum(EnumKey, EnumValue, BaseData) || {EnumKey, EnumValue} <- EnumList0],
[
{enum_list, EnumList} | BaseData
].
hrl_enum(EnumKey, EnumValue, BaseData) ->
EnumKeyUpper = string:to_upper(atom_to_list(EnumKey)),
[
{enum_key, EnumKey},
{enum_key_upper, EnumKeyUpper},
{enum_value, EnumValue} | BaseData
].