Files
fc/server/tools/gen_proto/main.erl
T

731 lines
30 KiB
Erlang
Raw Normal View History

2026-05-23 22:10:14 +08:00
%%----------------------------------------------------
%% 协议生成工具
%% @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, <<Bin/binary, ?proto_int8:8>>);
gen_erl_pack_mate_([{uint8, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_uint8:8>>);
gen_erl_pack_mate_([{int16, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_int16:8>>);
gen_erl_pack_mate_([{uint16, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_uint16:8>>);
gen_erl_pack_mate_([{int32, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_int32:8>>);
gen_erl_pack_mate_([{uint32, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_uint32:8>>);
gen_erl_pack_mate_([{string, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_string:8>>);
gen_erl_pack_mate_([{byte, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_byte:8>>);
gen_erl_pack_mate_([{array, _, _, _, Fields} | T], Bin) ->
gen_erl_pack_mate_(Fields ++ T, <<Bin/binary, ?proto_array:8, (length(Fields)):8>>);
gen_erl_pack_mate_([{array_map, _, _, Fields} | T], Bin) ->
gen_erl_pack_mate_(Fields ++ T, <<Bin/binary, ?proto_array:8, (length(Fields)):8>>);
gen_erl_pack_mate_([{float, _, _} | T], Bin) ->
gen_erl_pack_mate_(T, <<Bin/binary, ?proto_float:8>>);
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).