-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 ].