%%---------------------------------------------------- %% 协议生成工具 %% @author yeahoo2000@gmail.com %% @end %%---------------------------------------------------- -module(main). -export([ compile/1 ,compile/2 ] ). -include("common.hrl"). -include("protocol.hrl"). -include("condition.hrl"). -define(SRV_PATH, "../../server/src/proto/"). -define(CLI_PATH, "./cli/"). %% -define(SRV_PATH, "./out/"). compile(all) -> compile(all, release). compile(all, CType) -> io:setopts([{encoding,unicode}]), ?P("---------------------------------~n"), ?P("> 正在生成协议...~n"), ?P("---------------------------------~n"), List = cfg_file(), put(rpc, []), put(desc_fun, []), put(log_title, []), put(log_data, []), put(lua_send, []), put(lua_recv, []), put(js_send, []), put(js_recv, []), all(List, CType), gen_rpc_cfg(), gen_lua(), gen_js(), ?P("> 所有协议已生成~n"), ok; compile(Name, CType) -> ?P("===========~s~n", [Name]), put(compile_type, CType), Mod = list_to_atom(Name), Info = Mod:info(), L = Mod:cfg(), [gen_js_pack(Rpc) || Rpc <- L], [gen_js_unpack(Rpc) || Rpc <- L], [gen_lua_pack(Rpc) || Rpc <- L], [gen_lua_unpack(Rpc) || Rpc <- L], %% spawn_link(fun() -> gen_as_cmd(L) end), gen_srv_proto(Mod, Info, L), rpc_cfg(L), ok. %% 处理所有命令 all([], _CType) -> ok; all([H | T], CType) -> compile(H, CType), all(T, CType). gen_srv_proto(Mod, {Description, IncFiles}, L) -> Inc = ["\n-include(\"" ++ X ++ "\")." || X <- IncFiles], Pack = lists:concat([gen_erl_pack(cli, Code, ReqFields) ++ gen_erl_pack(srv, Code, ReplyFields) || #rpc{code = Code, req = ReqFields, reply = ReplyFields} <- L]), Unpack = lists:concat([gen_erl_unpack(srv, Code, ReqFields) ++ gen_erl_unpack(cli, Code, ReplyFields) || #rpc{code = Code, req = ReqFields, reply = ReplyFields} <- L]), PackMate = lists:concat([gen_erl_pack_mate(Code, ReplyFields) || #rpc{code = Code, reply = ReplyFields = [_ | _]} <- L, lists:member(Code, [20000, 20002, 20004, 20020, 20027])]), ConvertData = lists:concat([gen_erl_convert_data(Code, ReplyFields) || #rpc{code = Code, reply = ReplyFields} <- L, lists:member(Code, [20000,20002,20004, 20020,20027])]), Vars = [ {description, Description} ,{include_file, Inc} ,{mod_name, Mod} ,{pack_fun, Pack} ,{unpack_fun, Unpack} ,{pack_mate_fun, unicode:characters_to_binary(PackMate)} ,{convert_data, ConvertData} ], Text = cn_str(util:template("./tpl/server.tpl.erl", cn_vars(Vars))), case file:write_file(lists:concat([?SRV_PATH, Mod, ".erl"]), Text) of ok -> ok; %% ?P("> ~ts.erl~n", [Mod]); Err -> ?P("生成协议[~ts]时发生异常: ~w~n", [Mod, Err]) end. %% 保存rpc_cfg内容 gen_rpc_cfg() -> Vars = [{rpc, lists:reverse(get(rpc))}, {desc_fun, lists:reverse(get(desc_fun))}, {log_title, lists:reverse(get(log_title))}, {log_data, lists:reverse(get(log_data))}], Text = cn_str(util:template("./tpl/rpc_cfg.tpl.erl", cn_vars(Vars))), case file:write_file(lists:concat([?SRV_PATH, "rpc_cfg.erl"]), Text) of ok -> ?P("> rpc_cfg.erl~n"); Err -> ?P("生成rpc_cfg.erl时发生异常: ~w~n", [Err]) end. %% 保存lua文件 gen_lua() -> Vars = [ {lua_send, string:join(lists:reverse(get(lua_send)), ",\n")} ,{lua_recv, string:join(lists:reverse(get(lua_recv)), ",\n")} ], Text = cn_str(util:template("./tpl/client.tpl.lua", cn_vars(Vars))), case file:write_file(lists:concat([?CLI_PATH, "proto_mate.lua"]), Text) of ok -> ?P("> proto_mate.lua~n"); Err -> ?P("生成proto_mate.lua时发生异常: ~w~n", [Err]) end. %% 保存js文件 gen_js() -> Vars = [ {js_send, string:join(lists:reverse(get(js_send)), ",\n")} ,{js_recv, string:join(lists:reverse(get(js_recv)), ",\n")} ], Text = cn_str(util:template("./tpl/client.tpl.js", cn_vars(Vars))), case file:write_file(lists:concat([?CLI_PATH, "proto_mate.js"]), Text) of ok -> ?P("> proto_mate.js~n"); Err -> ?P("生成proto_mate.js时发生异常: ~w~n", [Err]) end. cn_vars(Vars) -> [{K, unicode:characters_to_binary(util:to_list(V))} || {K, V} <- Vars]. cn_str(Str) -> unicode:characters_to_binary(unicode:characters_to_list(list_to_bitstring(Str))). %% 生成rpc配置内容 rpc_cfg([]) -> ok; rpc_cfg([H | T]) -> do_rpc_cfg(H), rpc_cfg(T). do_rpc_cfg(Rpc = #rpc{log_title = LogTitle, code = Code, req = ReqFields, req_desc = ReqDesc, reply = ReplyFields, reply_desc = ReplyDesc}) -> put(code, Code), R = Rpc#rpc{ req_desc = {rpc_cfg, desc_fun, {req, Code}} ,log_title = undefined ,req = undefined ,reply_desc = {rpc_cfg, desc_fun, {reply, Code}} ,reply = undefined }, case is_list(ReqFields) of true when LogTitle =:= undefined orelse LogTitle =:= "" -> %% ?P("协议号[~w]允许请求但日志标题[log_title]为空,请填写日志标题[log_title]~n", [Code]); ok; true -> case put({log_title, LogTitle}, 1) of undefined -> skip; _ -> ?P("协议号[~w]日志标题[log_title]出现重复值: ~ts~n", [Code, LogTitle]) end; _ -> skip end, S = lists:concat(["get(", Code, ") ->\n", s(1), util:to_string(R), ";\n\n"]), put(rpc, [S | get(rpc)]), case ReqDesc of [_ | _] -> F1 = lists:concat(["desc_fun({req, ", Code, "}, _Data)-> ", cdesc(ReqDesc, ReqFields), ";\n"]), put(desc_fun, [F1 | get(desc_fun)]); _ -> skip end, case ReplyDesc of [_ | _] -> F2 = lists:concat(["desc_fun({reply, ", Code, "}, _Data)-> ", cdesc(ReplyDesc, ReplyFields), ";\n"]), put(desc_fun, [F2 | get(desc_fun)]); _ -> skip end, case LogTitle of [_ | _] -> LTitle = lists:concat(["log_title(", Code, ", _Data)-> ", cdesc(LogTitle, []), ";\n"]), put(log_title, [LTitle | get(log_title)]); _ -> skip end, case gen_log_data(ReqFields, 1, "", "", false) of {ok, D1, D2} -> LData = lists:concat(["log_data(", Code, ", ", D1, ") -> ", D2, ";\n"]), put(log_data, [LData | get(log_data)]); _ -> skip end. gen_log_data([], _N, DL1, DL2, true) -> {ok, "{" ++ string:join(lists:reverse(DL1), ", ") ++ "}", "{" ++ string:join(lists:reverse(DL2), ", ") ++ "}"}; gen_log_data([{string, _, _} | T], N, DL1, DL2, _Flag) -> V = lists:concat(["_V", N]), gen_log_data(T, N + 1, [V | DL1], DL2, true); gen_log_data([_ | T], N, DL1, DL2, Flag) -> V = lists:concat(["V", N]), gen_log_data(T, N + 1, [V | DL1], [V | DL2], Flag); gen_log_data(_, _N, _DL1, _DL2, _Flag) -> false. %% record_to_string(L, Rec) -> %% S = r2s(L, []), %% lists:concat(["#", Rec, "{", S, "}"]). %% %% r2s([], Str) -> t(lists:concat(lists:reverse(Str))); %% r2s([{K, V} | T], Str) -> %% S = lists:concat([K, " = ", V, ", "]), %% r2s(T, [S | Str]). %% 生成日志格式化代码 cdesc(undefined, _) -> "\"\""; cdesc({Desc, Vars}, Fields) -> V = vals(Vars, Fields, []), lists:concat(["io_lib:format(\"", Desc, "\", [", V, "])"]); cdesc(Desc, _) -> lists:concat(["\"", Desc, "\""]). %% 生成取值代码 vals([], _F, L) -> string:join(lists:reverse(L), ", "); vals([N | T], F, L) -> P = pos(F, 1, N), vals(T, F, [?S("element(~w, _Data)", [P]) | L]). %% 定位某项在list中的位置 pos([], _P, N) -> ?ERR("[Code: ~w]的desc项配置有误,没有找到对应的项[~ts]", [get(code), N]), exit(error); pos([{_, N, _} | _T], P, N) -> P; pos([{_, N, _, _} | _T], P, N) -> P; pos([{_, _, N, _, _} | _T], P, N) -> P; pos([_ | T], P, N) -> pos(T, P + 1, N). %% 生成打包函数 gen_erl_pack(_Type, _Code, undefined) -> %% 不支持请求的协议 ""; gen_erl_pack(Type, Code, []) -> lists:concat(["\n\npack(", Code, ", ", Type, ", {}) ->\n", s(1), "{ok, <<2:32, ", Code, ":16>>};"]); gen_erl_pack(Type, Code, {RecordName, Fields}) -> put(code, Code), Vars = lists:concat(["#", RecordName, "{", vr(Fields, 0), "}"]), reset_var(0), Txt = erl_pack(Fields, 0, []), lists:concat(["\n\npack(", Code, ", ", Type, ", ", Vars, ") ->\n", s(1), "D_a_t_a = ", Txt, ",\n", s(1),"{ok, <<(byte_size(D_a_t_a) + 2):32, ", Code, ":16, D_a_t_a/binary>>};"]); gen_erl_pack(Type, Code, Fields) -> put(code, Code), reset_var(0), Txt = erl_pack(Fields, 0, []), Vars = "{" ++ v(Fields, 0) ++ "}", lists:concat(["\n\npack(", Code, ", ", Type, ", ", Vars, ") ->\n", s(1), "D_a_t_a = ", Txt, ",\n", s(1),"{ok, <<(byte_size(D_a_t_a) + 2):32, ", Code, ":16, D_a_t_a/binary>>};"]). %% 处理record项 erl_pack([], _Deep, Vars) -> V = t(lists:concat(lists:reverse(Vars))), "<<" ++ V ++ ">>"; erl_pack([{int8, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":8/signed, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{uint8, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":8, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{int16, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":16/signed, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{uint16, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":16, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{int32, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":32/signed, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{uint32, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, ":32, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{float, N, _} | T], Deep, Vars) -> add_var(Deep, N), V = lists:concat(["V", Deep, "_", N, "/float, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{binary, N, _} | T], Deep, Vars) -> add_var(Deep, N), X = lists:concat(["V", Deep, "_", N]), V = lists:concat(["(protocol:pack(binary, ", X, "))/binary, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{string, N, _} | T], Deep, Vars) -> add_var(Deep, N), X = lists:concat(["V", Deep, "_", N]), V = lists:concat(["(protocol:pack(string, ", X, "))/binary, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{byte, N, _} | T], Deep, Vars) -> add_var(Deep, N), X = lists:concat(["V", Deep, "_", N]), V = lists:concat(["(protocol:pack(byte, ", X, "))/binary, "]), erl_pack(T, Deep, [V | Vars]); erl_pack([{tuple, _N, Fields} | T], Deep, Vars) -> %% @wpf 增加单个tuple元素的解析方法 A = t(erl_pack(Fields, Deep, [])), A1 = lists:reverse(t(lists:reverse(A))), A2 = lists:concat([A1, ", "]), erl_pack(T, Deep, [A2 | Vars]); erl_pack([{array, Type, _N1, N2, Desc, Fields} | T], Deep, Vars) -> erl_pack([{array, Type, N2, Desc, Fields} | T], Deep, Vars); erl_pack([{array, tuple, N, _, Fields} | T], Deep, Vars) -> add_var(Deep, N), S = "{" ++ v(Fields, Deep + 1) ++ "}", X = lists:concat(["V", Deep, "_", N]), reset_var(Deep + 1), A = erl_pack(Fields, Deep + 1, []), V = pack_erl_array(A, S, X), erl_pack(T, Deep, [V | Vars]); erl_pack([{array, list, N, _, Fields} | T], Deep, Vars) -> add_var(Deep, N), S = "[" ++ v(Fields, Deep + 1) ++ "]", X = lists:concat(["V", Deep, "_", N]), reset_var(Deep + 1), A = erl_pack(Fields, Deep + 1, []), V = pack_erl_array(A, S, X), erl_pack(T, Deep, [V | Vars]); erl_pack([{array, single, N, _, Fields} | T], Deep, Vars) -> add_var(Deep, N), S = v(Fields, Deep + 1), X = lists:concat(["V", Deep, "_", N]), reset_var(Deep + 1), A = erl_pack(Fields, Deep + 1, []), V = pack_erl_array(A, S, X), erl_pack(T, Deep, [V | Vars]); erl_pack([{array, new_map, N, _, Fields} | T], Deep, Vars) -> add_var(Deep, N), S = lists:concat(["#{", vmap(Fields, Deep + 1), "}"]), X = lists:concat(["V", Deep, "_", N]), reset_var(Deep + 1), A = erl_pack(Fields, Deep + 1, []), V = pack_erl_array(A, S, X), erl_pack(T, Deep, [V | Vars]); erl_pack([{array, RecordName, N, _, Fields} | T], Deep, Vars) -> add_var(Deep, N), S = lists:concat(["#", RecordName, "{", vr(Fields, Deep + 1), "}"]), X = lists:concat(["V", Deep, "_", N]), reset_var(Deep + 1), A = erl_pack(Fields, Deep + 1, []), V = pack_erl_array(A, S, X), erl_pack(T, Deep, [V | Vars]); erl_pack([{rec, _N, _RecN, Fields} | T], Deep, Vars) -> erl_pack(Fields ++ T, Deep, Vars); erl_pack([{Type, _N, N, Desc} | T], Deep, Vars) -> erl_pack([{Type, N, Desc} | T], Deep, Vars); erl_pack([{_, N, _} | _T], _Deep, _Vars) -> ?ERR("[code: ~w]的[~w]项配置有误", [get(code), N]), exit(error); erl_pack([{_, _, N, _, _} | _T], _Deep, _Vars) -> ?ERR("[code: ~w]的[~w]项配置有误", [get(code), N]), exit(error). pack_erl_array(A, S, X) -> case get(compile_type) of debug -> lists:concat(["(length(", X, ")):16, (list_to_binary(lists:map(fun(", S, ") -> ", A, " end, ", X, ")))/binary, "]); _ -> lists:concat(["(length(", X, ")):16, (list_to_binary([", A, " || ", S, " <- ", X, "]))/binary, "]) end. %% 获取变量名字串 v(Fields, Deep) -> v(Fields, Deep, []). v([], _Deep, Vars) -> t(lists:concat(lists:reverse(Vars))); v([{tuple, _Name, Fields} | T], Deep, Vars) -> V = "{" ++ v(Fields, Deep) ++ "}, ", v(T, Deep, [V | Vars]); v([{array, Type, _N1, N2, Desc, Fields} | T], Deep, Vars) -> v([{array, Type, N2, Desc, Fields} | T], Deep, Vars); v([{array, _, N, _, _} | T], Deep, Vars) -> V = lists:concat(["V", Deep, "_", N, ", "]), v(T, Deep, [V | Vars]); v([{rec, _N, new_map, Fields} | T], Deep, Vars) -> V = lists:concat(["#{", vmap(Fields, Deep), "}, "]), v(T, Deep, [V | Vars]); v([{rec, _N, RecN, Fields} | T], Deep, Vars) -> V = lists:concat(["#", RecN, "{", vr(Fields, Deep), "}, "]), v(T, Deep, [V | Vars]); v([{Type, Name, Desc} | T], Deep, Vars) -> v([{Type, Name, Name, Desc} | T], Deep, Vars); v([{_, _, N, _} | T], Deep, Vars) -> V = lists:concat(["V", Deep, "_", N, ", "]), v(T, Deep, [V | Vars]). %% 获取记录名字串 vr(Fields, Deep) -> vr(Fields, Deep, []). vr([], _Deep, Vars) -> t(lists:concat(lists:reverse(Vars))); vr([{tuple, N, L} | T], Deep, Vars) -> %% @wpf 增加记录中的单个元素是tuple类型的数据解析 V = lists:concat([N, " = {", v(L, Deep), "}, "]), vr(T, Deep, [V | Vars]); vr([{array, _Type, N1, N2, _Desc, _Fields} | T], Deep, Vars) -> V = lists:concat([N1, " = V", Deep, "_", N2, ", "]), vr(T, Deep, [V | Vars]); vr([{array, _, N, _, _} | T], Deep, Vars) -> V = lists:concat([N, " = V", Deep, "_", N, ", "]), vr(T, Deep, [V | Vars]); vr([{rec, N, new_map, Fields} | T], Deep, Vars) -> V = lists:concat([N , " = #{", vmap(Fields, Deep), "}, "]), vr(T, Deep, [V | Vars]); vr([{rec, N, RecN, Fields} | T], Deep, Vars) -> V = lists:concat([N , " = #", RecN, "{", vr(Fields, Deep), "}, "]), vr(T, Deep, [V | Vars]); vr([{Type, Name, Desc} | T], Deep, Vars) -> vr([{Type, Name, Name, Desc} | T], Deep, Vars); vr([{_, N1, N2, _} | T], Deep, Vars) -> V = lists:concat([N1, " = V", Deep, "_", N2, ", "]), vr(T, Deep, [V | Vars]). %% 获取记录名字串 vmap(Fields, Deep) -> vmap(Fields, Deep, []). vmap([], _Deep, Vars) -> t(lists:concat(lists:reverse(Vars))); vmap([{tuple, N, L} | T], Deep, Vars) -> %% @wpf 增加记录中的单个元素是tuple类型的数据解析 V = lists:concat([N, " := {", v(L, Deep), "}, "]), vmap(T, Deep, [V | Vars]); vmap([{array, _Type, N1, N2, _Desc, _Fields} | T], Deep, Vars) -> V = lists:concat([N1, " := V", Deep, "_", N2, ", "]), vmap(T, Deep, [V | Vars]); vmap([{array, _, N, _, _} | T], Deep, Vars) -> V = lists:concat([N, " := V", Deep, "_", N, ", "]), vmap(T, Deep, [V | Vars]); vmap([{rec, N, new_map, Fields} | T], Deep, Vars) -> V = lists:concat([N , " := #{", vmap(Fields, Deep), "}, "]), vmap(T, Deep, [V | Vars]); vmap([{rec, N, RecN, Fields} | T], Deep, Vars) -> V = lists:concat([N , " := #", RecN, "{", vr(Fields, Deep), "}, "]), vmap(T, Deep, [V | Vars]); vmap([{Type, Name, Desc} | T], Deep, Vars) -> vmap([{Type, Name, Name, Desc} | T], Deep, Vars); vmap([{_, N1, N2, _} | T], Deep, Vars) -> V = lists:concat([N1, " := V", Deep, "_", N2, ", "]), vmap(T, Deep, [V | Vars]). %% 生成解包函数 gen_erl_unpack(_Type, _Code, undefined) -> ""; gen_erl_unpack(Type, Code, []) -> lists:concat(["\n\nunpack(", Code, ", ", Type, ", _B0) ->\n", s(1), "{ok, {}};"]); gen_erl_unpack(Type, Code, {_RecordName, Fields}) -> gen_erl_unpack(Type, Code, Fields); gen_erl_unpack(Type, Code, Fields) -> {_Idx, _Deep, Txt} = erl_unpack(Fields, 0, 1, [], []), lists:concat(["\n\nunpack(", Code, ", ", Type, ", _B0) ->\n", Txt, ";"]). erl_unpack([], Idx, Deep, Vars, Str) -> V = case Deep =:= 1 of true -> lists:concat([s(1), "{ok, {", t(lists:concat([N ++ ", " || N <- lists:reverse(Vars)])), "}}"]); false -> case erase(array_type) of single -> lists:concat([s(Deep), "{", t(lists:concat([N ++ ", " || N <- lists:reverse(Vars)])), ", _B", Idx, "}"]); _ -> lists:concat([s(Deep), "{{", t(lists:concat([N ++ ", " || N <- lists:reverse(Vars)])), "}, _B", Idx, "}"]) end end, S = lists:concat(lists:reverse(Str)), {Idx + 1, Deep, S ++ V}; erl_unpack([{array, Type, _Name1, Name2, Desc, Fields} | T], Idx, Deep, Vars, Str) -> erl_unpack([{array, Type, Name2, Desc, Fields} | T], Idx, Deep, Vars, Str); erl_unpack([{array, _Type, Name, _Desc, Fields} | T], Idx, Deep, Vars, Str) -> V = lists:concat(["V", Deep, "_", Name]), X = s(Deep), put(array_type, _Type), {Idx1, Deep1, Txt} = erl_unpack(Fields, Idx + 1, Deep + 1, [], []), S = lists:concat([X, "{", V, ", _B", Idx1 + 1, "} = protocol:array(_B", Idx, ", fun(_B", Idx +1, ") ->\n", Txt, "\n", X, "end),\n"]), erl_unpack(T, Idx1 + 1, Deep1 - 1, [V | Vars], [S | Str]); erl_unpack([{tuple, _Name, Fields} | T], Idx, Deep, Vars, Str) -> %% @wpf 增加记录中的单个元素是tuple类型的数据解析 {NewIdx, NewV, NewS} = erl_unpack_tuple(Fields, Idx, Deep, Vars, Str), erl_unpack(T, NewIdx, Deep, NewV, NewS); erl_unpack([{rec, _N, _RecN, Fields} | T], Idx, Deep, Vars, Str) -> erl_unpack(Fields ++ T, Idx, Deep, Vars, Str); erl_unpack([{Type, Name, Desc} | T], Idx, Deep, Vars, Str) -> erl_unpack([{Type, Name, Name, Desc} | T], Idx, Deep, Vars, Str); erl_unpack([{Type, _, Name, _Desc} | T], Idx, Deep, Vars, Str) -> V = lists:concat(["V", Deep, "_", Name]), X = s(Deep), S = lists:concat([X, "{", V, ", _B", Idx + 1, "} = protocol:", Type, "(_B", Idx, "),\n"]), erl_unpack(T, Idx + 1, Deep, [V | Vars], [S | Str]). %% 添加的tuple组合 %% @wpf 增加记录中的单个元素是tuple类型的数据解析 erl_unpack_tuple([], Idx, _Deep, Vars, Str) -> {Idx, Vars, Str}; erl_unpack_tuple([{array, Type, _Name1, Name2, Desc, Fields} | T], Idx, Deep, Vars, Str) -> erl_unpack_tuple([{array, Type, Name2, Desc, Fields} | T], Idx, Deep, Vars, Str); erl_unpack_tuple([{array, _Type, Name, _Desc, Fields} | T], Idx, Deep, Vars, Str) -> V = lists:concat(["V", Deep, "_", Name]), X = s(Deep), {Idx1, _Deep1, Txt} = erl_unpack_tuple(Fields, Idx + 1, Deep + 1, [], []), S = lists:concat([X, "{", V, ", _B", Idx1 + 1, "} = protocol:array(_B", Idx, ", fun(_B", Idx +1, ") ->\n", Txt, "\n", X, "end),\n"]), erl_unpack_tuple(T, Idx1 + 1, Deep + 1, [V | Vars], [S | Str]); erl_unpack_tuple([{Type, Name, Desc} | T], Idx, Deep, Vars, Str) -> erl_unpack_tuple([{Type, Name, Name, Desc} | T], Idx, Deep, Vars, Str); erl_unpack_tuple([{Type, _N, Name, _Desc} | T], Idx, Deep, Vars, Str) -> V = lists:concat(["V", Deep, "_", Name]), X = s(Deep), S = lists:concat([X, "{", V, ", _B", Idx + 1, "} = protocol:", Type, "(_B", Idx, "),\n"]), erl_unpack_tuple(T, Idx + 1, Deep, [V | Vars], [S | Str]). %% 打包协议描述 gen_erl_pack_mate(Code, L) -> Bin = gen_erl_pack_mate_(L, <<(length(L)):8>>), lists:concat(["\pack_mate(", Code, ") -> ", ?S("~w", [Bin]) , ";\n"]). gen_erl_pack_mate_([], Bin) -> Bin; gen_erl_pack_mate_([{int8, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{uint8, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{int16, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{uint16, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{int32, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{uint32, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{string, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{byte, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{array, _, _, _, Fields} | T], Bin) -> gen_erl_pack_mate_(Fields ++ T, <>); gen_erl_pack_mate_([{array_map, _, _, Fields} | T], Bin) -> gen_erl_pack_mate_(Fields ++ T, <>); gen_erl_pack_mate_([{float, _, _} | T], Bin) -> gen_erl_pack_mate_(T, <>); gen_erl_pack_mate_([{tuple, _, Fields} | T], Bin) -> gen_erl_pack_mate_(Fields ++ T, Bin); gen_erl_pack_mate_([{rec, _, _, Fields} | T], Bin) -> gen_erl_pack_mate_(Fields ++ T, Bin); gen_erl_pack_mate_([{Type, _N1, N2, N3} | T], Bin) -> gen_erl_pack_mate_([{Type, N2, N3} | T], Bin). %% 生成版本数据转换 gen_erl_convert_data(Code, List) -> Txt = convert_data_tuple(List, undefined, 1, 1, "Data", []), lists:concat(["convert_data(", Code, ", Data) ->\n ", Txt, ";\n\n"]). convert_data_tuple([], undefined, _Pos, _Deep, _Data, L) -> lists:concat(["#{", string:join(lists:reverse(L), ", "), "}"]); convert_data_tuple([], RecName, _Pos, _Deep, _Data, L) -> lists:concat(["#", RecName, "{", string:join(lists:reverse(L), ", "), "}"]); convert_data_tuple([{Type, Name, _Desc} | T], RecName, Pos, Deep, Data, L) when Type =:= int8 orelse Type =:= uint8 orelse Type =:= int16 orelse Type =:= uint16 orelse Type =:= int32 orelse Type =:= uint32 -> S = convert_data_pos(Data, RecName, Pos, Name, int), convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{Type, Name, _Desc} | T], RecName, Pos, Deep, Data, L) when Type =:= string orelse Type =:= binary orelse Type =:= byte -> S = convert_data_pos(Data, RecName, Pos, Name, str), convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{tuple, Name, Fields} | T], RecName, Pos, Deep, Data, L) -> Data1 = ?S("V~w_~w", [Deep, Name]), S = case RecName of undefined -> ?S("~w=>begin ~s=?pcd(~s,~w,tuple),~s end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, undefined, 1, Deep + 1, Data1, [])]); _ -> ?S("~w=begin ~s=?pcd(~s,~w,tuple),~s end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, undefined, 1, Deep + 1, Data1, [])]) end, convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{array, tuple, Name, _Desc, Fields} | T], RecName, Pos, Deep, Data, L) -> Data1 = ?S("V~w_~w", [Deep, Name]), S = case RecName of undefined -> ?S("~w=>begin ~s=?pcd(~s,~w,list), [~s||~s_I<-~s] end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, undefined, 1, Deep + 1, Data1++"_I", []), Data1, Data1]); _ -> ?S("~w=begin ~s=?pcd(~s,~w,list), [~s||~s_I<-~s] end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, undefined, 1, Deep + 1, Data1++"_I", []), Data1, Data1]) end, convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{array, single, Name, _Desc, _Fields} | T], RecName, Pos, Deep, Data, L) -> S = case RecName of undefined -> ?S("~w=>?pcd(~s,~w,list)", [Name, Data, Pos]); _ -> ?S("~w=?pcd(~s,~w,list)", [Name, Data, Pos]) end, convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{array, NewRecName, Name, _Desc, Fields} | T], RecName, Pos, Deep, Data, L) -> Data1 = ?S("V~w_~w", [Deep, Name]), S = case RecName of undefined -> ?S("~w=>begin ~s=?pcd(~s,~w,list), [~s||~s_I<-~s] end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, NewRecName, 1, Deep + 1, Data1++"_I", []), Data1, Data1]); _ -> ?S("~w=begin ~s=?pcd(~s,~w,list), [~s||~s_I<-~s] end", [Name, Data1, Data, Pos, convert_data_tuple(Fields, NewRecName, 1, Deep + 1, Data1++"_I", []), Data1, Data1]) end, convert_data_tuple(T, RecName, Pos + 1, Deep, Data, [S | L]); convert_data_tuple([{Type, Name, _Name2, Desc} | T], RecName, Pos, Deep, Data, L) -> convert_data_tuple([{Type, Name, Desc} | T], RecName, Pos, Deep, Data, L). convert_data_pos(Data, undefined, Pos, Name, Type) -> ?S("~w=>?pcd(~s,~w,~w)", [Name, Data, Pos, Type]); convert_data_pos(Data, _RecName, Pos, Name, Type) -> ?S("~w=?pcd(~s,~w,~w)", [Name, Data,Pos, Type]). %% 缩进处理 s(N) -> s(N, ""). s(0, S) -> S; s(N, S) -> s(N - 1, S ++ " "). %% 尾部处理 t(S) -> [_ | [_ | R]] = lists:reverse(S), lists:reverse(R). %% lua打包发送 gen_lua_pack(#rpc{req = undefined}) -> ok; gen_lua_pack(#rpc{code = Code, req = Req}) -> LuaFields = gen_lua_fields(Req, " ", []), P = ?S(" [~w] = {\n~ts }", [Code, LuaFields]), put(lua_send, [P | get(lua_send)]). %% lua解包接收 gen_lua_unpack(#rpc{reply = undefined}) -> ok; gen_lua_unpack(#rpc{code = Code, reply = Reply}) -> LuaFields = gen_lua_fields(Reply, " ", []), P = ?S(" [~w] = {\n~ts }", [Code, LuaFields]), put(lua_recv, [P | get(lua_recv)]). gen_lua_fields([], _Space, []) -> ""; gen_lua_fields([], _Space, L) -> string:join(lists:reverse(L), ",\n") ++ "\n"; gen_lua_fields({_RecName, Fields}, Space, L) -> gen_lua_fields(Fields, Space, L); gen_lua_fields([{rec, _, _, Fields} | T], Space, L) -> gen_lua_fields(Fields ++ T, Space, L); gen_lua_fields([{tuple, _, Fields} | T], Space, L) -> gen_lua_fields(Fields ++ T, Space, L); gen_lua_fields([{array, Type, _Name1, Name2, _Desc, SubFields} | T], Space, L) -> gen_lua_fields([{array, Type, Name2, _Desc, SubFields} | T], Space, L); gen_lua_fields([{array, _, Name, _Desc, SubFields} | T], Space, L) -> SubS = gen_lua_fields(SubFields, Space ++ " ", []), S = ?S("~ts{name='~ts', type='array', fields={\n~ts~ts}}", [Space, Name, SubS, Space]), gen_lua_fields(T, Space, [S | L]); gen_lua_fields([{Type, _Name1, Name2, _Desc} | T], Space, L) -> gen_lua_fields([{Type, Name2, _Desc} | T], Space, L); gen_lua_fields([{binary, Name, Desc} | T], Space, L) -> gen_lua_fields([{string, Name, Desc} | T], Space, L); gen_lua_fields([{Type, Name, _Desc} | T], Space, L) when Type =:= int8 orelse Type =:= uint8 orelse Type =:= int16 orelse Type =:= uint16 orelse Type =:= int32 orelse Type =:= uint32 orelse Type =:= string orelse Type =:= byte -> S = ?S("~ts{name='~w', type='~w'}", [Space, Name, Type]), gen_lua_fields(T, Space, [S | L]). %% js打包发送 gen_js_pack(#rpc{req = undefined}) -> ok; gen_js_pack(#rpc{code = Code, req = Req}) -> JsFields = gen_js_fields(Req, " ", []), P = ?S(" ~w : [\n~ts ]", [Code, JsFields]), put(js_send, [P | get(js_send)]). %% lua解包接收 gen_js_unpack(#rpc{reply = undefined}) -> ok; gen_js_unpack(#rpc{code = Code, reply = Reply}) -> LuaFields = gen_js_fields(Reply, " ", []), P = ?S(" ~w : [\n~ts ]", [Code, LuaFields]), put(js_recv, [P | get(js_recv)]). gen_js_fields([], _Space, []) -> ""; gen_js_fields([], _Space, L) -> string:join(lists:reverse(L), ",\n") ++ "\n"; gen_js_fields({_RecName, Fields}, Space, L) -> gen_js_fields(Fields, Space, L); gen_js_fields([{rec, _, _, Fields} | T], Space, L) -> gen_js_fields(Fields ++ T, Space, L); gen_js_fields([{tuple, _, Fields} | T], Space, L) -> gen_js_fields(Fields ++ T, Space, L); gen_js_fields([{array, Type, _Name1, Name2, _Desc, SubFields} | T], Space, L) -> gen_js_fields([{array, Type, Name2, _Desc, SubFields} | T], Space, L); gen_js_fields([{array, _, Name, _Desc, SubFields} | T], Space, L) -> SubS = gen_js_fields(SubFields, Space ++ " ", []), S = ?S("~ts{s:'~ts', t:~w, f:[\n~ts~ts]}", [Space, Name, js_type(array), SubS, Space]), gen_js_fields(T, Space, [S | L]); gen_js_fields([{Type, _Name1, Name2, _Desc} | T], Space, L) -> gen_js_fields([{Type, Name2, _Desc} | T], Space, L); gen_js_fields([{binary, Name, Desc} | T], Space, L) -> gen_js_fields([{string, Name, Desc} | T], Space, L); gen_js_fields([{Type, Name, _Desc} | T], Space, L) when Type =:= int8 orelse Type =:= uint8 orelse Type =:= int16 orelse Type =:= uint16 orelse Type =:= int32 orelse Type =:= uint32 orelse Type =:= string orelse Type =:= byte -> S = ?S("~ts{s:'~w', t:~w}", [Space, Name, js_type(Type)]), gen_js_fields(T, Space, [S | L]). js_type(int8) -> 1; js_type(uint8) -> 2; js_type(int16) -> 3; js_type(uint16) -> 4; js_type(int32) -> 5; js_type(uint32) -> 6; js_type(string) -> 7; js_type(byte) -> 8; js_type(array) -> 9. %% 清空变量 reset_var(N) -> put({var_list, N}, []). %% 增加变量 add_var(N, Var) -> case lists:member(Var, get({var_list, N})) of true -> ?P("~w==字段重复==>deep:~w ~w~n", [get(code), N, Var]); _ -> put({var_list, N}, [Var | get({var_list, N})]) end. %% 获取所有的配置文件 cfg_file() -> %% ?DEBUG("配置目录:~ts", [env:get(code_path) ++ "/src/proto"]), case file:list_dir("./cfg") of {ok, L} -> do_cfg_file(L, []); {error, Why} -> ?P("获取RPC配置文件时发生异常: ~w~n", [Why]), [] end. %% 返回所有的配置文件 do_cfg_file([], List) -> lists:sort(List); do_cfg_file([F | T], List) -> L = case filename:extension(F) =:= ".erl" of true -> M = filename:basename(filename:rootname(F)), [M | List]; _ -> List end, do_cfg_file(T, L).