Kaynağa Gözat

新增提交

master
AICells 4 yıl önce
ebeveyn
işleme
ebeefabdbe
72 değiştirilmiş dosya ile 19688 ekleme ve 0 silme
  1. +124
    -0
      src/srvNodeMgr/baizhan/misc/config.erl
  2. +202
    -0
      src/srvNodeMgr/baizhan/misc/lib_send.erl
  3. +24
    -0
      src/srvNodeMgr/baizhan/misc/lib_sys.erl
  4. +729
    -0
      src/srvNodeMgr/baizhan/misc/misc.erl
  5. +1184
    -0
      src/srvNodeMgr/baizhan/misc/util.erl
  6. +714
    -0
      src/srvNodeMgr/misc.erl
  7. +186
    -0
      src/srvNodeMgr/tools/gameWorld/test/excel2mysql.erl
  8. +124
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/auto_id.erl
  9. +332
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/config.erl
  10. +270
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/dynamic_compile.erl
  11. +41
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/game_alarm_handler.erl
  12. +131
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/game_timer.erl
  13. +348
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/http_lib.erl
  14. +238
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/logger_h.erl
  15. +114
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/loglevel.erl
  16. +562
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/misc.erl
  17. +491
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/misc_admin.erl
  18. +132
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/php_parser.erl
  19. +651
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/tool.erl
  20. +563
    -0
      src/srvNodeMgr/tools/gameWorld/test/misc/util.erl
  21. +51
    -0
      src/srvNodeMgr/tools/gameWorld/test/mysql_test.erl
  22. +402
    -0
      src/srvNodeMgr/tools/gameWorld/test/mysql_to_emongo.erl
  23. +54
    -0
      src/srvNodeMgr/tools/gameWorld/test/performance/cast_and_call.erl
  24. +34
    -0
      src/srvNodeMgr/tools/gameWorld/test/performance/loop.erl
  25. +25
    -0
      src/srvNodeMgr/tools/gameWorld/test/performance/prof.erl
  26. +160
    -0
      src/srvNodeMgr/tools/gameWorld/test/random_test.erl
  27. +49
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/chat_script.erl
  28. +84
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/mail_script.erl
  29. +850
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/new_robot.erl
  30. +218
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/ptr_30.erl
  31. +30
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/task_script.erl
  32. +144
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_11.erl
  33. +198
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_19.erl
  34. +427
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_40.erl
  35. +54
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_44.erl
  36. +921
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot.erl
  37. +103
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot.hrl
  38. +131
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_battle.erl
  39. +91
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_chat.erl
  40. +589
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_gateway.erl
  41. +39
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_gm.erl
  42. +62
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_goods.erl
  43. +232
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_guild.erl
  44. +23
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_mail.erl
  45. +158
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_market.erl
  46. +44
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_mount.erl
  47. +18
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_newbie.erl
  48. +23
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_openfunc.erl
  49. +9
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_pet.erl
  50. +51
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_shop.erl
  51. +140
    -0
      src/srvNodeMgr/tools/gameWorld/test/robot/robot_task.erl
  52. +350
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/mmake.erl
  53. +298
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/mtop.erl
  54. +480
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/record_to_code.erl
  55. +492
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/table_to_erlang.erl
  56. +552
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/table_to_record.erl
  57. +247
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/task_data_checker.erl
  58. +152
    -0
      src/srvNodeMgr/tools/gameWorld/test/tools/u.erl
  59. +869
    -0
      src/srvNodeMgr/tools/gameWorld/test/union_to_emongo.erl
  60. +97
    -0
      src/srvNodeMgr/tools_cq/h.erl
  61. +36
    -0
      src/srvNodeMgr/tools_cq/hot_swap.erl
  62. +67
    -0
      src/srvNodeMgr/tools_cq/memory_show.erl
  63. +409
    -0
      src/srvNodeMgr/tools_cq/mmake.erl
  64. +704
    -0
      src/srvNodeMgr/tools_cq/recon/recon.erl
  65. +726
    -0
      src/srvNodeMgr/tools_cq/recon/recon_alloc.erl
  66. +278
    -0
      src/srvNodeMgr/tools_cq/recon/recon_lib.erl
  67. +644
    -0
      src/srvNodeMgr/tools_cq/recon/recon_trace.erl
  68. +249
    -0
      src/srvNodeMgr/tools_cq/seek_info.erl
  69. +103
    -0
      src/srvNodeMgr/tools_cq/test.erl
  70. +74
    -0
      src/srvNodeMgr/tools_cq/tester.erl
  71. +150
    -0
      src/srvNodeMgr/tools_cq/tools.erl
  72. +137
    -0
      src/srvNodeMgr/tools_cq/u.erl

+ 124
- 0
src/srvNodeMgr/baizhan/misc/config.erl Dosyayı Görüntüle

@ -0,0 +1,124 @@
%%%-----------------------------------
%%% @Author : gaomeng 595088880@qq.com
%%% @Created : 2017/10/17
%%% @Doc : APP启动相关
%%%-----------------------------------
-module(config).
-include("common.hrl").
-define(APP, server).
-export([
config/1
, server_ids/0
, listen_port/0
, get_ticket/0
, get_enter_ticket/0
, get_platform/0
, get_create_max_num/0
, is_gm_open/0
, set_gm_open/1
, get_white_ip/0
, add_white_ip/1
, del_white_ip/1
, open_date/0
, merge_date/0
, set_open_date/1
, set_merge_date/1
, print_cmd/0
, set_print_cmd/1
, version/0
, is_https/0
]).
%% @doc HTTPS; return true|false
is_https() ->
case catch config(is_https) of
{'EXIT', _} ->
false;
Val ->
Val
end.
%% @doc
version() ->
case catch config(version) of
{'EXIT', _} ->
"未知版本";
Val ->
Val
end.
%% @doc
print_cmd() ->
config(print_cmd).
%% @doc
set_print_cmd(Flag) ->
application:set_env(?APP, print_cmd, Flag).
%% @doc
set_open_date(Date) ->
application:set_env(?APP, open_date, Date, [{persistent, true}]).
%% @doc
set_merge_date(Date) ->
application:set_env(?APP, merge_date, Date, [{persistent, true}]).
%% @spec open_date() -> {Year, Month, Day}
%%@ doc
open_date() ->
config(open_date).
%% @spec merge_date() -> {Year, Month, Day}
%%@ doc
merge_date() ->
config(merge_date).
%% @doc
add_white_ip(Ip) ->
List = get_white_ip(),
List1 = [Ip | List],
application:set_env(?APP, white_ip, List1).
%% @doc
del_white_ip(Ip) ->
List = get_white_ip(),
List1 = lists:delete(Ip, List),
application:set_env(?APP, white_ip, List1).
%% @doc
get_white_ip() ->
config(white_ip).
set_gm_open(Flag) ->
application:set_env(?APP, gm, Flag).
is_gm_open() ->
config(gm).
get_enter_ticket() ->
config(enter_ticket).
get_ticket() ->
config(ticket).
listen_port() ->
config(listen_port).
server_ids() ->
config(server_ids).
get_platform() ->
config(platform).
get_create_max_num() ->
config(create_max_num).
%% @doc KEY获取对应的值
config(Key) ->
case application:get_env(?APP, Key) of
{ok, Val} ->
Val;
_ ->
throw(undefined)
end.

+ 202
- 0
src/srvNodeMgr/baizhan/misc/lib_send.erl Dosyayı Görüntüle

@ -0,0 +1,202 @@
%%%-----------------------------------
%%% @Author : gaomeng 595088880@qq.com
%%% @Created : 2017/1/30
%%% @Doc :
%%%-----------------------------------
-module(lib_send).
-include("common.hrl").
-include("scene.hrl").
-include("move.hrl").
-include("guild.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-export([
send/2,
pack_send/3,
pack_send/4,
pack_send_msg/2,
send_to_scene/1,
send_to_scene/2,
async_send_scene/2,
async_send_scene/3,
send_to_world/1,
send_to_world/2,
send_to_world/3,
send_to_guild/3,
async_online/3,
async_online/4
]).
%% @doc 线
async_online(M, F, Args) ->
async_online(0, M, F, Args).
async_online(RoleId, M, F, Args) ->
spawn(fun() ->
case ets:info(?ETS_ONLINE) of
undefined ->
ok;
_ ->
L = ets:tab2list(?ETS_ONLINE),
[svr_role:apply(async, Pid, {M, F, Args}) || #role{pid = Pid, id = TemRoleId} <- L, RoleId =/= TemRoleId]
end
end).
%% @doc 广
send_to_guild(GuildId, Cmd, List) when is_integer(GuildId) ->
svr_guild:apply(async, GuildId, {lib_send, send_to_guild, [Cmd, List]});
send_to_guild(#guild{members = Members}, Cmd, List) ->
case catch prot:encode(Cmd, List) of
{ok, Bin} ->
F = fun(#guild_member{role_id = RoleId}) ->
case lib_account:get_role_pid(RoleId) of
Pid when is_pid(Pid) ->
send(Pid, Bin);
_ ->
ok
end
end,
[F(M) || M <- Members];
Ret ->
?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
ok
end,
ok.
%%广
send_to_world(RoleId, Bin) ->
spawn(fun() ->
[send(Sid, Bin) || #role{id = Id, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Id =/= RoleId]
end).
send_to_world(Bin) ->
spawn(fun() ->
[send(Sid, Bin) || #role{sid = Sid} <- ets:tab2list(?ETS_ONLINE)]
end).
%% @doc 广()
send_to_world(level, ReqLevel, Bin) ->
spawn(fun() ->
[send(Sid, Bin) || #role{level = Level, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Level >= ReqLevel]
end);
send_to_world(RoleId, Cmd, List) ->
case catch prot:encode(Cmd, List) of
{ok, Bin} ->
spawn(fun() ->
[send(Sid, Bin) || #role{id = Id, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Id =/= RoleId]
end);
Ret ->
?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
ok
end.
%%广
send_to_scene(Rid, BinData) ->
AllRole = svr_scene_role:get_all(),
F = fun(Role) ->
case Role#scene_role.id =/= Rid of
true ->
send(Role#scene_role.sid, BinData);
_ ->
ok
end
end,
[F(P) || P <- AllRole].
send_to_scene(BinData) ->
AllRole = svr_scene_role:get_all(),
F = fun(Role) ->
send(Role#scene_role.sid, BinData)
end,
[F(P) || P <- AllRole].
%% @doc 广
async_send_scene(ScenePid, BinData) ->
async_send_scene(ScenePid, BinData, 0).
async_send_scene(ScenePid, BinData, RoleId) when is_pid(ScenePid) ->
svr_scene:apply(async, ScenePid, {svr_scene_info, async_send_scene, [RoleId, BinData]});
async_send_scene(_, _, _) ->
ok.
%% @doc
pack_send(Node, Rid = #node_rid{id = RoleId}, Cmd, List) ->
case Node =:= node() of
true ->
pack_send(RoleId, Cmd, List);
_ ->
svr_kfnode:send_role(Node, [Rid], lib_send, pack_send, [Cmd, List])
end.
pack_send(RoleId, Cmd, List) when is_integer(RoleId) ->
case lib_account:get_role_pid(RoleId) of
Pid when is_pid(Pid) ->
pack_send(Pid, Cmd, List);
_ ->
ok
end;
pack_send(#node_rid{id = RoleId}, Cmd, List) ->
pack_send(RoleId, Cmd, List);
pack_send(#role{sid = Sid}, Cmd, List) ->
pack_send(Sid, Cmd, List);
pack_send(Sid, Cmd, List) ->
case misc:is_process_alive(Sid) of
true ->
case catch prot:encode(Cmd, List) of
{ok, Bin} ->
send(Sid, Bin);
Ret ->
?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
ok
end;
_R ->
ok
end,
ok.
send(#role{sid = Sid}, Bin) ->
send(Sid, Bin);
send(Sid, Bin) ->
case catch config:config(print_send_cmd) of
true ->
<<_L:32, Cmd:32, _Data/binary>> = Bin,
svr_handle_mgr:listen_cmd(Cmd, byte_size(Bin));
_ ->
ok
end,
Sid ! {'send', Bin},
ok.
pack_send_msg(#node_rid{id = RoleId}, List) ->
pack_send_msg(RoleId, List);
pack_send_msg(RoleId, List) when is_integer(RoleId) ->
case ets:lookup(?ETS_ONLINE, RoleId) of
[#role{sid = Sid} | _] ->
case misc:is_process_alive(Sid) of
true ->
pack_send_msg(Sid, List);
_ ->
ok
end;
_ ->
ok
end;
pack_send_msg(#role{sid = Sid}, List) ->
pack_send_msg(Sid, List);
pack_send_msg(Sid, [Type, {Code, Vals}]) ->
pack_send_msg(Sid, [Type, 0, Code, Vals]);
pack_send_msg(Sid, [Type, Code]) ->
pack_send_msg(Sid, [Type, 0, Code, ""]);
pack_send_msg(Sid, [Type, SubType, {Code, Vals}]) ->
pack_send_msg(Sid, [Type, SubType, Code, Vals]);
pack_send_msg(Sid, [Type, SubType, Code]) ->
pack_send_msg(Sid, [Type, SubType, Code, ""]);
pack_send_msg(Sid, List) ->
pack_send(Sid, 10100, List),
ok.

+ 24
- 0
src/srvNodeMgr/baizhan/misc/lib_sys.erl Dosyayı Görüntüle

@ -0,0 +1,24 @@
%%%-----------------------------------
%%% @Author : gaomeng 595088880@qq.com
%%% @Created : 2017/10/17
%%% @Doc :
%%%-----------------------------------
-module(lib_sys).
-include("common.hrl").
-export([
get_var/1
]).
%% @doc
get_var(TarName) when is_list(TarName) ->
Sql = io_lib:format(<<"SELECT `value` FROM `sys_var` WHERE `name` = '~s' limit 1;">>, [TarName]),
case db:get_one(Sql) of
[] ->
util:term_to_bitstring([]);
<<>> ->
util:term_to_bitstring([]);
Ret ->
Ret
end;
get_var(Obj) ->
get_var(util:to_list(Obj)).

+ 729
- 0
src/srvNodeMgr/baizhan/misc/misc.erl Dosyayı Görüntüle

@ -0,0 +1,729 @@
%%%-----------------------------------
%%% @Module : misc
%%% @Author : lizemao
%%% @Created : 2014.2.24
%%% @Description: misc
%%%-----------------------------------
-module(misc).
%%
%% Include files
%%
-include("common.hrl").
-include("cache.hrl").
-include("item.hrl").
-include_lib("kernel/include/file.hrl").
%%
%% Exported Functions
%%
-export([
whereis_name/1,
register/3,
unregister/2,
is_process_alive/1,
create_process_name/2,
to_atom/1,
% t/1,
% t/2,
% tr/1,
% tun/1,
% tan/1,
% t_clear/0,
dump_process_info/1
, u/1
, hot/0
, hot_beam/1 %% beam文件使
, ets_mem/0
, tcp_links/0
, top_back/0
, top/0
, request/1
, u_one/1
, stop/0
, del_ref/1
]).
-export([
role_cmd/3
, gm/2
, check_mem/0
, check_mem/1
, online_num/0
, is_cross/0
]).
-export([
decompile/1
, pstack/1
, etop/0
, etop_mem/0
, etop_stop/0
, gc_all/0
, fprof/3
, eprof_all/1
, eprof/2
, scheduler_usage/0
, scheduler_usage/1
, scheduler_stat/0
, scheduler_stat/1
, trace/1
, trace/2
, trace_stop/0
, proc_mem_all/1
, proc_mem/1
, crash_dump/0
, process_infos/0
]).
-export([check_item/0, ints2str/2]).
%%
%% API Functions
%%
%% @doc ref
del_ref(Ref) when is_reference(Ref) ->
erlang:cancel_timer(Ref);
del_ref(_) ->
ok.
%% @doc
process_infos() ->
filelib:ensure_dir("./logs/"),
File = "./logs/processes_infos.log",
{ok, Fd} = file:open(File, [write, raw, binary, append]),
Fun = fun(Pi) ->
Info = io_lib:format("=>~p \n\n", [Pi]),
case filelib:is_file(File) of
true -> file:write(Fd, Info);
false ->
file:close(Fd),
{ok, NewFd} = file:open(File, [write, raw, binary, append]),
file:write(NewFd, Info)
end,
timer:sleep(20)
end,
[Fun(erlang:process_info(P)) || P <- erlang:processes()].
%% @doc erlang_dump
crash_dump() ->
Date = erlang:list_to_binary(rfc1123_local_date()),
Header = binary:list_to_bin([<<"=erl_crash_dump:0.2\n">>, Date, <<"\nSystem version: ">>]),
Ets = ets_info(),
Report = binary:list_to_bin([Header, erlang:list_to_binary(erlang:system_info(system_version)),
erlang:system_info(info), erlang:system_info(procs), Ets, erlang:system_info(dist),
<<"=loaded_modules\n">>, binary:replace(erlang:system_info(loaded),
<<"\n">>, <<"\n=mod:">>, [global])]),
file:write_file("erl_crash.dump", Report).
ets_info() ->
binary:list_to_bin([ets_table_info(T) || T <- ets:all()]).
ets_table_info(Table) ->
Info = ets:info(Table),
Owner = erlang:list_to_binary(erlang:pid_to_list(proplists:get_value(owner, Info))),
TableN = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))),
Name = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))),
Objects = erlang:list_to_binary(erlang:integer_to_list(proplists:get_value(size, Info))),
binary:list_to_bin([<<"=ets:">>, Owner, <<"\nTable: ">>, TableN, <<"\nName: ">>, Name,
<<"\nObjects: ">>, Objects, <<"\n">>]).
rfc1123_local_date() ->
rfc1123_local_date(os:timestamp()).
rfc1123_local_date({A, B, C}) ->
rfc1123_local_date(calendar:now_to_local_time({A, B, C}));
rfc1123_local_date({{YYYY, MM, DD}, {Hour, Min, Sec}}) ->
DayNumber = calendar:day_of_the_week({YYYY, MM, DD}),
lists:flatten(
io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT",
[httpd_util:day(DayNumber), DD, httpd_util:month(MM), YYYY, Hour, Min, Sec]));
rfc1123_local_date(Epoch) when erlang:is_integer(Epoch) ->
rfc1123_local_date(calendar:gregorian_seconds_to_datetime(Epoch + 62167219200)).
%% @doc etop 10w+ , proc后通过pstackmessage_queu_len
proc_mem_all(SizeLimitKb) ->
Procs = [{undefined, Pid} || Pid <- erlang:processes()],
proc_mem(Procs, SizeLimitKb).
proc_mem(SizeLimitKb) ->
Procs = [{Name, Pid} || {_, Name, Pid, _} <- release_handler_1:get_supervised_procs(), erlang:is_process_alive(Pid)],
proc_mem(Procs, SizeLimitKb).
proc_mem(Procs, SizeLimitKb) ->
SizeLimit = SizeLimitKb * 1024,
{R, Total} = lists:foldl(fun({Name, Pid}, {Acc, TotalSize}) ->
case erlang:process_info(Pid, total_heap_size) of
{_, Size0} ->
Size = Size0 * 8,
case Size > SizeLimit of
true -> {[{Name, Pid, Size} | Acc], TotalSize + Size};
false -> {Acc, TotalSize}
end;
_ -> {Acc, TotalSize}
end
end, {[], 0}, Procs),
R1 = lists:keysort(3, R),
{Total, lists:reverse(R1)}.
%trace Mod
trace(Mod) ->
dbg:tracer(),
dbg:tpl(Mod, '_', []),
dbg:p(all, c).
%trace Node上指定 Mod , shell
trace(Node, Mod) ->
dbg:tracer(),
dbg:n(Node),
dbg:tpl(Mod, '_', []),
dbg:p(all, c).
%trace
trace_stop() ->
dbg:stop_clear().
% 1s内调度进程数量()
scheduler_stat() ->
scheduler_stat(1000).
scheduler_stat(RunMs) ->
erlang:system_flag(scheduling_statistics, enable),
Ts0 = erlang:system_info(total_scheduling_statistics),
timer:sleep(RunMs),
Ts1 = erlang:system_info(total_scheduling_statistics),
erlang:system_flag(scheduling_statistics, disable),
lists:map(fun({{Key, In0, Out0}, {Key, In1, Out1}}) ->
{Key, In1 - In0, Out1 - Out0} end, lists:zip(Ts0, Ts1)).
% 1s每个调度器CPU的实际利用率(spin wait, usage top显示低很多)
scheduler_usage() ->
scheduler_usage(1000).
scheduler_usage(RunMs) ->
erlang:system_flag(scheduler_wall_time, true),
Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)),
timer:sleep(RunMs),
Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)),
erlang:system_flag(scheduler_wall_time, false),
Cores = lists:map(fun({{I, A0, T0}, {I, A1, T1}}) ->
{I, (A1 - A0) / (T1 - T0)} end, lists:zip(Ts0, Ts1)),
{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai, Ti}) ->
{Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0, Ts1)),
Total = A / T,
io:format("~p~n", [[{total, Total} | Cores]]).
% eprof, eprof 线,!
% TimeoutSec<10s< 1000crash
% :
% mod调用执行时间
% mod - Fun
eprof_all(TimeoutSec) ->
eprof(processes() -- [whereis(eprof)], TimeoutSec).
eprof(Pids, TimeoutSec) ->
eprof:start(),
eprof:start_profiling(Pids),
timer:sleep(TimeoutSec),
eprof:stop_profiling(),
eprof:analyze(total),
eprof:stop().
% @doc MFA
% :
% fprof
fprof(M, F, A) ->
fprof:start(),
fprof:apply(M, F, A),
fprof:profile(),
fprof:analyse([{dest, "fprof.analysis"}, {sort, own}]),
fprof:stop().
% @doc process做gc
gc_all() ->
[erlang:garbage_collect(Pid) || Pid <- processes()].
% @doc CPU占用排名
etop() ->
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, runtime}]) end).
% @doc Mem占用排名
etop_mem() ->
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, memory}]) end).
% @doc etop
etop_stop() ->
etop:stop().
%% @doc jstackhang住等问题用到
pstack(Reg) when is_atom(Reg) ->
case whereis(Reg) of
undefined -> undefined;
Pid -> pstack(Pid)
end;
pstack(Pid) ->
io:format("~s~n", [element(2, process_info(Pid, backtrace))]).
%% @doc
decompile(Mod) ->
{ok, {_, [{abstract_code, {_, AC}}]}} = beam_lib:chunks(code:which(Mod), [abstract_code]),
?INF("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
%% @doc 线
online_num() ->
ets:info(?ETS_ONLINE, size).
%% @doc 600M的全部强制GC
check_mem() ->
Total = erlang:memory(total),
case Total > 600000000 of
true ->
spawn(fun() -> [erlang:garbage_collect(Pid) || Pid <- processes()] end);
_ ->
ok
end.
% check_mem(1000000000).
%% gc,
check_mem(MemLim) ->
lists:foreach(
fun(P) ->
case is_pid(P) andalso erlang:is_process_alive(P) of
true ->
{memory, Mem} = erlang:process_info(P, memory),
case Mem > MemLim of
true ->
erlang:garbage_collect(P);
false ->
[]
end;
false ->
[]
end
end, erlang:processes()).
%% @doc GM命令
gm(RoleId, Content) ->
role_cmd(RoleId, 11600, [Content]).
%% @doc
role_cmd(RoleId, Cmd, Data) ->
svr_role:apply(async, RoleId, {lib_role, async_cmd, [Cmd, Data]}).
%% @doc
stop() ->
?INF("server_starting_stop"),
case is_cross() of
true ->
cross_stop();
_ ->
common_stop()
end.
%% @doc
common_stop() ->
AllRoles = ets:tab2list(?ETS_ONLINE),
[Pid ! {'stop', server_stop} || #role{pid = Pid} <- AllRoles],%线
cowboy:stop_listener(http),
catch svr_cache_mgr:do_save(),
catch svr_chat:save_chat(),
catch svr_rank:hand_save(),
catch svr_log:hand_save(),
case catch check_item() of
{'EXIT', Res} ->
?INF("error:~p", [Res]);
_ ->
ok
end,
?INF("server_stop"),
init:stop().
%% @doc
check_item() ->
List = ets:tab2list(?ETS_CACHE_ITEM_ROLE),
check_item(List).
check_item([{RoleId, Ids = [_ | _]} | T]) ->
SelectSql = io_lib:format(<<"select id from player_item where role_id=~p;">>, [RoleId]),
IdVals = db:execute(SelectSql),
case filter_item_ids(IdVals, Ids, []) of
[_ | IdStrs] ->
Sql = io_lib:format(<<"delete from player_item where id in (~s);">>, [IdStrs]),
db:execute(Sql);
_ ->
ok
end,
save_eq(Ids),
check_item(T);
check_item([_ | T]) ->
check_item(T);
check_item([]) ->
ok.
%% @doc
save_eq(Ids) ->
case find_eq_item(Ids, []) of
[_ | SqlVals] ->
Sql = io_lib:format(?SQL_ITEM_BATCH_REPLACE, [SqlVals]),
db:execute(Sql);
_ ->
ok
end.
find_eq_item([Id | T], L) ->
L1 =
case svr_cache_item:find_item(Id) of
Item = #item{slot = Slot} ->
case Slot > 0 orelse lib_awake_equip:is_awake(Item) of
true ->
"," ++ lib_item_dict:make_batch_insert_sql_one(Item) ++ L;
_ ->
L
end;
_ ->
L
end,
find_eq_item(T, L1);
find_eq_item([], L) ->
L.
%% @doc
filter_item_ids([[Id] | T], Ids, L) ->
L1 =
case lists:member(Id, Ids) of
false ->
IdStr = integer_to_list(Id),
"," ++ IdStr ++ L;
_ ->
L
end,
filter_item_ids(T, Ids, L1);
filter_item_ids([], _, L) ->
L.
ints2str([Id | T], L) ->
IdStr = integer_to_list(Id),
case T of
[] ->
ints2str(T, IdStr ++ L);
_ ->
ints2str(T, "," ++ IdStr ++ L)
end;
ints2str([], L) ->
L.
%% @doc
cross_stop() ->
catch svr_kfboss_awake_mgr:stop(),
catch svr_kfnode:stop(),
init:stop().
%% @doc
is_cross() ->
case config:get_platform() of
"cross" ->
true;
_ ->
false
end.
%% @doc PID
whereis_name({local, Atom}) ->
erlang:whereis(Atom);
whereis_name({global, Atom}) ->
global:whereis_name(Atom).
register(local, Name, Pid) ->
erlang:register(Name, Pid);
register(global, Name, Pid) ->
global:re_register_name(Name, Pid).
unregister(local, Name) ->
erlang:unregister(Name);
unregister(global, Name) ->
global:unregister_name(Name).
is_process_alive(Pid) ->
try
case Pid of
_ when is_pid(Pid) ->
Node = node(),
Result = case node(Pid) of
Node -> erlang:is_process_alive(Pid);
Node1 -> rpc:call(Node1, erlang, is_process_alive, [Pid])
end,
case Result of
{badrpc, _Reason} -> false;
Res -> Res
end;
_ -> false
end
catch
_:_ -> false
end.
create_process_name(Prefix, List) ->
to_atom(lists:concat(lists:flatten([Prefix] ++ lists:map(fun(T) -> ['_', T] end, List)))).
to_atom(Msg) when is_atom(Msg) ->
Msg;
to_atom(Msg) when is_binary(Msg) ->
list_to_atom2(binary_to_list(Msg));
to_atom(Msg) when is_list(Msg) ->
list_to_atom2(Msg);
to_atom(_) ->
throw(other_value). %%list_to_atom("").
list_to_atom2(List) when is_list(List) ->
case catch (list_to_existing_atom(List)) of
{'EXIT', _} -> erlang:list_to_atom(List);
Atom when is_atom(Atom) -> Atom
end.
%%------------------------------------------------
%% Admin API
%%------------------------------------------------
%% @spec hot/0 -> ok
%% @doc TODO:
%% @doc 线beam文件
hot() ->
HotTime = svr_handle_mgr:hot_time() - 360,
Now = ?NOW,
case max(0, Now - HotTime) of
TimeLimit when TimeLimit > 0 ->
hot_beam(TimeLimit),
%
svr_activity_fl:reflash(),
ok;
_ ->
ok
end.
hot_beam(TimeLimit) when TimeLimit > 0 ->
Now = ?NOW,
FilePaths = all_ebin_file(),
io:format("-----------------------------------------------~n"),
io:format("hots ~p ~p~n", [node(), config:server_ids()]),
io:format("~n"),
lists:foreach(fun(FilePath) ->
case file:read_file_info(FilePath) of
{ok, #file_info{mtime = Mtime}} ->
Time = util:datetime_to_seconds(Mtime),
case Now - Time =< TimeLimit of
true ->
Module = filename:basename(FilePath, ".beam"),
u(list_to_atom(Module));
_ ->
ok
end;
_ ->
ok
end
end, FilePaths),
io:format("~n"),
io:format("-----------------------------------------------~n");
hot_beam(_) ->
ok.
%% @doc
all_ebin_file() ->
LogicNames = filelib:wildcard("../ebin/*.beam"),
DepsNames = filelib:wildcard("../deps/*/ebin/*.beam"),
DepsNames ++ LogicNames.
%% @doc
u(M) when not is_list(M) ->
u([M], []);
u(List) ->
u(List, []).
u([], List) ->
List;
u([Module | T], List) ->
Ret = u_one(Module),
u(T, [{Ret, Module} | List]).
u_one(Module) ->
case c:nl(Module) of
abcast ->
?PRINT("~w:load ~20w ok", [calendar:local_time(), Module]),
ok;
_ ->
?PRINT("~w:load ~20w fail", [calendar:local_time(), Module]),
error
end.
%% @spec top() -> ok
%% @doc
top() ->
Release = erlang:system_info(otp_release),
SchedNum = erlang:system_info(schedulers),
ProcCount = erlang:system_info(process_count),
ProcLimit = erlang:system_info(process_limit),
ProcMemUsed = erlang:memory(processes_used),
EtsMemAlc = erlang:memory(ets),
MemTot = erlang:memory(total),
RoleNum = ets:info(?ETS_ONLINE, size),
%PetNum = all_pets(),
io:format(
"++++++++++++++++++++++++++++++++++++++++++~n"
" ServerId: ~p~n"
" Node: ~p~n"
" Erlang Ver: ~p~n"
" Free Threads: ~p~n"
" Process Used Memory: ~pMb~n"
" Ets Used Memory: ~pMb~n"
" Erlang VM Used Memory: ~pMb~n"
" Process Limit: ~p~n"
" Process Used: ~p~n"
" Online Players: ~p~n"
"++++++++++++++++++++++++++++++++++++++++++~n"
, [config:server_ids(), node(), Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]),
ok.
%% @doc
top_back() ->
Release = erlang:system_info(otp_release),
SchedNum = erlang:system_info(schedulers),
ProcCount = erlang:system_info(process_count),
ProcLimit = erlang:system_info(process_limit),
ProcMemUsed = erlang:memory(processes_used),
EtsMemAlc = erlang:memory(ets),
MemTot = erlang:memory(total),
RoleNum = ets:info(?ETS_ONLINE, size),
Str = io_lib:format(
" Erlang 版本: ~p~n"
" 可使用的调度线程: ~p~n"
" 所有进程使用的内存: ~pMb~n"
" 所有ets使用的内存: ~pMb~n"
" Erlang系统占用内存: ~pMb~n"
" 可创建进程数量上限: ~p~n"
" 当前进程数: ~p~n"
" 在线角色数: ~p~n"
, [Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]),
binary_to_list(list_to_binary(Str)).
%% @spec ets_mem() -> term()
%% @doc 30ets表
ets_mem() ->
L = ets:all(),
Mems = lists:map(fun(Tab) ->
Info = ets:info(Tab),
case lists:keyfind(memory, 1, Info) of
{memory, Mem} -> {Tab, Mem};
_ -> {Tab, 0}
end
end, L),
L1 = lists:sublist(lists:reverse(lists:keysort(2, Mems)), 30),
?PRINT("~n--------------------------------------------------~n"
"~-30w ~w~n--------------------------------------------------~n"
, [table, used_memory]),
lists:foreach(fun({Tab, Mem}) ->
?PRINT("~-30w ~wKb~n", [Tab, Mem / 1024])
end, L1).
%% @spec tcp_links() -> Info
%% @doc tcp链接
tcp_links() ->
L = erlang:ports(),
F = fun(P) ->
Pinfo = erlang:port_info(P),
case lists:keyfind(name, 1, Pinfo) of
{name, "tcp_inet"} -> true;
_ -> false
end
end,
L1 = lists:filter(F, L),
?PRINT("~n当前socket数量(包括链接数据库的socket): ~w~n", [length(L1)]).
% %% @doc trace
% tan(AcountName) ->
% Bin = unicode:characters_to_binary(AcountName),
% [t(UserID)||#ets_user{account_name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin].
% %% @doc trace
% tun(UserName) ->
% Bin = unicode:characters_to_binary(UserName),
% [t(UserID) ||#ets_user{name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin].
% %% @doc ID trace
% t(UserID, MFN) ->
% t(UserID),
% t(MFN).
% t({M, F, Num}) ->
% dbg:tpl(M, F, Num, []);
% t(UserID) ->
% dbg:tracer(),
% Pid = misc:whereis_name({global, player_process_name(UserID)}),
% dbg:p(Pid, c).
% tr({M, F, Num}) ->
% dbg:tpl(M, F, Num, [{'_', [], [{return_trace}]}]).
% %% @doc trace
% t_clear() ->
% dbg:stop_clear().
%% @doc
dump_process_info(Pid) ->
{{Year, Month, Day}, {Hour, Minutes, Second}} = util:local_time(),
{ok, FileHandle} = file:open(util:fbin("~s-~w-~w-~w-~w-~w-~w", [<<"../logs/pid_info.dump">>, Year, Month, Day, Hour, Minutes, Second]), write),
case erlang:process_info(Pid) of
Info when is_list(Info) ->
lists:foreach(fun({messages, Messages}) ->
case Messages =:= [] of
true ->
io:format(FileHandle, "~w~n", [{messages, Messages}]);
_ ->
io:format(FileHandle, "{messages,~n", []),
lists:foreach(fun(M) ->
io:format(FileHandle, " ~w~n", [M])
end, Messages),
io:format(FileHandle, "}~n", [])
end;
({dictionary, Dics}) ->
case Dics =:= [] of
true ->
io:format(FileHandle, "~w~n", [{dictionary, Dics}]);
_ ->
io:format(FileHandle, "{dictionary,~n", []),
lists:foreach(fun(M) ->
io:format(FileHandle, " ~w~n", [M])
end, Dics),
io:format(FileHandle, "}~n", [])
end;
(E) ->
io:format(FileHandle, "~w~n", [E])
end, Info);
_ -> ?PRINT("not find pid info")
end,
file:close(FileHandle).
request(Url) ->
{ok, RequestId} = httpc:request(get, {Url, []}, [], [{sync, false}]),
receive
{http, {RequestId, {{_Version, 200, _ReasonPhrase}, _Headers, Body}}} ->
Body;
E ->
E
after 500 ->
timeout
end.

+ 1184
- 0
src/srvNodeMgr/baizhan/misc/util.erl
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 714
- 0
src/srvNodeMgr/misc.erl Dosyayı Görüntüle

@ -0,0 +1,714 @@
-module(misc).
%%
%% Include files
%%
-include("common.hrl").
-include("cache.hrl").
-include("item.hrl").
-include_lib("kernel/include/file.hrl").
%%
%% Exported Functions
%%
-export([
whereis_name/1,
register/3,
unregister/2,
is_process_alive/1,
create_process_name/2,
to_atom/1,
% t/1,
% t/2,
% tr/1,
% tun/1,
% tan/1,
% t_clear/0,
dump_process_info/1
, u/1
, hot/0
, hot_beam/1 %% beam文件使
, ets_mem/0
, tcp_links/0
, top_back/0
, top/0
, request/1
, u_one/1
, stop/0
, del_ref/1
]).
-export([
role_cmd/3
, gm/2
, check_mem/0
, check_mem/1
, online_num/0
, is_cross/0
]).
-export([
decompile/1
, pstack/1
, etop/0
, etop_mem/0
, etop_stop/0
, gc_all/0
, fprof/3
, eprof_all/1
, eprof/2
, scheduler_usage/0
, scheduler_usage/1
, scheduler_stat/0
, scheduler_stat/1
, trace/1
, trace/2
, trace_stop/0
, proc_mem_all/1
, proc_mem/1
, crash_dump/0
, process_infos/0
]).
-export([check_item/0, ints2str/2]).
%%
%% API Functions
%%
%% @doc ref
del_ref(Ref) when is_reference(Ref) ->
erlang:cancel_timer(Ref);
del_ref(_) ->
ok.
%% @doc
process_infos() ->
filelib:ensure_dir("./logs/"),
File = "./logs/processes_infos.log",
{ok, Fd} = file:open(File, [write, raw, binary, append]),
Fun = fun(Pi) ->
Info = io_lib:format("=>~p \n\n", [Pi]),
case filelib:is_file(File) of
true -> file:write(Fd, Info);
false ->
file:close(Fd),
{ok, NewFd} = file:open(File, [write, raw, binary, append]),
file:write(NewFd, Info)
end,
timer:sleep(20)
end,
[Fun(erlang:process_info(P)) || P <- erlang:processes()].
%% @doc erlang_dump
crash_dump() ->
Date = erlang:list_to_binary(rfc1123_local_date()),
Header = binary:list_to_bin([<<"=erl_crash_dump:0.2\n">>, Date, <<"\nSystem version: ">>]),
Ets = ets_info(),
Report = binary:list_to_bin([Header, erlang:list_to_binary(erlang:system_info(system_version)),
erlang:system_info(info), erlang:system_info(procs), Ets, erlang:system_info(dist),
<<"=loaded_modules\n">>, binary:replace(erlang:system_info(loaded),
<<"\n">>, <<"\n=mod:">>, [global])]),
file:write_file("erl_crash.dump", Report).
ets_info() ->
binary:list_to_bin([ets_table_info(T) || T <- ets:all()]).
ets_table_info(Table) ->
Info = ets:info(Table),
Owner = erlang:list_to_binary(erlang:pid_to_list(proplists:get_value(owner, Info))),
TableN = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))),
Name = erlang:list_to_binary(erlang:atom_to_list(proplists:get_value(name, Info))),
Objects = erlang:list_to_binary(erlang:integer_to_list(proplists:get_value(size, Info))),
binary:list_to_bin([<<"=ets:">>, Owner, <<"\nTable: ">>, TableN, <<"\nName: ">>, Name,
<<"\nObjects: ">>, Objects, <<"\n">>]).
rfc1123_local_date() ->
rfc1123_local_date(os:timestamp()).
rfc1123_local_date({A, B, C}) ->
rfc1123_local_date(calendar:now_to_local_time({A, B, C}));
rfc1123_local_date({{YYYY, MM, DD}, {Hour, Min, Sec}}) ->
DayNumber = calendar:day_of_the_week({YYYY, MM, DD}),
lists:flatten(
io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT",
[httpd_util:day(DayNumber), DD, httpd_util:month(MM), YYYY, Hour, Min, Sec]));
rfc1123_local_date(Epoch) when erlang:is_integer(Epoch) ->
rfc1123_local_date(calendar:gregorian_seconds_to_datetime(Epoch + 62167219200)).
%% @doc etop 10w+ , proc后通过pstackmessage_queu_len
proc_mem_all(SizeLimitKb) ->
Procs = [{undefined, Pid} || Pid <- erlang:processes()],
proc_mem(Procs, SizeLimitKb).
proc_mem(SizeLimitKb) ->
Procs = [{Name, Pid} || {_, Name, Pid, _} <- release_handler_1:get_supervised_procs(), erlang:is_process_alive(Pid)],
proc_mem(Procs, SizeLimitKb).
proc_mem(Procs, SizeLimitKb) ->
SizeLimit = SizeLimitKb * 1024,
{R, Total} = lists:foldl(fun({Name, Pid}, {Acc, TotalSize}) ->
case erlang:process_info(Pid, total_heap_size) of
{_, Size0} ->
Size = Size0 * 8,
case Size > SizeLimit of
true -> {[{Name, Pid, Size} | Acc], TotalSize + Size};
false -> {Acc, TotalSize}
end;
_ -> {Acc, TotalSize}
end
end, {[], 0}, Procs),
R1 = lists:keysort(3, R),
{Total, lists:reverse(R1)}.
%trace Mod
trace(Mod) ->
dbg:tracer(),
dbg:tpl(Mod, '_', []),
dbg:p(all, c).
%trace Node上指定 Mod , shell
trace(Node, Mod) ->
dbg:tracer(),
dbg:n(Node),
dbg:tpl(Mod, '_', []),
dbg:p(all, c).
%trace
trace_stop() ->
dbg:stop_clear().
% 1s内调度进程数量()
scheduler_stat() ->
scheduler_stat(1000).
scheduler_stat(RunMs) ->
erlang:system_flag(scheduling_statistics, enable),
Ts0 = erlang:system_info(total_scheduling_statistics),
timer:sleep(RunMs),
Ts1 = erlang:system_info(total_scheduling_statistics),
erlang:system_flag(scheduling_statistics, disable),
lists:map(fun({{Key, In0, Out0}, {Key, In1, Out1}}) ->
{Key, In1 - In0, Out1 - Out0} end, lists:zip(Ts0, Ts1)).
% 1s每个调度器CPU的实际利用率(spin wait, usage top显示低很多)
scheduler_usage() ->
scheduler_usage(1000).
scheduler_usage(RunMs) ->
erlang:system_flag(scheduler_wall_time, true),
Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)),
timer:sleep(RunMs),
Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)),
erlang:system_flag(scheduler_wall_time, false),
Cores = lists:map(fun({{I, A0, T0}, {I, A1, T1}}) ->
{I, (A1 - A0) / (T1 - T0)} end, lists:zip(Ts0, Ts1)),
{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai, Ti}) ->
{Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0, Ts1)),
Total = A / T,
io:format("~p~n", [[{total, Total} | Cores]]).
% eprof, eprof 线,!
% TimeoutSec<10s< 1000crash
% :
% mod调用执行时间
% mod - Fun
eprof_all(TimeoutSec) ->
eprof(processes() -- [whereis(eprof)], TimeoutSec).
eprof(Pids, TimeoutSec) ->
eprof:start(),
eprof:start_profiling(Pids),
timer:sleep(TimeoutSec),
eprof:stop_profiling(),
eprof:analyze(total),
eprof:stop().
% @doc MFA
% :
% fprof
fprof(M, F, A) ->
fprof:start(),
fprof:apply(M, F, A),
fprof:profile(),
fprof:analyse([{dest, "fprof.analysis"}, {sort, own}]),
fprof:stop().
% @doc process做gc
gc_all() ->
[erlang:garbage_collect(Pid) || Pid <- processes()].
% @doc CPU占用排名
etop() ->
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, runtime}]) end).
% @doc Mem占用排名
etop_mem() ->
spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, memory}]) end).
% @doc etop
etop_stop() ->
etop:stop().
%% @doc jstackhang住等问题用到
pstack(Reg) when is_atom(Reg) ->
case whereis(Reg) of
undefined -> undefined;
Pid -> pstack(Pid)
end;
pstack(Pid) ->
io:format("~s~n", [element(2, process_info(Pid, backtrace))]).
%% @doc 600M的全部强制GC
check_mem() ->
Total = erlang:memory(total),
case Total > 600000000 of
true ->
spawn(fun() -> [erlang:garbage_collect(Pid) || Pid <- processes()] end);
_ ->
ok
end.
% check_mem(1000000000).
%% gc,
check_mem(MemLim) ->
lists:foreach(
fun(P) ->
case is_pid(P) andalso erlang:is_process_alive(P) of
true ->
{memory, Mem} = erlang:process_info(P, memory),
case Mem > MemLim of
true ->
erlang:garbage_collect(P);
false ->
[]
end;
false ->
[]
end
end, erlang:processes()).
%% @doc GM命令
gm(RoleId, Content) ->
role_cmd(RoleId, 11600, [Content]).
%% @doc
role_cmd(RoleId, Cmd, Data) ->
svr_role:apply(async, RoleId, {lib_role, async_cmd, [Cmd, Data]}).
%% @doc
stop() ->
case is_cross() of
true ->
cross_stop();
_ ->
common_stop()
end.
%% @doc
common_stop() ->
AllRoles = ets:tab2list(?ETS_ONLINE),
[Pid ! {'stop', server_stop} || #role{pid = Pid} <- AllRoles],%线
cowboy:stop_listener(http),
catch svr_cache_mgr:do_save(),
catch svr_chat:save_chat(),
catch svr_rank:hand_save(),
catch svr_log:hand_save(),
case catch check_item() of
{'EXIT', Res} ->
?INF("error:~p", [Res]);
_ ->
ok
end,
?INF("server_stop"),
init:stop().
%% @doc
check_item() ->
List = ets:tab2list(?ETS_CACHE_ITEM_ROLE),
check_item(List).
check_item([{RoleId, Ids = [_ | _]} | T]) ->
SelectSql = io_lib:format(<<"select id from player_item where role_id=~p;">>, [RoleId]),
IdVals = db:execute(SelectSql),
case filter_item_ids(IdVals, Ids, []) of
[_ | IdStrs] ->
Sql = io_lib:format(<<"delete from player_item where id in (~s);">>, [IdStrs]),
db:execute(Sql);
_ ->
ok
end,
save_eq(Ids),
check_item(T);
check_item([_ | T]) ->
check_item(T);
check_item([]) ->
ok.
%% @doc
save_eq(Ids) ->
case find_eq_item(Ids, []) of
[_ | SqlVals] ->
Sql = io_lib:format(?SQL_ITEM_BATCH_REPLACE, [SqlVals]),
db:execute(Sql);
_ ->
ok
end.
find_eq_item([Id | T], L) ->
L1 =
case svr_cache_item:find_item(Id) of
Item = #item{slot = Slot} ->
case Slot > 0 orelse lib_awake_equip:is_awake(Item) of
true ->
"," ++ lib_item_dict:make_batch_insert_sql_one(Item) ++ L;
_ ->
L
end;
_ ->
L
end,
find_eq_item(T, L1);
find_eq_item([], L) ->
L.
%% @doc
filter_item_ids([[Id] | T], Ids, L) ->
L1 =
case lists:member(Id, Ids) of
false ->
IdStr = integer_to_list(Id),
"," ++ IdStr ++ L;
_ ->
L
end,
filter_item_ids(T, Ids, L1);
filter_item_ids([], _, L) ->
L.
ints2str([Id | T], L) ->
IdStr = integer_to_list(Id),
case T of
[] ->
ints2str(T, IdStr ++ L);
_ ->
ints2str(T, "," ++ IdStr ++ L)
end;
ints2str([], L) ->
L.
%% @doc
cross_stop() ->
catch svr_kfboss_awake_mgr:stop(),
catch svr_kfnode:stop(),
init:stop().
%% @doc
is_cross() ->
case config:get_platform() of
"cross" ->
true;
_ ->
false
end.
%% @doc PID
whereis_name({local, Atom}) ->
erlang:whereis(Atom);
whereis_name({global, Atom}) ->
global:whereis_name(Atom).
register(local, Name, Pid) ->
erlang:register(Name, Pid);
register(global, Name, Pid) ->
global:re_register_name(Name, Pid).
unregister(local, Name) ->
erlang:unregister(Name);
unregister(global, Name) ->
global:unregister_name(Name).
is_process_alive(Pid) ->
try
case Pid of
_ when is_pid(Pid) ->
Node = node(),
Result = case node(Pid) of
Node -> erlang:is_process_alive(Pid);
Node1 -> rpc:call(Node1, erlang, is_process_alive, [Pid])
end,
case Result of
{badrpc, _Reason} -> false;
Res -> Res
end;
_ -> false
end
catch
_:_ -> false
end.
create_process_name(Prefix, List) ->
to_atom(lists:concat(lists:flatten([Prefix] ++ lists:map(fun(T) -> ['_', T] end, List)))).
to_atom(Msg) when is_atom(Msg) ->
Msg;
to_atom(Msg) when is_binary(Msg) ->
list_to_atom2(binary_to_list(Msg));
to_atom(Msg) when is_list(Msg) ->
list_to_atom2(Msg);
to_atom(_) ->
throw(other_value). %%list_to_atom("").
list_to_atom2(List) when is_list(List) ->
case catch (list_to_existing_atom(List)) of
{'EXIT', _} -> erlang:list_to_atom(List);
Atom when is_atom(Atom) -> Atom
end.
%%------------------------------------------------
%% Admin API
%%------------------------------------------------
%% @spec hot/0 -> ok
%% @doc TODO:
%% @doc 线beam文件
hot() ->
HotTime = svr_handle_mgr:hot_time() - 360,
Now = ?NOW,
case max(0, Now - HotTime) of
TimeLimit when TimeLimit > 0 ->
hot_beam(TimeLimit),
%
svr_activity_fl:reflash(),
ok;
_ ->
ok
end.
hot_beam(TimeLimit) when TimeLimit > 0 ->
Now = ?NOW,
FilePaths = all_ebin_file(),
io:format("-----------------------------------------------~n"),
io:format("hots ~p ~p~n", [node(), config:server_ids()]),
io:format("~n"),
lists:foreach(fun(FilePath) ->
case file:read_file_info(FilePath) of
{ok, #file_info{mtime = Mtime}} ->
Time = util:datetime_to_seconds(Mtime),
case Now - Time =< TimeLimit of
true ->
Module = filename:basename(FilePath, ".beam"),
u(list_to_atom(Module));
_ ->
ok
end;
_ ->
ok
end
end, FilePaths),
io:format("~n"),
io:format("-----------------------------------------------~n");
hot_beam(_) ->
ok.
%% @doc
all_ebin_file() ->
LogicNames = filelib:wildcard("../ebin/*.beam"),
DepsNames = filelib:wildcard("../deps/*/ebin/*.beam"),
DepsNames ++ LogicNames.
%% @doc
u(M) when not is_list(M) ->
u([M], []);
u(List) ->
u(List, []).
u([], List) ->
List;
u([Module | T], List) ->
Ret = u_one(Module),
u(T, [{Ret, Module} | List]).
u_one(Module) ->
case c:nl(Module) of
abcast ->
?PRINT("~w:load ~20w ok", [calendar:local_time(), Module]),
ok;
_ ->
?PRINT("~w:load ~20w fail", [calendar:local_time(), Module]),
error
end.
%% @spec top() -> ok
%% @doc
top() ->
Release = erlang:system_info(otp_release),
SchedNum = erlang:system_info(schedulers),
ProcCount = erlang:system_info(process_count),
ProcLimit = erlang:system_info(process_limit),
ProcMemUsed = erlang:memory(processes_used),
EtsMemAlc = erlang:memory(ets),
MemTot = erlang:memory(total),
RoleNum = ets:info(?ETS_ONLINE, size),
%PetNum = all_pets(),
io:format(
"++++++++++++++++++++++++++++++++++++++++++~n"
" ServerId: ~p~n"
" Node: ~p~n"
" Erlang Ver: ~p~n"
" Free Threads: ~p~n"
" Process Used Memory: ~pMb~n"
" Ets Used Memory: ~pMb~n"
" Erlang VM Used Memory: ~pMb~n"
" Process Limit: ~p~n"
" Process Used: ~p~n"
" Online Players: ~p~n"
"++++++++++++++++++++++++++++++++++++++++++~n"
, [config:server_ids(), node(), Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]),
ok.
%% @doc
top_back() ->
Release = erlang:system_info(otp_release),
SchedNum = erlang:system_info(schedulers),
ProcCount = erlang:system_info(process_count),
ProcLimit = erlang:system_info(process_limit),
ProcMemUsed = erlang:memory(processes_used),
EtsMemAlc = erlang:memory(ets),
MemTot = erlang:memory(total),
RoleNum = ets:info(?ETS_ONLINE, size),
Str = io_lib:format(
" Erlang 版本: ~p~n"
" 可使用的调度线程: ~p~n"
" 所有进程使用的内存: ~pMb~n"
" 所有ets使用的内存: ~pMb~n"
" Erlang系统占用内存: ~pMb~n"
" 可创建进程数量上限: ~p~n"
" 当前进程数: ~p~n"
" 在线角色数: ~p~n"
, [Release, SchedNum, ProcMemUsed / 1024 / 1024, EtsMemAlc / 1024 / 1024, MemTot / 1024 / 1024, ProcLimit, ProcCount, RoleNum]),
binary_to_list(list_to_binary(Str)).
%% @spec ets_mem() -> term()
%% @doc 30ets表
ets_mem() ->
L = ets:all(),
Mems = lists:map(fun(Tab) ->
Info = ets:info(Tab),
case lists:keyfind(memory, 1, Info) of
{memory, Mem} -> {Tab, Mem};
_ -> {Tab, 0}
end
end, L),
L1 = lists:sublist(lists:reverse(lists:keysort(2, Mems)), 30),
?PRINT("~n--------------------------------------------------~n"
"~-30w ~w~n--------------------------------------------------~n"
, [table, used_memory]),
lists:foreach(fun({Tab, Mem}) ->
?PRINT("~-30w ~wKb~n", [Tab, Mem / 1024])
end, L1).
%% @spec tcp_links() -> Info
%% @doc tcp链接
tcp_links() ->
L = erlang:ports(),
F = fun(P) ->
Pinfo = erlang:port_info(P),
case lists:keyfind(name, 1, Pinfo) of
{name, "tcp_inet"} -> true;
_ -> false
end
end,
L1 = lists:filter(F, L),
?PRINT("~n当前socket数量(包括链接数据库的socket): ~w~n", [length(L1)]).
% %% @doc trace
% tan(AcountName) ->
% Bin = unicode:characters_to_binary(AcountName),
% [t(UserID)||#ets_user{account_name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin].
% %% @doc trace
% tun(UserName) ->
% Bin = unicode:characters_to_binary(UserName),
% [t(UserID) ||#ets_user{name = Name, id = UserID} <- ets:tab2list(?ETS_ONLINE), Name =:= Bin].
% %% @doc ID trace
% t(UserID, MFN) ->
% t(UserID),
% t(MFN).
% t({M, F, Num}) ->
% dbg:tpl(M, F, Num, []);
% t(UserID) ->
% dbg:tracer(),
% Pid = misc:whereis_name({global, player_process_name(UserID)}),
% dbg:p(Pid, c).
% tr({M, F, Num}) ->
% dbg:tpl(M, F, Num, [{'_', [], [{return_trace}]}]).
% %% @doc trace
% t_clear() ->
% dbg:stop_clear().
%% @doc
dump_process_info(Pid) ->
{{Year, Month, Day}, {Hour, Minutes, Second}} = util:local_time(),
{ok, FileHandle} = file:open(util:fbin("~s-~w-~w-~w-~w-~w-~w", [<<"../logs/pid_info.dump">>, Year, Month, Day, Hour, Minutes, Second]), write),
case erlang:process_info(Pid) of
Info when is_list(Info) ->
lists:foreach(fun({messages, Messages}) ->
case Messages =:= [] of
true ->
io:format(FileHandle, "~w~n", [{messages, Messages}]);
_ ->
io:format(FileHandle, "{messages,~n", []),
lists:foreach(fun(M) ->
io:format(FileHandle, " ~w~n", [M])
end, Messages),
io:format(FileHandle, "}~n", [])
end;
({dictionary, Dics}) ->
case Dics =:= [] of
true ->
io:format(FileHandle, "~w~n", [{dictionary, Dics}]);
_ ->
io:format(FileHandle, "{dictionary,~n", []),
lists:foreach(fun(M) ->
io:format(FileHandle, " ~w~n", [M])
end, Dics),
io:format(FileHandle, "}~n", [])
end;
(E) ->
io:format(FileHandle, "~w~n", [E])
end, Info);
_ -> ?PRINT("not find pid info")
end,
file:close(FileHandle).
request(Url) ->
{ok, RequestId} = httpc:request(get, {Url, []}, [], [{sync, false}]),
receive
{http, {RequestId, {{_Version, 200, _ReasonPhrase}, _Headers, Body}}} ->
Body;
E ->
E
after 500 ->
timeout
end.

+ 186
- 0
src/srvNodeMgr/tools/gameWorld/test/excel2mysql.erl Dosyayı Görüntüle

@ -0,0 +1,186 @@
-module(excel2mysql).
%%
%% Include files
%%
-include("common.hrl").
-compile(export_all).
-define(CONFIG_FILE, "../config/gateway.config").
-define(TMP_TABLE_PATH, "./tmptable/").
-define(SRC_TABLE_PATH, "../src/table/").
-define(RECORD_FILENAME, "../include/table_to_record.hrl").
-define(BEAM_PATH, "./").
-define(EXCEL_PATH, "../temp/excel2mysql/").
%%
%% API Functions
%%
start() ->
case get_db_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB, Encode] ->
start_erlydb(Host, Port, User, Password, DB),
mysql:start_link(?DB_POOL, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?DB_POOL, Host, Port, User, Password, DB, Encode, true),
excel_to_mysql_base_goods_practise();
_ -> mysql_config_fail
end,
ok.
get_db_config(Config_file) ->
try
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(mysql_config, 1, C),
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode]
catch
_:_ -> no_config
end.
%%
%% Local Functions
%%
start_erlydb(IP, Port, User, Password, Db) ->
erlydb:start(mysql, [{pool_id, erlydb_mysql},
{hostname, IP},
{port, Port},
{username, User},
{password, Password},
{database, Db},
{encoding, utf8},
{pool_size, 10}]).
excel_to_mysql_base_goods_practise() ->
Practise_path = lists:concat([?EXCEL_PATH, 'base_goods_practise']),
case file:list_dir(Practise_path) of
{ok, Filenames} ->
lists:foreach(fun(F) ->
case string:rstr(F, ".txt") > 0 of
true ->
base_goods_practise_0(Practise_path ++ "/" ++ F),
ok;
_ -> no_action
end,
ok
end,
lists:sort(Filenames));
{error, _} -> ignore
end,
ok.
base_goods_practise_0(Filename) ->
io:format("__1__~p~n", [Filename]),
{ok, IoDevice} = file:open(Filename, [read]),
try
%% (09)_绿(1)_
%%
%%
%% 9/1
%% max_attack/min_attack/hit/agile/physique
{ok, _Line1} = file:read_line(IoDevice),
{ok, _Line2} = file:read_line(IoDevice),
{ok, _Line3} = file:read_line(IoDevice),
{ok, Line4} = file:read_line(IoDevice),
{ok, Line5} = file:read_line(IoDevice),
[Line4_0] = string:tokens(Line4, "\n"),
[Line5_0] = string:tokens(Line5, "\n"),
%% io:format(" ~p~n ~p~n", [Line4_0, Line5_0]),
[Subtype, Color] = string:tokens(Line4_0, "/"),
Attrs = string:tokens(Line5_0, "/"),
base_goods_practise_1(IoDevice,
tool:to_integer(Subtype),
tool:to_integer(Color),
Attrs
),
file:close(IoDevice),
ok
catch
_:_ -> file:close(IoDevice)
end,
ok.
base_goods_practise_1(IoDevice, Subtype, Color, Attrs) ->
%% io:format(" ~p~n", [[Subtype, Color, Attrs, Att_num]]),
case file:read_line(IoDevice) of
{ok, Line} ->
[Line_0] = string:tokens(Line, "\n"),
Vals0 = string:tokens(Line_0, ","),
[Grade0 | Vals] = Vals0,
Grade = tool:to_integer(Grade0),
%% io:format(" ~p~n", [Grade]),
base_goods_practise_2(Subtype, Color, Attrs, Grade, Vals, 10),
base_goods_practise_1(IoDevice, Subtype, Color, Attrs);
eof ->
{ok, finshed};
{error, Reason} ->
{error, Reason}
end.
base_goods_practise_2(_Subtype, _Color, _Attrs, _Grade, [], _Step) ->
ok;
base_goods_practise_2(Subtype, Color, Attrs, Grade, Vals, Step) ->
%% io:format(" ~p/~p/~p~n", [Grade, Step, length(Vals)]),
case length(Attrs) of
5 -> Att_num = 1,
{L1, L2} = lists:split(length(Vals) - 5, Vals),
%% (09)_绿(1)_
%%
%%
%% 9/1
%% max_attack/min_attack/hit/agile/physique
io:format("Here_1_~n", []),
[Field1, Field2, Field3, Field4, Field5] = Attrs,
io:format("Here_2_~n", []),
[Val1, Val2, Val3, Val4, Val5] = L2,
io:format("Here_3_~n", []),
Field_Value_List = [{att_num, Att_num}, {subtype, Subtype}, {step, Step}, {color, Color}, {grade, Grade}]
++ [{tool:to_atom(Field1), tool:to_integer(Val1)}]
++ [{tool:to_atom(Field2), tool:to_integer(Val2)}]
++ [{tool:to_atom(Field3), tool:to_integer(Val3)}]
++ [{tool:to_atom(Field4), tool:to_integer(Val4)}]
++ [{tool:to_atom(Field5), tool:to_integer(Val5)}],
io:format("Here_4_/~p/~n", [Field_Value_List]),
Sql = make_replace_sql(base_goods_practise, Field_Value_List),
%% io:format(" ~p/~p/~p/~p~n", [Grade, Step, length(Vals), Sql]),
db_sql:execute(Sql),
base_goods_practise_2(Subtype, Color, Attrs, Grade, L1, Step - 1),
ok;
7 -> _Att_num = 2,
{L1, _L2} = lists:split(length(Vals) - 7, Vals),
base_goods_practise_2(Subtype, Color, Attrs, Grade, L1, Step - 1),
ok
end,
ok.
make_replace_sql(Table_name, Field_Value_List) ->
{Vsql, _Count1} =
lists:mapfoldl(
fun(Field_value, Sum) ->
Expr = case Field_value of
{Field, Val} ->
case is_binary(Val) orelse is_list(Val) of
true ->
io_lib:format("`~s`='~s'", [Field, re:replace(Val, "'", "''", [global, {return, binary}])]);
_ -> io_lib:format("`~s`='~p'", [Field, Val])
end
end,
S1 = if Sum == length(Field_Value_List) -> io_lib:format("~s ", [Expr]);
true -> io_lib:format("~s,", [Expr])
end,
{S1, Sum + 1}
end,
1, Field_Value_List),
lists:concat(["replace into `", Table_name, "` set ",
lists:flatten(Vsql)
]).

+ 124
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/auto_id.erl Dosyayı Görüntüle

@ -0,0 +1,124 @@
%%--------------------------------------
%% @Module : auto_id
%% @Author : smxx
%% @Created : 2013.03.01
%% @Description: ID初值
%%--------------------------------------
-module(auto_id).
-compile([export_all]).
-include("auto_id.hrl").
%%ID初值(. )
set_auto_increment(server) ->
ServerNum = config:get_server_num(),
io:format("~n--------------------------------------------------~n"),
io:format("Start checking tables Auto Increment...~n"),
io:format("Current Server Num: ~p~n", [ServerNum]),
io:format("--------------------------------------------------~n"),
F = fun(TableName) ->
case get_auto_increment_width(TableName) of
no_match ->
io:format("Table: ~p found NO AUTO_INCREMENT fields, check your configuration!~n", [TableName]);
Width -> %%
case Width of
20 ->
Start = ServerNum * ?SPACE20 + 1,
End = (ServerNum + 1) * ?SPACE20;
11 ->
Start = ServerNum * ?SPACE11 + 1,
End = (ServerNum + 1) * ?SPACE11
end,
CurrentOffset = get_auto_increment_offset(TableName),
if
%% CurrentOffset >= Start andalso CurrentOffset < End -> %%
%% io:format("Table: ~p \tAUTO_INCREMENT OFFSET ->\tOK~n", [TableName]),
%% io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]);
%% CurrentOffset >= End ->
%% io:format("Table: ~p \tAUTO_INCREMENT OFFSET -> OUT OF RANGE~n", [TableName]),
%% io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]);
CurrentOffset > ?SPACE20 -> %%
io:format("Table: ~p \t AUTO_INCREMENT OFFSET ->\tOK~n", [TableName]),
io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n~n", [CurrentOffset, Start, End]);
true ->
io:format("Table: ~p \tAUTO_INCREMENT OFFSET -> NOT SET~n", [TableName]),
io:format("\t\tCurrent: ~p, Start: ~p, End:~p~n", [CurrentOffset, Start, End]),
io:format("\t\tSetting to: ~p", [Start]),
case set_auto_increment_offset(TableName, Start) of
true -> io:format(" -> OK~n~n");
_ -> io:format(" -> Failed~n~n")
end
end
end
end,
lists:foreach(F, ?AUTO_ID_TABLES),
io:format("~nTables Auto Increment Done~n"),
io:format("--------------------------------------------------~n");
set_auto_increment(_) ->
skip.
%%Auto_Increment字段在第11位
get_auto_increment_offset(TableName) ->
Sql = lists:concat(["show table status where name='", TableName, "'"]),
case lists:nth(11, db_esql:get_row(Sql)) of
Offset when is_integer(Offset) ->
Offset;
_Error ->
io:format("ERROR when getting Auto_Increment for table ~p~n", [TableName]),
error
end.
%%AUTO_INCREMENT字段的宽度
get_auto_increment_width(TableName) ->
Sql = lists:concat(["show create table ", TableName]),
case db_esql:get_row(Sql) of
{db_error, _} ->
error;
[_, A | _] ->
CreateTableList = re:split(A, "[\n]", [{return, binary}]),
search_auto_increment(CreateTableList)
end.
%%AUTO_INCREMENT的值
set_auto_increment_offset(TableName, Offset) ->
Sql = io_lib:format("alter table ~s auto_increment=~s;", [atom_to_list(TableName), integer_to_list(Offset)]),
case db_esql:execute_sql(Sql) of
{db_error, _} ->
false;
_Result ->
%io:format("Result: ~p~n", [Result])
true
end.
%%AUTO_INCRMENT字段的行
%%,no_match
%%: AUTO_INCREMENT行中"int(xx)"xx的值, no_match
search_auto_increment([]) ->
no_match;
search_auto_increment([L | T]) ->
Line = binary_to_list(L),
case re:run(Line, "AUTO_INCREMENT", [caseless]) of %%AUTO_INCREMENT行
{match, _} -> %%
search_int_width(Line);
_Other ->
search_auto_increment(T)
end.
%%"int(xx)"xx的值, no_match
search_int_width(Line) ->
case re:run(Line, "int", [caseless]) of
{match, [{Idx1, L1} | _]} -> %%,Idx1, L1是"int"
Idx = min(Idx1 + L1 + 1, length(Line)),
case lists:sublist(Line, Idx, 4) of %%"(xx)", 4
[40, A, B, 41] -> %%40"(", 41")",
list_to_integer([A, B]);
[40, A, 41] -> %%1
list_to_integer([A]);
_Other ->
no_match
end;
_Other ->
no_match
end.

+ 332
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/config.erl Dosyayı Görüntüle

@ -0,0 +1,332 @@
-module(config).
-include("record.hrl").
-include("common.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-compile(export_all).
%% .config里的配置信息
get_log_path(App) ->
case application:get_env(App, log_path) of
{ok, LogPath} -> LogPath;
_ -> "logs"
end.
%% .config里的配置信息
get_log_level(App) ->
case application:get_env(App, log_level) of
{ok, LogLevel} -> LogLevel;
_ -> 3
end.
%% .config里的配置信息
get_server_node(App) ->
case application:get_env(App, game_server_node) of
{ok, Node} -> Node;
_ -> ''
end.
%% key
get_charge_key(App) ->
case application:get_env(App, charge_key) of
{ok, Node} -> Node;
_ -> ''
end.
%% .config里的配置信息
get_md5_key(App) ->
case application:get_env(App, md5_key) of
{ok, Node} -> Node;
_ -> ''
end.
%% .config里的配置信息
get_platform_key(App) ->
case application:get_env(App, platform_key) of
{ok, Node} -> Node;
_ -> ''
end.
get_infant_ctrl(App) ->
%%
case application:get_env(App, infant_ctrl) of
{ok, Mode} -> tool:to_integer(Mode);
_ -> 0
end.
get_tcp_listener(App) ->
case application:get_env(App, tcp_listener) of
{ok, false} -> throw(undefined);
{ok, Tcp_listener} ->
try
{_, Port} = lists:keyfind(port, 1, Tcp_listener),
{_, Acceptor_num} = lists:keyfind(acceptor_num, 1, Tcp_listener),
{_, Max_connections} = lists:keyfind(max_connections, 1, Tcp_listener),
[Port, Acceptor_num, Max_connections]
catch
_:_ -> exit({bad_config, {server, {tcp_listener, config_error}}})
end;
undefined -> throw(undefined)
end.
get_tcp_listener_ip(App) ->
case application:get_env(App, tcp_listener_ip) of
{ok, false} -> throw(undefined);
{ok, Tcp_listener_ip} ->
try
{_, Ip} = lists:keyfind(ip, 1, Tcp_listener_ip),
[Ip]
catch
_:_ -> exit({bad_config, {server, {tcp_listener, config_error}}})
end;
undefined -> throw(undefined)
end.
get_mysql_config(App) ->
case application:get_env(App, mysql_config) of
{ok, false} -> throw(undefined);
{ok, Mysql_config} ->
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
{_, Conns} = lists:keyfind(conns, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode, Conns];
undefined -> throw(undefined)
end.
get_mysql_log_config(App) ->
case application:get_env(App, mysql_log_config) of
{ok, false} -> throw(undefined);
{ok, Mysql_config} ->
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
{_, Conns} = lists:keyfind(conns, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode, Conns];
undefined -> throw(undefined)
end.
get_mongo_config(App) ->
case application:get_env(App, emongo_config) of
{ok, false} -> throw(undefined);
{ok, Emongo_config} ->
{_, PoolId} = lists:keyfind(poolId, 1, Emongo_config),
{_, EmongoSize} = lists:keyfind(emongoSize, 1, Emongo_config),
{_, EmongoHost} = lists:keyfind(emongoHost, 1, Emongo_config),
{_, EmongoPort} = lists:keyfind(emongoPort, 1, Emongo_config),
{_, EmongoDatabase} = lists:keyfind(emongoDatabase, 1, Emongo_config),
[PoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize];
undefined -> throw(undefined)
end.
get_slave_mongo_config(App) ->
case application:get_env(App, slave_emongo_config) of
{ok, false} -> throw(undefined);
{ok, Emongo_config} ->
{_, PoolId} = lists:keyfind(poolId, 1, Emongo_config),
{_, EmongoSize} = lists:keyfind(emongoSize, 1, Emongo_config),
{_, EmongoHost} = lists:keyfind(emongoHost, 1, Emongo_config),
{_, EmongoPort} = lists:keyfind(emongoPort, 1, Emongo_config),
{_, EmongoDatabase} = lists:keyfind(emongoDatabase, 1, Emongo_config),
[PoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize];
undefined -> get_mongo_config(App)
end.
has_slave_mongo_config() ->
case application:get_env(server, slave_emongo_config) of
{ok, false} -> false;
{ok, _Emongo_config} -> true
end.
get_read_data_mode(App) ->
case application:get_env(App, base_data_from_db) of
{ok, Mode} -> tool:to_integer(Mode);
_ -> 0
end.
get_gateway_node(App) ->
case application:get_env(App, gateway_node) of
{ok, Gateway_node} -> Gateway_node;
_ -> undefined
end.
get_gateway_async_time() ->
case application:get_env(gateway, gateway_async_time) of
{ok, Async_time} -> Async_time;
_ -> undefined
end.
get_scene_here(App) ->
case application:get_env(App, scene_here) of
undefined -> [];
{ok, all} ->
MS = ets:fun2ms(fun(S) when S#temp_scene.type =< 3 -> S#temp_scene.sid end),
ets:select(?ETS_TEMP_SCENE, MS);
{ok, SL} when is_list(SL) ->
SL1 = lists:filter(fun(SId) ->
case ets:lookup(?ETS_TEMP_SCENE, SId) of
[] -> false;
[S] ->
if S#temp_scene.type =< 3 ->
true;
true ->
false
end
end
end,
SL),
SL1;
_ -> []
end.
get_guest_account_url(App) ->
case application:get_env(App, guest_account_url) of
{ok, Guest_account_url} -> Guest_account_url;
_ -> ""
end.
%% GM指令开关读取
get_can_gmcmd() ->
case application:get_env(server, can_gmcmd) of
{ok, Mode} -> tool:to_integer(Mode);
_ -> throw(undefined)
end.
get_strict_md5(App) ->
case application:get_env(App, strict_md5) of
{ok, Strict_md5} -> Strict_md5;
_ -> 1
end.
get_http_ips(App) ->
case application:get_env(App, http_ips) of
{ok, Http_ips} -> Http_ips;
_ -> []
end.
%% .config里的配置信息
get_server_number(App) ->
case application:get_env(App, server_number) of
{ok, Server_number} ->
case is_integer(Server_number) == true of
false -> 0;
true -> Server_number
end;
_ -> 0
end.
%% .config里的配置信息
get_max_id(App) ->
case application:get_env(App, max_id) of
{ok, Max_id} ->
case is_integer(Max_id) == true of
false -> 0;
true -> Max_id
end;
_ -> 0
end.
%%
get_platform_name() ->
case application:get_env(server, platform) of
{ok, Name} ->
Name;
_ ->
undefined
end.
%%
get_card_key() ->
case application:get_env(server, card_key) of
{ok, Crypto} ->
Crypto;
_ ->
undefined
end.
%%
get_server_num() ->
case application:get_env(server, server_num) of
{ok, N} ->
N;
_ ->
undefined
end.
%%
get_db_log_path() ->
case application:get_env(server, db_log_path) of
{ok, N} ->
N;
_ ->
undefined
end.
%%
get_opening_time() ->
case application:get_env(server, open_time) of
{ok, N} ->
N;
_ ->
0
end.
%%1id
get_domain() ->
case application:get_env(server, domain) of
{ok, N} ->
N;
_ ->
1
end.
%%2id
get_node_id_2() ->
case application:get_env(server, node_id_2) of
{ok, N} ->
N;
_ ->
2
end.
%%
get_client_os(Os) ->
case Os of
1 ->
<<"Android">>;
2 ->
<<"iphone">>;
_ ->
<<"未知">>
end.
%%
get_client_device_type(DeviceType) ->
case DeviceType of
1 -> <<"Android">>;
2 -> <<"iphone">>;
3 -> <<"ipad">>;
_ -> <<"未知">>
end.
%%
get_client_isp(Isp) ->
case Isp of
1 -> <<"中国移动">>;
2 -> <<"中国电信">>;
3 -> <<"中国联通">>;
_ -> "未知"
end.
%%
get_client_net_type(Net) ->
case Net of
1 -> <<"3G">>;
2 -> <<"WIFI">>;
3 -> <<"2G">>;
_ -> <<"未知">>
end.

+ 270
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/dynamic_compile.erl Dosyayı Görüntüle

@ -0,0 +1,270 @@
%% Copyright (c) 2007
%% Mats Cronqvist <mats.cronqvist@ericsson.com>
%% Chris Newcombe <chris.newcombe@gmail.com>
%% Jacob Vorreuter <jacob.vorreuter@gmail.com>
%%
%% Permission is hereby granted, free of charge, to any person
%% obtaining a copy of this software and associated documentation
%% files (the "Software"), to deal in the Software without
%% restriction, including without limitation the rights to use,
%% copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the
%% Software is furnished to do so, subject to the following
%% conditions:
%%
%% The above copyright notice and this permission notice shall be
%% included in all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
%% OTHER DEALINGS IN THE SOFTWARE.
%%%-------------------------------------------------------------------
%%% File : dynamic_compile.erl
%%% Description :
%%% Authors : Mats Cronqvist <mats.cronqvist@ericsson.com>
%%% Chris Newcombe <chris.newcombe@gmail.com>
%%% Jacob Vorreuter <jacob.vorreuter@gmail.com>
%%% - add support for limit include-file depth (and prevent circular references)
%%% prevent circular macro expansion set FILE correctly when -module() is found
%%% -include_lib support $ENVVAR in include filenames
%%% substitute-stringize (??MACRO)
%%% -undef/-ifdef/-ifndef/-else/-endif
%%% -file(File, Line)
%%%-------------------------------------------------------------------
-module(dynamic_compile).
%% API
-export([from_string/1, from_string/2]).
-import(lists, [reverse/1, keyreplace/4]).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function:
%% Description:
%% Returns a binary that can be used with
%% code:load_binary(Module, ModuleFilenameForInternalRecords, Binary).
%%--------------------------------------------------------------------
from_string(CodeStr) ->
from_string(CodeStr, []).
% takes Options as for compile:forms/2
from_string(CodeStr, CompileFormsOptions) ->
%% Initialise the macro dictionary with the default predefined macros,
%% (adapted from epp.erl:predef_macros/1
Filename = "compiled_from_string",
%%Machine = list_to_atom(erlang:system_info(machine)),
Ms0 = dict:new(),
% Ms1 = dict:store('FILE', {[], "compiled_from_string"}, Ms0),
% Ms2 = dict:store('LINE', {[], 1}, Ms1), % actually we might add special code for this
% Ms3 = dict:store('MODULE', {[], undefined}, Ms2),
% Ms4 = dict:store('MODULE_STRING', {[], undefined}, Ms3),
% Ms5 = dict:store('MACHINE', {[], Machine}, Ms4),
% InitMD = dict:store(Machine, {[], true}, Ms5),
InitMD = Ms0,
%% From the docs for compile:forms:
%% When encountering an -include or -include_dir directive, the compiler searches for header files in the following directories:
%% 1. ".", the current working directory of the file server;
%% 2. the base name of the compiled file;
%% 3. the directories specified using the i option. The directory specified last is searched first.
%% In this case, #2 is meaningless.
IncludeSearchPath = ["." | reverse([Dir || {i, Dir} <- CompileFormsOptions])],
{RevForms, _OutMacroDict} = scan_and_parse(CodeStr, Filename, 1, [], InitMD, IncludeSearchPath),
Forms = reverse(RevForms),
%% note: 'binary' is forced as an implicit option, whether it is provided or not.
case compile:forms(Forms, CompileFormsOptions) of
{ok, ModuleName, CompiledCodeBinary} when is_binary(CompiledCodeBinary) ->
{ModuleName, CompiledCodeBinary};
{ok, ModuleName, CompiledCodeBinary, []} when is_binary(CompiledCodeBinary) -> % empty warnings list
{ModuleName, CompiledCodeBinary};
{ok, _ModuleName, _CompiledCodeBinary, Warnings} ->
throw({?MODULE, warnings, Warnings});
Other ->
throw({?MODULE, compile_forms, Other})
end.
%%====================================================================
%% Internal functions
%%====================================================================
%%% Code from Mats Cronqvist
%%% See http://www.erlang.org/pipermail/erlang-questions/2007-March/025507.html
%%%## 'scan_and_parse'
%%%
%%% basically we call the OTP scanner and parser (erl_scan and
%%% erl_parse) line-by-line, but check each scanned line for (or
%%% definitions of) macros before parsing.
%% returns {ReverseForms, FinalMacroDict}
scan_and_parse([], _CurrFilename, _CurrLine, RevForms, MacroDict, _IncludeSearchPath) ->
{RevForms, MacroDict};
scan_and_parse(RemainingText, CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) ->
case scanner(RemainingText, CurrLine, MacroDict) of
{tokens, NLine, NRemainingText, Toks} ->
{ok, Form} = erl_parse:parse_form(Toks),
scan_and_parse(NRemainingText, CurrFilename, NLine, [Form | RevForms], MacroDict, IncludeSearchPath);
{macro, NLine, NRemainingText, NMacroDict} ->
scan_and_parse(NRemainingText, CurrFilename, NLine, RevForms, NMacroDict, IncludeSearchPath);
{include, NLine, NRemainingText, IncludeFilename} ->
IncludeFileRemainingTextents = read_include_file(IncludeFilename, IncludeSearchPath),
%%io:format("include file ~p contents: ~n~p~nRemainingText = ~p~n", [IncludeFilename,IncludeFileRemainingTextents, RemainingText]),
%% Modify the FILE macro to reflect the filename
%%IncludeMacroDict = dict:store('FILE', {[],IncludeFilename}, MacroDict),
IncludeMacroDict = MacroDict,
%% Process the header file (inc. any nested header files)
{RevIncludeForms, IncludedMacroDict} = scan_and_parse(IncludeFileRemainingTextents, IncludeFilename, 1, [], IncludeMacroDict, IncludeSearchPath),
%io:format("include file results = ~p~n", [R]),
%% Restore the FILE macro in the NEW MacroDict (so we keep any macros defined in the header file)
%%NMacroDict = dict:store('FILE', {[],CurrFilename}, IncludedMacroDict),
NMacroDict = IncludedMacroDict,
%% Continue with the original file
scan_and_parse(NRemainingText, CurrFilename, NLine, RevIncludeForms ++ RevForms, NMacroDict, IncludeSearchPath);
done ->
scan_and_parse([], CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath)
end.
scanner(Text, Line, MacroDict) ->
case erl_scan:tokens([], Text, Line) of
{done, {ok, Toks, NLine}, LeftOverChars} ->
case pre_proc(Toks, MacroDict) of
{tokens, NToks} -> {tokens, NLine, LeftOverChars, NToks};
{macro, NMacroDict} -> {macro, NLine, LeftOverChars, NMacroDict};
{include, Filename} -> {include, NLine, LeftOverChars, Filename}
end;
{more, _Continuation} ->
%% This is supposed to mean "term is not yet complete" (i.e. a '.' has
%% not been reached yet).
%% However, for some bizarre reason we also get this if there is a comment after the final '.' in a file.
%% So we check to see if Text only consists of comments.
case is_only_comments(Text) of
true ->
done;
false ->
throw({incomplete_term, Text, Line})
end
end.
is_only_comments(Text) -> is_only_comments(Text, not_in_comment).
is_only_comments([], _) -> true;
is_only_comments([$ | T], not_in_comment) ->
is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$\t | T], not_in_comment) ->
is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$\n | T], not_in_comment) ->
is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$% | T], not_in_comment) -> is_only_comments(T, in_comment); % found start of a comment
is_only_comments(_, not_in_comment) -> false;
% found any significant char NOT in a comment
is_only_comments([$\n | T], in_comment) -> is_only_comments(T, not_in_comment); % found end of a comment
is_only_comments([_ | T], in_comment) -> is_only_comments(T, in_comment). % skipping over in-comment chars
%%%## 'pre-proc'
%%%
%%% have to implement a subset of the pre-processor, since epp insists
%%% on running on a file.
%%% only handles 2 cases;
%% -define(MACRO, something).
%% -define(MACRO(VAR1,VARN),{stuff,VAR1,more,stuff,VARN,extra,stuff}).
pre_proc([{'-', _}, {atom, _, define}, {'(', _}, {_, _, Name} | DefToks], MacroDict) ->
false = dict:is_key(Name, MacroDict),
case DefToks of
[{',', _} | Macro] ->
{macro, dict:store(Name, {[], macro_body_def(Macro, [])}, MacroDict)};
[{'(', _} | Macro] ->
{macro, dict:store(Name, macro_params_body_def(Macro, []), MacroDict)}
end;
pre_proc([{'-', _}, {atom, _, include}, {'(', _}, {string, _, Filename}, {')', _}, {dot, _}], _MacroDict) ->
{include, Filename};
pre_proc(Toks, MacroDict) ->
{tokens, subst_macros(Toks, MacroDict)}.
macro_params_body_def([{')', _}, {',', _} | Toks], RevParams) ->
{reverse(RevParams), macro_body_def(Toks, [])};
macro_params_body_def([{var, _, Param} | Toks], RevParams) ->
macro_params_body_def(Toks, [Param | RevParams]);
macro_params_body_def([{',', _}, {var, _, Param} | Toks], RevParams) ->
macro_params_body_def(Toks, [Param | RevParams]).
macro_body_def([{')', _}, {dot, _}], RevMacroBodyToks) ->
reverse(RevMacroBodyToks);
macro_body_def([Tok | Toks], RevMacroBodyToks) ->
macro_body_def(Toks, [Tok | RevMacroBodyToks]).
subst_macros(Toks, MacroDict) ->
reverse(subst_macros_rev(Toks, MacroDict, [])).
%% returns a reversed list of tokes
subst_macros_rev([{'?', _}, {_, LineNum, 'LINE'} | Toks], MacroDict, RevOutToks) ->
%% special-case for ?LINE, to avoid creating a new MacroDict for every line in the source file
subst_macros_rev(Toks, MacroDict, [{integer, LineNum, LineNum}] ++ RevOutToks);
subst_macros_rev([{'?', _}, {_, _, Name}, {'(', _} = Paren | Toks], MacroDict, RevOutToks) ->
case dict:fetch(Name, MacroDict) of
{[], MacroValue} ->
%% This macro does not have any vars, so ignore the fact that the invocation is followed by "(...stuff"
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []),
subst_macros_rev([Paren | Toks], MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks);
ParamsAndBody ->
%% This macro does have vars.
%% Collect all of the passe arguments, in an ordered list
{NToks, Arguments} = subst_macros_get_args(Toks, []),
%% Expand the varibles
ExpandedParamsToks = subst_macros_subst_args_for_vars(ParamsAndBody, Arguments),
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(ExpandedParamsToks, MacroDict, []),
subst_macros_rev(NToks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks)
end;
subst_macros_rev([{'?', _}, {_, _, Name} | Toks], MacroDict, RevOutToks) ->
%% This macro invocation does not have arguments.
%% Therefore the definition should not have parameters
{[], MacroValue} = dict:fetch(Name, MacroDict),
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []),
subst_macros_rev(Toks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks);
subst_macros_rev([Tok | Toks], MacroDict, RevOutToks) ->
subst_macros_rev(Toks, MacroDict, [Tok | RevOutToks]);
subst_macros_rev([], _MacroDict, RevOutToks) -> RevOutToks.
subst_macros_get_args([{')', _} | Toks], RevArgs) ->
{Toks, reverse(RevArgs)};
subst_macros_get_args([{',', _}, {var, _, ArgName} | Toks], RevArgs) ->
subst_macros_get_args(Toks, [ArgName | RevArgs]);
subst_macros_get_args([{var, _, ArgName} | Toks], RevArgs) ->
subst_macros_get_args(Toks, [ArgName | RevArgs]).
subst_macros_subst_args_for_vars({[], BodyToks}, []) ->
BodyToks;
subst_macros_subst_args_for_vars({[Param | Params], BodyToks}, [Arg | Args]) ->
NBodyToks = keyreplace(Param, 3, BodyToks, {var, 1, Arg}),
subst_macros_subst_args_for_vars({Params, NBodyToks}, Args).
read_include_file(Filename, IncludeSearchPath) ->
case file:path_open(IncludeSearchPath, Filename, [read, raw, binary]) of
{ok, IoDevice, FullName} ->
{ok, Data} = file:read(IoDevice, filelib:file_size(FullName)),
file:close(IoDevice),
binary_to_list(Data);
{error, Reason} ->
throw({failed_to_read_include_file, Reason, Filename, IncludeSearchPath})
end.

+ 41
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/game_alarm_handler.erl Dosyayı Görüntüle

@ -0,0 +1,41 @@
%%%----------------------------------------
%%% @Module : game_alarm_handler
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description:
%%%----------------------------------------
-module(game_alarm_handler).
-behaviour(gen_event).
-include("common.hrl").
%%gen_envent callbacks.
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
init(Args) ->
?DEBUG("game_alarm_handler init : ~p.", [Args]),
{ok, Args}.
handle_event({set_alarm, From}, _State) ->
?DEBUG("csj depot clear by ~p started.", [From]),
{ok, _State};
handle_event({clear_alarm, From}, _State) ->
?DEBUG("csj depot clear by ~p done.", [From]),
{ok, _State};
handle_event(Event, State) ->
?DEBUG("unmatched event: ~p.", [Event]),
{ok, State}.
handle_call(_Req, State) ->
{ok, State, State}.
handle_info(_Info, State) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

+ 131
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/game_timer.erl Dosyayı Görüntüle

@ -0,0 +1,131 @@
%%%----------------------------------------------------------------------
%%% File : game_timer.erl
%%% Author : csj
%%% Created : 2010-10-17
%%% Description:
%%%----------------------------------------------------------------------
-module(game_timer).
-behaviour(gen_server).
%% --------------------------------------------------------------------
%% Include files
%% --------------------------------------------------------------------
-include("common.hrl").
%% --------------------------------------------------------------------
%% External exports
-export([now/0, now_seconds/0, cpu_time/0, start_link/0, start/1, info/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%% ====================================================================
%% External functions
%% ====================================================================
now() ->
[{timer, {Now, _}}] = ets:lookup(ets_timer, timer),
Now.
now_seconds() ->
[{timer, {Now, _}}] = ets:lookup(ets_timer, timer),
{MegaSecs, Secs, _MicroSecs} = Now,
lists:concat([MegaSecs, Secs]).
cpu_time() ->
[{timer, {_, Wallclock_Time_Since_Last_Call}}] = ets:lookup(ets_timer, timer),
Wallclock_Time_Since_Last_Call.
info() ->
[
ets:info(ets_timer),
ets:tab2list(ets_timer)
].
-define(CLOCK, 100).
start(Sup) ->
supervisor:start_child(Sup,
{game_timer,
{game_timer, start_link, []},
permanent, brutal_kill, worker, [game_timer]}).
%% ====================================================================
%% Server functions
%% ====================================================================
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% --------------------------------------------------------------------
init([]) ->
ets:new(ets_timer, [set, protected, named_table]),
ets:insert(ets_timer, {timer, {erlang:now(), 0}}),
erlang:send_after(?CLOCK, self(), {event, clock}),
misc:write_monitor_pid(self(), ?MODULE, {}),
{ok, []}.
%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call(_Request, _From, State) ->
{reply, State, State}.
%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info({event, clock}, State) ->
{_Total_Run_Time, Time_Since_Last_Call} = statistics(runtime),
ets:insert(ets_timer, {timer, {erlang:now(), Time_Since_Last_Call}}),
erlang:send_after(?CLOCK, self(), {event, clock}),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(_Reason, _State) ->
misc:delete_monitor_pid(self()),
ok.
%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% --------------------------------------------------------------------
%%% Internal functions
%% --------------------------------------------------------------------

+ 348
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/http_lib.erl Dosyayı Görüntüle

@ -0,0 +1,348 @@
%% @author Ruslan Babayev <ruslan@babayev.com>
%% @copyright 2009 Ruslan Babayev
%% @doc HTTP Encoding and Utility Library.
-module(http_lib).
-export([uri_to_path/1, encode/1, list_to_absoluteURI/1, etag/1,
local_time_to_rfc1123/1, rfc1123_to_date_time/1, mime_type/1,
mime_type/2, extension/1, is_compressible/1, month_to_list/1,
url_decode/1, chunk/1, response/1, response/2,
accept/1, recv/2, recv/3, send/2, setopts/2, close/1, peername/1,
dir/1, is_persistent/1, is_idempotent/1, is_modified/2,
reason_phrase/1]).
-include("http.hrl").
-include_lib("kernel/include/file.hrl").
-include_lib("eunit/include/eunit.hrl").
%% --------------------------------------------------------------------
%% Macros
%% --------------------------------------------------------------------
-define(CS_DEBUG(F, D), io:format(lists:concat(["D(", ?MODULE, ":", ?LINE, ") :", F, "~n"]), D)).
%% @doc Encodes HTTP request or response.
%% @spec encode(#http_request{} | #http_response{}) -> iolist()
encode(#http_request{version = {Major, Minor}, method = Method,
uri = URI, headers = Headers, body = Body}) ->
Headers1 = case proplists:is_defined('Host', Headers) of
true ->
Headers;
false when is_record(URI, absoluteURI) ->
[{'Host', URI#absoluteURI.host} | Headers];
false ->
Headers
end,
[atom_to_list(Method), " ", uri_to_path(URI), " HTTP/",
integer_to_list(Major), ".", integer_to_list(Minor), "\r\n",
headers(Headers1), "\r\n", Body];
encode(#http_response{version = {Major, Minor}, status = Status,
headers = Headers0, body = Body}) ->
LocalTime = calendar:now_to_local_time(now()),
Date = local_time_to_rfc1123(LocalTime),
{ok, Server} = application:get_env(http, server),
Headers1 = [{'Date', Date}, {'Server', Server} | Headers0],
["HTTP/", integer_to_list(Major), ".", integer_to_list(Minor), " ",
integer_to_list(Status), " ", reason_phrase(Status), "\r\n",
headers(Headers1), "\r\n", Body].
uri_to_path(#abs_path{path = Path}) ->
Path;
uri_to_path(#absoluteURI{path = Path}) ->
Path;
uri_to_path('*') ->
"*".
list_to_absoluteURI(List) ->
RE = "^([^:/?#]+):?//([^/?#]*)",
[_, S, HP, Rest] = re:split(List, RE, [{return, list}]),
Scheme = list_to_atom(S),
{Host, Port} =
case re:split(HP, ":", [{return, list}]) of
[H, P] -> {H, list_to_integer(P)};
[H] when Scheme == http -> {H, 80};
[H] when Scheme == https -> {H, 443}
end,
Path = case Rest of
"" -> "/";
Else -> Else
end,
#absoluteURI{scheme = Scheme, host = Host, port = Port, path = Path}.
headers(Headers) ->
headers(Headers, []).
headers([], Acc) ->
Acc;
headers([{Name, Value} | T], Acc) ->
Header = [any_to_list(Name), ": ", any_to_list(Value), "\r\n"],
headers(T, Acc ++ Header).
any_to_list(A) when is_atom(A) ->
atom_to_list(A);
any_to_list(I) when is_integer(I) ->
integer_to_list(I);
any_to_list(L) when is_list(L) ->
L.
chunk(IoList) ->
[erlang:integer_to_list(iolist_size(IoList), 16), "\r\n", IoList, "\r\n"].
local_time_to_rfc1123(LocalTime) ->
[{{YYYY, MM, DD}, {H, M, S}} | _] =
calendar:local_time_to_universal_time_dst(LocalTime),
Day = calendar:day_of_the_week({YYYY, MM, DD}),
lists:flatten(
io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT",
[day(Day), DD, month_to_list(MM), YYYY, H, M, S])).
rfc1123_to_date_time([_D, _A, _Y, $,, $ , D1, D2, $ , M, O, N, $ , Y1, Y2, Y3, Y4, $ ,
H1, H2, $:, M1, M2, $:, S1, S2 | _]) ->
Year = list_to_integer([Y1, Y2, Y3, Y4]),
Day = list_to_integer([D1, D2]),
Month = list_to_month([M, O, N]),
Hour = list_to_integer([H1, H2]),
Min = list_to_integer([M1, M2]),
Sec = list_to_integer([S1, S2]),
{{Year, Month, Day}, {Hour, Min, Sec}}.
day(1) -> "Mon";
day(2) -> "Tue";
day(3) -> "Wed";
day(4) -> "Thu";
day(5) -> "Fri";
day(6) -> "Sat";
day(7) -> "Sun".
month_to_list(1) -> "Jan";
month_to_list(2) -> "Feb";
month_to_list(3) -> "Mar";
month_to_list(4) -> "Apr";
month_to_list(5) -> "May";
month_to_list(6) -> "Jun";
month_to_list(7) -> "Jul";
month_to_list(8) -> "Aug";
month_to_list(9) -> "Sep";
month_to_list(10) -> "Oct";
month_to_list(11) -> "Nov";
month_to_list(12) -> "Dec".
list_to_month("Jan") -> 1;
list_to_month("Feb") -> 2;
list_to_month("Mar") -> 3;
list_to_month("Apr") -> 4;
list_to_month("May") -> 5;
list_to_month("Jun") -> 6;
list_to_month("Jul") -> 7;
list_to_month("Aug") -> 8;
list_to_month("Sep") -> 9;
list_to_month("Oct") -> 10;
list_to_month("Nov") -> 11;
list_to_month("Dec") -> 12.
is_modified(#file_info{mtime = Mtime}, Since) ->
erlang:localtime_to_universaltime(Mtime) > rfc1123_to_date_time(Since).
is_idempotent('HEAD') -> true;
is_idempotent('GET') -> true;
is_idempotent('PUT') -> true;
is_idempotent('DELETE') -> true;
is_idempotent('TRACE') -> true;
is_idempotent('OPTIONS') -> true;
is_idempotent(_) -> false.
is_persistent(#http_request{version = Version, headers = Headers}) ->
Connection = proplists:get_value('Connection', Headers, ""),
is_persistent(Version, string:to_lower(Connection)).
is_persistent(Version, _) when Version < {1, 0} -> false;
is_persistent({1, 0}, "keep-alive") -> true;
is_persistent({1, 0}, _) -> false;
is_persistent(Version, "close") when Version >= {1, 1} -> false;
is_persistent(Version, _) when Version >= {1, 1} -> true.
url_decode(URL) ->
url_decode(URL, []).
url_decode([], Acc) ->
lists:reverse(Acc);
url_decode([37, H, L | T], Acc) ->
url_decode(T, [erlang:list_to_integer([H, L], 16) | Acc]);
url_decode([$+ | T], Acc) ->
url_decode(T, [32 | Acc]);
url_decode([H | T], Acc) ->
url_decode(T, [H | Acc]).
url_decode_test() ->
?assertEqual("I am decoded", url_decode("I+am+decoded")),
?assertEqual("#$%&+=<> /", url_decode("%23%24%25%26%2B%3D%3C%3D%20%2F")).
%% @doc Generates Etag based on file modification time and size.
%% @spec etag(#file_info{}) -> string()
etag(#file_info{mtime = MTime, size = Size}) ->
{{Year, Month, Day}, {Hour, Min, Sec}} = MTime,
F = fun(X) when X =< 25 -> X + $A;
(X) when X =< 50 -> X - 26 + $a;
(X) -> X - 3
end,
SizeStr = integer_to_list(Size),
lists:map(F, [X rem 60 || X <- [Year, Month, Day, Hour, Min, Sec]]) ++ SizeStr.
mime_type(Path) ->
mime_type(Path, undefined).
mime_type(Path, Default) ->
Ext = extension(Path),
case ets:lookup(http_mime_types, Ext) of
[{mime_type, Ext, Type, _Compressible} | _] ->
Type;
[] ->
Default
end.
extension(Path) ->
case filename:extension(Path) of
[] ->
[];
Extension ->
tl(Extension)
end.
is_compressible(Path) ->
Ext = extension(Path),
case ets:lookup(http_mime_types, Ext) of
[{mime_type, Ext, _Type, Compressible} | _] ->
Compressible;
[] ->
true
end.
response(Code) ->
response(Code, reason_phrase(Code)).
response(Code, Reason) ->
Headers = [{'Content-Type', "text/plain"},
{'Content-Length', iolist_size(Reason)}],
#http_response{status = Code, headers = Headers, body = Reason}.
dir(priv_dir) ->
priv_dir(http);
dir({priv_dir, Module}) ->
priv_dir(Module);
dir({priv_dir, Module, SubDir}) ->
filename:join([priv_dir(Module), any_to_list(SubDir)]);
dir({lib_dir, SubDir}) ->
code:lib_dir(http, SubDir);
dir({lib_dir, App, SubDir}) ->
code:lib_dir(App, SubDir);
dir(Path) when is_list(Path) ->
Path.
priv_dir(Module) ->
filename:join(get_base_dir(Module), "priv").
get_base_dir(Module) ->
{file, Here} = code:is_loaded(Module),
filename:dirname(filename:dirname(Here)).
accept(Socket) when element(1, Socket) == sslsocket ->
case ssl:transport_accept(Socket) of
{ok, SSLSocket} ->
case ssl:ssl_accept(SSLSocket) of
ok ->
{ok, SSLSocket};
Else ->
Else
end;
Else ->
Else
end;
accept(Socket) ->
gen_tcp:accept(Socket).
recv(Socket, Length) when element(1, Socket) == sslsocket ->
ssl:recv(Socket, Length);
recv(Socket, Length) ->
gen_tcp:recv(Socket, Length).
recv(Socket, Length, Timeout) when element(1, Socket) == sslsocket ->
ssl:recv(Socket, Length, Timeout);
recv(Socket, Length, Timeout) ->
gen_tcp:recv(Socket, Length, Timeout).
send(Socket, Data) when element(1, Socket) == sslsocket ->
ssl:send(Socket, Data);
send(Socket, Data) ->
gen_tcp:send(Socket, Data).
setopts(Socket, Options) when element(1, Socket) == sslsocket ->
ssl:setopts(Socket, Options);
setopts(Socket, Options) ->
inet:setopts(Socket, Options).
close(Socket) when element(1, Socket) == sslsocket ->
ssl:close(Socket);
close(Socket) ->
gen_tcp:close(Socket).
peername(Socket) when element(1, Socket) == sslsocket ->
ssl:peername(Socket);
peername(Socket) ->
gen_tcp:peername(Socket).
%% RFC 2616, HTTP 1.1 Status codes
reason_phrase(100) -> "Continue";
reason_phrase(101) -> "Switching Protocols";
reason_phrase(200) -> "OK";
reason_phrase(201) -> "Created";
reason_phrase(202) -> "Accepted";
reason_phrase(203) -> "Non-Authoritative Information";
reason_phrase(204) -> "No Content";
reason_phrase(205) -> "Reset Content";
reason_phrase(206) -> "Partial Content";
reason_phrase(300) -> "Multiple Choices";
reason_phrase(301) -> "Moved Permanently";
reason_phrase(302) -> "Moved Temporarily";
reason_phrase(303) -> "See Other";
reason_phrase(304) -> "Not Modified";
reason_phrase(305) -> "Use Proxy";
reason_phrase(306) -> "(unused)";
reason_phrase(307) -> "Temporary Redirect";
reason_phrase(400) -> "Bad Request";
reason_phrase(401) -> "Unauthorized";
reason_phrase(402) -> "Payment Required";
reason_phrase(403) -> "Forbidden";
reason_phrase(404) -> "Object Not Found";
reason_phrase(405) -> "Method Not Allowed";
reason_phrase(406) -> "Not Acceptable";
reason_phrase(407) -> "Proxy Authentication Required";
reason_phrase(408) -> "Request Time-out";
reason_phrase(409) -> "Conflict";
reason_phrase(410) -> "Gone";
reason_phrase(411) -> "Length Required";
reason_phrase(412) -> "Precondition Failed";
reason_phrase(413) -> "Request Entity Too Large";
reason_phrase(414) -> "Request-URI Too Large";
reason_phrase(415) -> "Unsupported Media Type";
reason_phrase(416) -> "Requested Range Not Satisfiable";
reason_phrase(417) -> "Expectation Failed";
reason_phrase(500) -> "Internal Server Error";
reason_phrase(501) -> "Not Implemented";
reason_phrase(502) -> "Bad Gateway";
reason_phrase(503) -> "Service Unavailable";
reason_phrase(504) -> "Gateway Time-out";
reason_phrase(505) -> "HTTP Version not supported";
%% RFC 2518, HTTP Extensions for Distributed Authoring -- WEBDAV
reason_phrase(102) -> "Processing";
reason_phrase(207) -> "Multi-Status";
reason_phrase(422) -> "Unprocessable Entity";
reason_phrase(423) -> "Locked";
reason_phrase(424) -> "Failed Dependency";
reason_phrase(507) -> "Insufficient Storage";
%% (Work in Progress) WebDAV Advanced Collections
reason_phrase(425) -> "";
%% RFC 2817, HTTP Upgrade to TLS
reason_phrase(426) -> "Upgrade Required";
%% RFC 3229, Delta encoding in HTTP
reason_phrase(226) -> "IM Used";
reason_phrase(_) -> "Internal Server Error".

+ 238
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/logger_h.erl Dosyayı Görüntüle

@ -0,0 +1,238 @@
%%%----------------------------------------------------------------------
%%% File : logger_h.erl
%%% Created : 2010-08-20
%%%----------------------------------------------------------------------
-module(logger_h).
-behaviour(gen_event).
-include("common.hrl").
-include("debug.hrl").
-export([start_link/2, log_level/0]).
%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2,
code_change/3, reopen_log/0, rotate_log/1]).
-record(state, {fd, file, level}).
-define(LOG_FILE_INTERVAL, 24 * 3600000). % 11log文件
start_link(Log_file, Log_level) ->
case gen_event:start_link({local, ?LOGMODULE}) of
Ret = {ok, _Pid} ->
gen_event:add_handler(?LOGMODULE, ?MODULE, [Log_file, Log_level]),
Ret;
Other ->
Other
end.
log_level() ->
gen_event:call({local, ?LOGMODULE}, ?MODULE, log_level).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_event
%%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, State} |
%% Other
%%----------------------------------------------------------------------
init([File, Level]) ->
FileName = gen_full_log_filename(File, erlang:localtime()),
case file:open(FileName, [append, raw]) of
{ok, Fd} ->
erlang:send_after(?LOG_FILE_INTERVAL, self(), change_log_filename),
{ok, #state{fd = Fd, file = File, level = Level}};
Error ->
Error
end.
%%----------------------------------------------------------------------
%% Func: handle_event/2
%% Returns: {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%%----------------------------------------------------------------------
handle_event(Event, State) ->
write_event(State#state.fd, {erlang:localtime(), Event}),
{ok, State}.
%%----------------------------------------------------------------------
%% Func: handle_call/2
%% Returns: {ok, Reply, State} |
%% {swap_handler, Reply, Args1, State1, Mod2, Args2} |
%% {remove_handler, Reply}
%%----------------------------------------------------------------------
handle_call(log_level, State) ->
{ok, State#state.level, State};
handle_call(_Request, State) ->
Reply = ok,
{ok, Reply, State}.
%%----------------------------------------------------------------------
%% Func: handle_info/2
%% Returns: {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%%----------------------------------------------------------------------
handle_info({'EXIT', _Fd, _Reason}, _State) ->
remove_handler;
handle_info({emulator, _GL, reopen}, State) ->
file:close(State#state.fd),
rotate_log(State#state.file),
case file:open(State#state.file, [append, raw]) of
{ok, Fd} ->
{ok, State#state{fd = Fd}};
Error ->
Error
end;
handle_info({emulator, GL, Chars}, State) ->
write_event(State#state.fd, {erlang:localtime(), {emulator, GL, Chars}}),
{ok, State};
handle_info(change_log_filename, State) ->
file:close(State#state.fd),
FileName = gen_full_log_filename(State#state.file, erlang:localtime()),
NewState = case file:open(FileName, [append, raw]) of
{ok, Fd} ->
State#state{fd = Fd};
Error ->
?TRACE("open ~s fail, reason:~p~n", [FileName, Error]),
State
end,
erlang:send_after(?LOG_FILE_INTERVAL, self(), change_log_filename),
{ok, NewState};
handle_info(_Info, State) ->
{ok, State}.
%%----------------------------------------------------------------------
%% Func: terminate/2
%% Purpose: Shutdown the server
%% Returns: any
%%----------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
reopen_log() ->
?LOGMODULE ! {emulator, noproc, reopen}.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
% Copied from erlang_logger_file_h.erl
write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->
T = write_time(Time),
case catch io_lib:format(add_node(Format, Pid), Args) of
S when is_list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
file:write(Fd, io_lib:format(T ++ F, [Format, Args]))
end;
write_event(Fd, {Time, {emulator, _GL, Chars}}) ->
T = write_time(Time),
case catch io_lib:format(Chars, []) of
S when is_list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
file:write(Fd, io_lib:format(T ++ "ERROR: ~p ~n", [Chars]))
end;
write_event(Fd, {Time, {info, _GL, {Pid, Info, _}}}) ->
T = write_time(Time),
file:write(Fd, io_lib:format(T ++ add_node("~p~n", Pid), [Info]));
write_event(Fd, {Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
T = write_time(Time),
S = format_report(Rep),
file:write(Fd, io_lib:format(T ++ S ++ add_node("", Pid), []));
write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
T = write_time(Time, "INFO REPORT"),
S = format_report(Rep),
file:write(Fd, io_lib:format(T ++ S ++ add_node("", Pid), []));
write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
T = write_time(Time, "INFO REPORT"),
case catch io_lib:format(add_node(Format, Pid), Args) of
S when is_list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
file:write(Fd, io_lib:format(T ++ F, [Format, Args]))
end;
write_event(_, _) ->
ok.
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
true ->
io_lib:format("~s~n", [Rep]);
_ ->
format_rep(Rep)
end;
format_report(Rep) ->
io_lib:format("~p~n", [Rep]).
format_rep([{Tag, Data} | Rep]) ->
io_lib:format(" ~p: ~p~n", [Tag, Data]) ++ format_rep(Rep);
format_rep([Other | Rep]) ->
io_lib:format(" ~p~n", [Other]) ++ format_rep(Rep);
format_rep(_) ->
[].
add_node(X, Pid) when is_atom(X) ->
add_node(atom_to_list(X), Pid);
add_node(X, Pid) when node(Pid) /= node() ->
lists:concat([X, "** at node ", node(Pid), " **~n"]);
add_node(X, _) ->
X.
string_p([]) ->
false;
string_p(Term) ->
string_p1(Term).
string_p1([H | T]) when is_integer(H), H >= $\s, H < 255 ->
string_p1(T);
string_p1([$\n | T]) -> string_p1(T);
string_p1([$\r | T]) -> string_p1(T);
string_p1([$\t | T]) -> string_p1(T);
string_p1([$\v | T]) -> string_p1(T);
string_p1([$\b | T]) -> string_p1(T);
string_p1([$\f | T]) -> string_p1(T);
string_p1([$\e | T]) -> string_p1(T);
string_p1([H | T]) when is_list(H) ->
case string_p1(H) of
true -> string_p1(T);
_ -> false
end;
string_p1([]) -> true;
string_p1(_) -> false.
write_time(Time) -> write_time(Time, "ERROR REPORT").
write_time({{Y, Mo, D}, {H, Mi, S}}, Type) ->
io_lib:format("~n=~s==== ~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w ===",
[Type, Y, Mo, D, H, Mi, S]).
gen_full_log_filename(File, {{Y, Mo, D}, {H, Mi, S}}) ->
io_lib:format("~s_~w.~.2.0w.~.2.0w_~.2.0w-~.2.0w-~.2.0w", [File, Y, Mo, D, H, Mi, S]).
%% @doc Rename the log file if exists, to "*-old.log".
%% This is needed in systems when the file must be closed before rotation (Windows).
%% On most Unix-like system, the file can be renamed from the command line and
%% the log can directly be reopened.
%% @spec (Filename::string()) -> ok
rotate_log(Filename) ->
case file:read_file_info(Filename) of
{ok, _FileInfo} ->
RotationName = filename:rootname(Filename),
file:rename(Filename, [RotationName, "-old.log"]),
ok;
{error, _Reason} ->
ok
end.

+ 114
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/loglevel.erl Dosyayı Görüntüle

@ -0,0 +1,114 @@
%%%----------------------------------------------------------------------
%%% File : loglevel.erl
%%% Created : 2010-08-30
%%%----------------------------------------------------------------------
-module(loglevel).
-export([set/1, get/0]).
-include("common.hrl").
-include("debug.hrl").
%% Error levels:
-define(LOG_LEVELS, [{0, no_log, "No log"}
, {1, critical, "Critical"}
, {2, error, "Error"}
, {3, warning, "Warning"}
, {4, info, "Info"}
, {5, debug, "Debug"}
, {6, test, "Test"}
]).
get() ->
Level = logger:get(),
case lists:keysearch(Level, 1, ?LOG_LEVELS) of
{value, Result} -> Result;
_ -> erlang:error({no_such_loglevel, Level})
end.
set(LogLevel) when is_atom(LogLevel) ->
set(level_to_integer(LogLevel));
set(Loglevel) when is_integer(Loglevel) ->
try
io:format("$$$ loglevel:set, level is ~p~n", [Loglevel]),
{Mod, Code} = dynamic_compile:from_string(logger_src(Loglevel)),
code:load_binary(Mod, "logger_h.erl", Code)
catch
Type:Error -> ?CRITICAL_MSG("Error compiling logger (~p): ~p~n", [Type, Error])
end;
set(_) ->
exit("Loglevel must be an integer").
level_to_integer(Level) ->
case lists:keysearch(Level, 2, ?LOG_LEVELS) of
{value, {Int, Level, _Desc}} -> Int;
_ -> erlang:error({no_such_loglevel, Level})
end.
%% --------------------------------------------------------------
%% Code of the mcs logger, dynamically compiled and loaded
%% This allows to dynamically change log level while keeping a
%% very efficient code.
logger_src(Loglevel) ->
L = integer_to_list(Loglevel),
"-module(logger).
-export([test_msg/4,
debug_msg/4,
info_msg/4,
warning_msg/4,
error_msg/4,
critical_msg/4,
get/0]).
get() -> " ++ L ++ ".
%% Helper functions
test_msg(Module, Line, Format, Args) when " ++ L ++ " >= 6 ->
notify(info_msg,
\"T(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args);
test_msg(_,_,_,_) -> ok.
debug_msg(Module, Line, Format, Args) when " ++ L ++ " >= 5 ->
notify(info_msg,
\"D(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args);
debug_msg(_,_,_,_) -> ok.
info_msg(Module, Line, Format, Args) when " ++ L ++ " >= 4 ->
notify(info_msg,
\"I(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args);
info_msg(_,_,_,_) -> ok.
warning_msg(Module, Line, Format, Args) when " ++ L ++ " >= 3 ->
notify(error,
\"W(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args);
warning_msg(_,_,_,_) -> ok.
error_msg(Module, Line, Format, Args) when " ++ L ++ " >= 2 ->
case Args of
%% start with : ** Node php
[42,42,32,78,111,100,101,32,112,104,112|_] ->
ok;
_ ->
notify(error,
\"E(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args)
end;
error_msg(_,_,_,_) -> ok.
critical_msg(Module, Line, Format, Args) when " ++ L ++ " >= 1 ->
notify(error,
\"C(~p:~p:~p) : \"++Format++\"~n\",
[self(), Module, Line]++Args);
critical_msg(_,_,_,_) -> ok.
%% Distribute the message to the Erlang error logger
notify(Type, Format, Args) ->
LoggerMsg = {Type, group_leader(), {self(), Format, Args}},
gen_event:notify(logger_mgr, LoggerMsg).
".

+ 562
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/misc.erl Dosyayı Görüntüle

@ -0,0 +1,562 @@
%%%----------------------------------------
%%% @Module : misc
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description:
%%%----------------------------------------
-module(misc).
%%
%% Include files
%%
-include("common.hrl").
-include("record.hrl").
-include("goods.hrl").
%%
%% Exported Functions
%%
-compile(export_all).
%%
%% API Functions
%%
%% get the pid of a registered name
whereis_name({local, Atom}) ->
erlang:whereis(Atom);
whereis_name({global, Atom}) ->
global:whereis_name(Atom).
register(local, Name, Pid) ->
erlang:register(Name, Pid);
register(global, Name, Pid) ->
%% case global:whereis_name(Name) of
%% Pid0 when is_pid(Pid0) ->
%% exit(Pid0,normal);
%% undefined ->
%% global:re_register_name(Name, Pid)
%% end.
global:re_register_name(Name, Pid);
register(unique, Name, Pid) ->
global:register_name(Name, Pid).
unregister({local, Atom}) ->
erlang:unregister(Atom);
unregister({global, Atom}) ->
global:unregister(Atom).
is_process_alive(Pid) ->
try
if is_pid(Pid) ->
%%访
%% case rpc:call(node(Pid), erlang, is_process_alive, [Pid]) of
%% {badrpc, _Reason} -> false;
%% Res -> Res
%% end;
erlang:is_process_alive(Pid);
true -> false
end
catch
_:_ -> false
end.
%% time format
one_to_two(One) -> io_lib:format("~2..0B", [One]).
%% @doc get the time's seconds for integer type
%% @spec get_seconds(Time) -> integer()
get_seconds(Time) ->
{_MegaSecs, Secs, _MicroSecs} = Time,
Secs.
time_format(Now) ->
{{Y, M, D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ",
one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
date_format(Now) ->
{{Y, M, D}, {_H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D)]).
date_hour_format(Now) ->
{{Y, M, D}, {H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H)]).
date_hour_minute_format(Now) ->
{{Y, M, D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H), "-", one_to_two(MM)]).
%% split by -
minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), "-", one_to_two(MM)]).
hour_minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
rand_to_process(S) ->
Rand = random:uniform(?SEND_MSG),
lists:nth(Rand, S).
%% list然后注册成全局的
player_process_name(PlayerId) when is_integer(PlayerId) or is_atom(PlayerId) ->
tool:to_atom(lists:concat([p_p_, PlayerId]));
player_process_name(PlayerId) when is_list(PlayerId) ->
tool:to_atom(lists:flatten(["p_p_" | PlayerId]));
player_process_name(PlayerId) when is_binary(PlayerId) ->
tool:to_atom(lists:concat([p_p_, tool:md5(PlayerId)])).
%% ID判断唯一性
player_process_accountname(AccountId) when is_integer(AccountId) or is_atom(AccountId) ->
lists:concat([p_a_, AccountId]);
player_process_accountname(AccountId) when is_list(AccountId) ->
lists:flatten(["p_a_" | AccountId]);
player_process_accountname(AccountId) when is_binary(AccountId) ->
lists:concat([p_a_, tool:md5(AccountId)]).
%%
create_process_name(Prefix, List) ->
tool:to_atom(lists:concat(lists:flatten([Prefix] ++ lists:map(fun(T) -> ['_', T] end, List)))).
%%
create_atom(Prefix, List) ->
tool:to_atom(lists:concat(lists:flatten([Prefix] ++ lists:map(fun(T) -> ['_', T] end, List)))).
%% IP
get_ip(Socket) ->
case inet:peername(Socket) of
{ok, {PeerIP, _Port}} ->
ip_to_binary(PeerIP);
{error, _NetErr} ->
""
end.
ip_to_binary(Ip) ->
case Ip of
{A1, A2, A3, A4} ->
[integer_to_list(A1), ".", integer_to_list(A2), ".", integer_to_list(A3), ".", integer_to_list(A4)];
_ ->
"-"
end.
ip_list_to_binary(Data) ->
case Data of
[] -> "";
undefined -> "-";
{IP, _PORT} -> ip_to_binary(IP);
_ when is_list(Data) ->
[H | T] = Data,
[ip_list_to_binary(H), ",", ip_list_to_binary(T)];
_ -> "-"
end.
get_child_count(Atom) ->
case whereis_name({local, Atom}) of
undefined ->
0;
_ ->
[_, {active, ChildCount}, _, _] = supervisor:count_children(Atom),
ChildCount
end.
get_child_message_queue_length(Atom) ->
case whereis_name({local, Atom}) of
undefined ->
[];
_ ->
Child_list = supervisor:which_children(Atom),
lists:map(
fun({Name, Pid, _Type, [Class]}) when is_pid(Pid) ->
{message_queue_len, Qlen} = erlang:process_info(Pid, message_queue_len),
{links, Links} = erlang:process_info(Pid, links),
{Name, Pid, Qlen, Class, length(Links)}
end,
Child_list)
end.
%% desc: ets表编号
create_goods_ets_name(Num) ->
case lists:member(Num, lists:seq(1, ?MAX_GOODS_ETS_NUM)) of
true -> tool:to_atom(lists:concat([ets_goods_online_, Num]));
false -> none
end.
%% desc: ets表编号
create_goods_attr_ets_name(Num) ->
case lists:member(Num, lists:seq(1, ?MAX_GOODS_ETS_NUM)) of
true -> tool:to_atom(lists:concat([ets_goods_attribute_, Num]));
false -> none
end.
%% desc: ets表编号
create_goods_polish_ets_name(Num) ->
case lists:member(Num, lists:seq(1, ?MAX_GOODS_ETS_NUM)) of
true -> tool:to_atom(lists:concat([ets_polish_, Num]));
false -> none
end.
%% --------------------------------------------------------------------
%% Func: get pid info/7
%% Param Process: atom Pid or Pid RegName
%% Top: 0=all result, N=0-N record in the result
%% NeedModule fiter Pid module,[]=all
%% Layer node child layer, 0=all,1=self
%% MinMsgLen message queue length >= MinMsgLen
%% MinMemSize pid memory size >= MinMemSize
%% OrderKey, type atom and the value is: msglen,memory
%% Purpose: get pid info
%% Returns: {ok,Result,Count} Result=[{Pid,RegName,MemSize,MessageLength,Module},...]
%% {error,Reason}
%% --------------------------------------------------------------------
get_process_info(Process, Top, NeedModule, Layer, MinMsgLen, MinMemSize, OrderKey) ->
RootPid =
if erlang:is_pid(Process) ->
Process;
true ->
case whereis_name({local, Process}) of
undefined ->
error;
ProcessPid ->
ProcessPid
end
end,
case RootPid of
error ->
{error, lists:concat([Process, " is not process reg name in the ", node()])};
_ ->
AllPidList = get_process_all_pid(RootPid, Layer),
RsList = get_process_info_detail(NeedModule, AllPidList, []),
Len = erlang:length(RsList),
FilterRsList =
case OrderKey of
msglen ->
lists:filter(fun({_, _, _, Qlen, _}) -> Qlen >= MinMsgLen end, RsList);
memory ->
lists:filter(fun({_, _, Qmem, _, _}) -> Qmem >= MinMemSize end, RsList);
_ ->
lists:filter(fun({_, _, _, Qlen, _}) -> Qlen >= MinMsgLen end, RsList)
end,
RsList2 =
case OrderKey of
msglen ->
lists:sort(fun({_, _, _, MsgLen1, _}, {_, _, _, MsgLen2, _}) -> MsgLen1 > MsgLen2 end, FilterRsList);
memory ->
lists:sort(fun({_, _, MemSize1, _, _}, {_, _, MemSize2, _, _}) ->
MemSize1 > MemSize2 end, FilterRsList);
_ ->
lists:sort(fun({_, _, _, MsgLen1, _}, {_, _, _, MsgLen2, _}) -> MsgLen1 > MsgLen2 end, FilterRsList)
end,
NewRsList =
if Top =:= 0 ->
RsList2;
true ->
if erlang:length(RsList2) > Top ->
lists:sublist(RsList2, Top);
true ->
RsList2
end
end,
{ok, NewRsList, Len}
end.
%% --------------------------------------------------------------------
%% Func: get_process_info_detail/3
%% Purpose: get pid detail info
%% Returns: [{Pid,RegName,MemSize,MessageLength,Module},...]
%% --------------------------------------------------------------------
get_process_info_detail(_NeedModule, [], Result) -> Result;
get_process_info_detail(NeedModule, [H | T], Result) ->
Mql = get_process_data({message_queue_len, H}),
MemSize = get_process_data({memory, H}),
RegName = get_process_data({registered_name, H}),
case NeedModule of
[] ->
Module = get_process_info_initial_call(H),
%% io:format("~p process RegName:~p,Mql:~p,MemSize:~p,Module:~p\n",[H, RegName, Mql, MemSize, Module]),
get_process_info_detail(NeedModule, T, lists:append(Result, [{H, RegName, MemSize, Mql, Module}]));
_ ->
case get_process_info_check_initial_call(NeedModule, H) of
"" ->
get_process_info_detail(NeedModule, T, Result);
Module ->
%% io:format("~p process RegName:~p,Mql:~p,MemSize:~p\n",[H, RegName, Mql, MemSize]),
get_process_info_detail(NeedModule, T, lists:append(Result, [{H, RegName, MemSize, Mql, Module}]))
end
end.
%% --------------------------------------------------------------------
%% Func: get_process_info_check_initial_call/2
%% Purpose: check inital call
%% Returns: true or false
%% --------------------------------------------------------------------
get_process_info_check_initial_call(NeedModule, Pid) ->
DictionaryList = get_process_data({dictionary, Pid}),
%% io:format("Dictionary List:~p\n",[DictionaryList]),
case proplists:lookup('$initial_call', DictionaryList) of
{'$initial_call', {Module, _, _}} ->
%% io:format("~p found initial_call Module=~p\n",[Pid,Module]),
case lists:member(Module, NeedModule) of
true ->
Module;
_ ->
""
end;
_ ->
""
end.
%% --------------------------------------------------------------------
%% Func: get_process_info_initial_call/1
%% Purpose: get initial call
%% Returns: true or false
%% --------------------------------------------------------------------
get_process_info_initial_call(Pid) ->
DictionaryList = get_process_data({dictionary, Pid}),
%% io:format("Dictionary List:~p\n",[DictionaryList]),
case proplists:lookup('$initial_call', DictionaryList) of
{'$initial_call', {Module, _, _}} ->
Module;
_ ->
""
end.
%% --------------------------------------------------------------------
%% Func: get_process_all_pid/1
%% Purpose: get pid and child pid, Layer 0 all 1 fisrt
%% Returns: [Pid,...]
%% --------------------------------------------------------------------
get_process_all_pid(RootPid, Layer) ->
ParentPid = get_process_parent_pid(RootPid),
RootLinkPidList = get_process_data({links, RootPid}),
%% io:format("~p links process links~p,and parent pid is~p\n",[RootPid, RootLinkPidList, ParentPid]),
case RootLinkPidList of
[] ->
[RootPid];
_ ->
if erlang:length(RootLinkPidList) =:= 1 ->
[RootPid];
true ->
NewLinkPidList =
if erlang:is_pid(ParentPid) ->
lists:delete(ParentPid, RootLinkPidList);
true ->
RootLinkPidList
end,
LinkPidList = lists:delete(RootPid, NewLinkPidList),
%% io:format("~p do handle links process links~p\n",[RootPid,LinkPidList]),
if Layer =:= 1 ->
[RootPid];
true ->
get_process_all_pid(LinkPidList, Layer, [RootPid], 2)
end
end
end.
get_process_all_pid([], _Layer, ResultList, _Index) -> ResultList;
get_process_all_pid([H | T], Layer, ResultList, Index) ->
%% io:format("get process all pid Index=~p", [Index]),
if erlang:is_pid(H) ->
ParentPid = get_process_parent_pid(H),
RootLinkPidList = get_process_data({links, H}),
%% io:format("~p links process links~p,and parent pid is~p\n",[H, RootLinkPidList, ParentPid]),
case RootLinkPidList of
[] ->
get_process_all_pid(T, Layer, lists:append(ResultList, [H]), Index);
_ ->
if erlang:length(RootLinkPidList) =:= 1 ->
get_process_all_pid(T, Layer, lists:append(ResultList, [H]), Index);
true ->
NewLinkPidList =
if erlang:is_pid(ParentPid) ->
lists:delete(ParentPid, RootLinkPidList);
true ->
RootLinkPidList
end,
LinkPidList = lists:delete(H, NewLinkPidList),
NewIndex = Index + 1,
SubResultList =
if NewIndex > Layer, Layer =/= 0 ->
[H];
true ->
get_process_all_pid(LinkPidList, Layer, [H], NewIndex)
end,
get_process_all_pid(T, Layer, lists:append(ResultList, SubResultList), Index)
end
end;
true ->
get_process_all_pid(T, Layer, ResultList, Index)
end.
%% --------------------------------------------------------------------
%% Func: get_process_parent_pid/1
%% Purpose: get the pid parent pid
%% Returns: Pid or ignore
%% --------------------------------------------------------------------
get_process_parent_pid(Pid) ->
DictionaryList = get_process_data({dictionary, Pid}),
%% io:format("Dictionary List:~p\n",[DictionaryList]),
case proplists:lookup('$ancestors', DictionaryList) of
{'$ancestors', [ParentPid | _]} ->
%% io:format("~p found parent pid is ~p\n",[Pid,ParentPid]),
if erlang:is_pid(ParentPid) ->
ParentPid;
true ->
whereis_name({local, ParentPid})
end;
_ ->
ignore
end.
%% --------------------------------------------------------------------
%% Func: get_process_data/1
%% Purpose: get the dictionary info of the process
%% Returns: [] or DictionaryList
%% --------------------------------------------------------------------
get_process_data({dictionary, Pid}) ->
try erlang:process_info(Pid, dictionary) of
{_, DList} -> DList;
_ -> []
catch
_:_ -> []
end;
%% --------------------------------------------------------------------
%% Func: get_process_data/1
%% Purpose: get the links info of the process
%% Returns: [] or LinksList
%% --------------------------------------------------------------------
get_process_data({links, Pid}) ->
try erlang:process_info(Pid, links) of
{_, Links} -> lists:filter(fun(I) -> erlang:is_pid(I) end, Links);
_ -> []
catch
_:_ -> []
end;
%% --------------------------------------------------------------------
%% Func: get_process_data/1
%% Purpose: get the message queue length info of the process
%% Returns: 0 or Length
%% --------------------------------------------------------------------
get_process_data({message_queue_len, Pid}) ->
try erlang:process_info(Pid, message_queue_len) of
{message_queue_len, Length} -> Length;
_ -> 0
catch
_:_ -> 0
end;
%% --------------------------------------------------------------------
%% Func: get_process_data/1
%% Purpose: get the memory size info of the process
%% Returns: 0 or MemorySize
%% --------------------------------------------------------------------
get_process_data({memory, Pid}) ->
try erlang:process_info(Pid, memory) of
{memory, Size} -> Size;
_ -> 0
catch
_:_ -> 0
end;
%% --------------------------------------------------------------------
%% Func: get_process_data/1
%% Purpose: get the registered name info of the process
%% Returns: "" or RegisteredName
%% --------------------------------------------------------------------
get_process_data({registered_name, Pid}) ->
try erlang:process_info(Pid, registered_name) of
{registered_name, RegName} -> RegName;
_ -> ""
catch
_:_ -> ""
end.
%% --------------------------------------------------------------------
%% Func: get_online_role_count/1
%% Purpose: get online role count
%% Returns: {0,0} or {SpecsCount,ActiveCount}
%% --------------------------------------------------------------------
%% get_online_role_count(AccountList) ->
%% case AccountList of
%% AccAtom when is_atom(AccAtom) ->
%% get_online_role_count([AccAtom], 0, 0);
%% AccList when is_list(AccList) ->
%% get_online_role_count(AccList, 0, 0)
%% end.
%%
%% get_online_role_count([], Count, ActiveCount) ->{Count,ActiveCount};
%% get_online_role_count(Ports, Count, ActiveCount) ->
%% [AccountSupName|T] = Ports,
%% {SNum,ANum} = get_online_role_count_item(AccountSupName),
%% get_online_role_count(T, Count + SNum, ActiveCount + ANum).
%%
%% get_online_role_count_item(SupName) ->
%% try supervisor:count_children(SupName) of
%% [] -> {0,0};
%% SupList when erlang:is_list(SupList) ->
%% %% io:format("SupList ~p ~n", [SupList]),
%% SCount =
%% case proplists:lookup(specs, SupList) of
%% {specs, SNum} -> SNum;
%% _ -> 0
%% end,
%% ACount =
%% case proplists:lookup(active, SupList) of
%% {active, ANum} -> ANum;
%% _ -> 0
%% end,
%% {SCount,ACount};
%% _ -> {0,0}
%% catch
%% _:_ -> {0,0}
%% end.
%% --------------------------------------------------------------------
%% Func: replace_all/4
%% Purpose: Subject,RE,Replacement,Options
%% Returns: List
%% --------------------------------------------------------------------
replace_all(Subject, RE, Replacement, Options) ->
ReSubject = re:replace(Subject, RE, Replacement, Options),
case ReSubject =:= Subject of
false ->
replace_all(ReSubject, RE, Replacement, Options);
_ ->
ReSubject
end.
pg2_get_members(Pg2_name) ->
L = case pg2:get_members(Pg2_name) of
{error, _} ->
timer:sleep(100),
pg2:get_members(Pg2_name);
Other when is_list(Other) ->
Other
end,
if not is_list(L) -> [];
true -> lists:usort(L)
end.
get_http_content(Url) ->
case httpc:request(Url) of
{ok, {_Status, _Headers, Raw}} ->
Raw;
{error, _Reason} ->
""
end.
cancel_timer(Timer) ->
case get(Timer) of
undefined -> skip;
Timer1 ->
erlang:cancel_timer(Timer1)
end.
write_system_info(Pid, Module, Args) ->
ets:insert(?ETS_SYSTEM_INFO, {Pid, Module, Args}).
delete_system_info(Pid) ->
ets:delete(?ETS_SYSTEM_INFO, Pid).
write_monitor_pid(Pid, Module, Args) ->
ets:insert(?ETS_MONITOR_PID, {Pid, Module, Args}).
delete_monitor_pid(Pid) ->
ets:delete(?ETS_MONITOR_PID, Pid).

+ 491
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/misc_admin.erl Dosyayı Görüntüle

@ -0,0 +1,491 @@
%%%----------------------------------------
%%% @Module : misc_admin
%%% @Author :
%%% @Created :
%%% @Description:
%%%----------------------------------------
-module(misc_admin).
%%
%% Include files
%%
-include("common.hrl").
-include("record.hrl").
-include("debug.hrl").
-include("goods.hrl").
%%
-define(PARAM_ERROR_CODE, <<"param_error">>). %
-define(FLAG_ERROR_CODE, <<"flag_error">>). %
-define(FAILED_CODE, <<"failed">>). %
-define(SUCCESS_CODE, <<"success">>). %
-compile(export_all).
%% http请求IP验证
treat_http_request(Socket, PacketStr) ->
case gen_tcp:recv(Socket, 0, ?RECV_TIMEOUT) of
{ok, Packet} ->
try
P = lists:concat([PacketStr, tool:to_list(Packet)]),
io:format("PacketStr ~p ~n", [http_util:get_cmd_parm(P)]),
%% ?INFO_MSG("Packet:~p ~n", [P]),
{Cmd, KvList, Md5Key} = http_util:get_cmd_parm(P),
Md5Str = string:to_upper(tool:md5(Md5Key)),
io:format("md5 ~p ~n", [Md5Str]),
%% ?INFO_MSG("Cmd:~p ~n ~p ~n ~p ~n ~p ~n ~n", [Cmd, KvList, Md5Key, Md5Str]),
case Md5Str =:= http_util:get_param("flag", KvList) of
false -> do_handle_request(Cmd, KvList, Socket);
true -> gen_tcp:send(Socket, ?FLAG_ERROR_CODE)
end
catch
What:Why ->
?ERROR_MSG("What ~p, Why ~p, ~p", [What, Why, erlang:get_stacktrace()]),
gen_tcp:send(Socket, ?FAILED_CODE)
end;
{error, Reason} ->
?ERROR_MSG("http_request error Reason:~p ~n", [Reason])
end.
%% 广
do_handle_request("send_sys_bulletin", KvList, Socket) ->
MsgType = list_to_integer(http_util:get_param("msg_type", KvList)),
Content = http_util:get_param("content", KvList),
cast_to_server(lib_chat, broadcast_sys_msg, [MsgType, Content]),
%% lib_chat:broadcast_sys_msg("test"),
?INFO_MSG("type:~p content:~ts ~n", [MsgType, Content]),
gen_tcp:send(Socket, <<"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nhello world!">>);
% gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("send_mail", KvList, Socket) ->
ok;
%% Action = http_util:get_param("action", KvList),
%% UserNames = http_util:get_param("user_names", KvList),
%% UserIds = http_util:get_param("user_ids", KvList),
%% MailTitle = http_util:get_param("mail_title", KvList),
%% MailConten = http_util:get_param("mail_content", KvList),
%% UserNameList = string:tokens(UserNames, ","),
%% UserIdList = string:tokens(UserIds, ","),
%% if
%% Action =:= 1 -> % user_names user_ids
%% cast_to_server(lib_mail, broadcast_sys_msg, [Action, UserNameList, UserIdList, MailTitle, MailConten]);
%% Action =:= 2 -> % "条件参数"
%% cast_to_server(lib_mail, broadcast_sys_msg, [MsgType, Content]);
%% Action =:= 3 -> % 线
%% cast_to_server(lib_mail, broadcast_sys_msg, [Action, MailTitle, MailConten]);
%% true ->
%% ok
%% end,
%% ?INFO_MSG("Action:~p title:~ts content:~ts ~n", [Action, MailTitle, MailConten]),
%% gen_tcp:send(Socket, ?SUCCESS_CODE);
%% GM回复玩家接口
do_handle_request("complain_reply", KvList, Socket) ->
UserName = http_util:get_param("user_name", KvList),
Conten = http_util:get_param("content", KvList),
CompainId = http_util:get_param("compain_id", KvList),
cast_to_server(lib_mail, broadcast_sys_msg, [CompainId, UserName, Conten]),
?INFO_MSG("CompainId:~p UserName::~ts content:~ts ~n", [CompainId, UserName, Conten]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%% /
do_handle_request("forbid_login", KvList, Socket) ->
UserNames = http_util:get_param("user_names", KvList),
IsForbid = http_util:get_param("is_forbid", KvList),
ForbidTime =
case http_util:get_param("forbid_time", KvList) of
[] -> 0;
ForbidTime1 -> list_to_integer(ForbidTime1)
end,
Reason = http_util:get_param("reason", KvList),
UserNameList = string:tokens(UserNames, ","),
cast_to_server(lib_admin, ban_role, [UserNameList, list_to_integer(IsForbid), ForbidTime, Reason]),
?INFO_MSG("IsForbid:~p ~n ForbidTime:~p ~n UserName:~ts ~n list:~ts ~n Reason:~ts ~n",
[IsForbid, ForbidTime, UserNames, UserNameList, Reason]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%% / IP
do_handle_request("ip_ban", KvList, Socket) ->
IP = http_util:get_param("ip", KvList),
IsForbid = http_util:get_param("is_forbid", KvList),
ForbidTime =
case http_util:get_param("forbid_time", KvList) of
[] -> 0;
ForbidTime1 -> list_to_integer(ForbidTime1)
end,
Reason = http_util:get_param("reason", KvList),
IpList = string:tokens(IP, ","),
cast_to_server(lib_admin, ban_ip, [IpList, list_to_integer(IsForbid), ForbidTime, Reason]),
?INFO_MSG("IsForbid:~p ForbidTime:~p IP:~ts Reason:~ts ~n", [IsForbid, ForbidTime, IP, Reason]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("kick_user", KvList, Socket) ->
UserNames = http_util:get_param("user_names", KvList),
KillFlag = list_to_integer(http_util:get_param("kick_all", KvList)),
Reason = http_util:get_param("reason", KvList),
if
KillFlag =:= 0 -> %
UserNameList = string:tokens(UserNames, ","),
cast_to_server(lib_admin, kick_user, [UserNameList, Reason]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
KillFlag =:= 1 -> %
cast_to_server(lib_admin, kick_all_user, []),
gen_tcp:send(Socket, ?SUCCESS_CODE);
true ->
gen_tcp:send(Socket, ?PARAM_ERROR_CODE)
end,
?INFO_MSG("KillFlag:~p Reason:~ts UserNames:~ts ~n", [KillFlag, Reason]);
%% /
do_handle_request("ban_chat", KvList, Socket) ->
UserNames = http_util:get_param("user_names", KvList),
BanFlag = list_to_integer(http_util:get_param("is_ban", KvList)),
BanTime1 = http_util:get_param("ban_date", KvList), % 0=
BanTime =
case BanTime1 =:= [] of
true -> 0;
false -> list_to_integer(BanTime1)
end,
Reason = http_util:get_param("reason", KvList),
UserNameList = string:tokens(UserNames, ","),
cast_to_server(lib_admin, donttalk, [UserNameList, BanFlag, BanTime, Reason]), %1= 0=
?INFO_MSG("BanFlag:~p BanTime:~p Reason:~ts UserNames:~ts ~n", [BanFlag, BanTime, Reason, UserNames]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("game_instructor_manage", KvList, Socket) ->
UserName = http_util:get_param("user_name", KvList),
Type = http_util:get_param("type", KvList), %1= 0=
InstructorType = http_util:get_param("instructor_type", KvList), %1. 2.3.4.5.GM
StartTime = http_util:get_param("start_time", KvList),
EndTime = http_util:get_param("end_time", KvList),
%% cast_to_server(lib_mail, broadcast_sys_msg, [UserName, Type, InstructorType, StartTime, EndTime]),
?INFO_MSG("Type:~p InstructorType:~p StartTime:~p EndTime:~p UserName:~ts ~n", [Type, InstructorType, StartTime, EndTime, UserName]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("reset_user_pos", KvList, Socket) ->
UserName = http_util:get_param("user_name", KvList),
%% cast_to_server(lib_mail, broadcast_sys_msg, UserName),
?INFO_MSG("content:~ts ~n", [UserName]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("count_user", KvList, Socket) ->
ok;
%%
do_handle_request("user_info_detail", KvList, Socket) ->
UserId = http_util:get_param("user_id", KvList),
UserName = http_util:get_param("user_name", KvList),
Account = http_util:get_param("account", KvList),
% SQL语句里面是and的关系
%% case call_to_server(lib_admin, get_player_info, [UserId, UserName, Account]) of
%% {badrpc, _} ->
%% gen_tcp:send(Socket, ?FAILED_CODE);
%% Player ->
%% RetMsg = <<>>,
%% gen_tcp:send(Socket, ?SUCCESS_CODE)
%% end,
?INFO_MSG("UserId:~p UserName:~ts Account:~ts ~n", [UserId, UserName, Account]);
% desc {"字段名":"字段中文含义"} {"user_name":"角色名称",user_id":"ID"}
% data data
%
% account
% user_id ID
% user_name
% reg_time
% level
% last_login_ip IP
% last_login_time
% country -1
% guild -1
% career -1
% ()
%
% {
% "account":"gfsyra",
% "user_id":"221",
% "user_name":"高富帅有人爱",
% "reg_time":"1371928400",
% "level":"22",
% "reg_time":"22",
% "last_login_ip":"94.123.22.123",
% "last_login_time":"1388928400",
% "country":"魏国",
% "guild":"超级兵马俑",
% "career":"魏将",
% "is_vip":"y",
% "sex":"1",
% ......
%
%%
do_handle_request("user_info_list", KvList, Socket) ->
ok;
%%
do_handle_request("guild_info_detail", KvList, Socket) ->
GuildId = http_util:get_param("guild_id", KvList),
GuildName = http_util:get_param("guild_name", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [GuildId, GuildName]),
?INFO_MSG("type:~p content:~ts ~n", [GuildId, GuildName]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
% data
%
% guild_id ID
% guild_name
% guild_level
% guild_ranking
% leader
% create_time
% member_count
% member_list json数组格式
% ()
%
% {
% "guild_id":"1234",
% "guild_name":"高富帅帮",
% "guild_level":"2",
% "guild_ranking":"1",
% "member_count":"3",
% "member_list":[
% "", "","","高富帅有人爱"
% ],
% "leader":"高富帅有人爱",
% "create_time":"1388928400",
% "is_vip":"y",
% ......
% }
%%
do_handle_request("guild_info_list", KvList, Socket) ->
GuildId = http_util:get_param("guild_id", KvList),
GuildName = http_util:get_param("guild_name", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [GuildId, GuildName]),
?INFO_MSG("type:~p content:~ts ~n", [GuildId, GuildName]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%% 线
do_handle_request("freshen_online_user", KvList, Socket) ->
%% cast_to_server(lib_mail, broadcast_sys_msg, []),
?INFO_MSG("freshen_online_user ~p ~n", []),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("admin_send_gift", KvList, Socket) ->
Action = list_to_integer(http_util:get_param("action", KvList)),
UserNames = http_util:get_param("user_names", KvList),
UserIds = http_util:get_param("user_ids", KvList),
MinLvStr = http_util:get_param("min_lv", KvList),
MinLv =
case MinLvStr =:= [] of
true -> 0;
false -> list_to_integer(MinLvStr)
end,
MaxLvStr = http_util:get_param("max_lv", KvList),
MaxLv =
case MaxLvStr =:= [] of
true -> 0;
false -> list_to_integer(MaxLvStr)
end,
%% min_login_time = http_util:get_param("min_login_time", KvList),
%% max_login_time = http_util:get_param("max_login_time", KvList),
%% min_reg_time = http_util:get_param("min_reg_time", KvList),
%% max_reg_time = http_util:get_param("max_reg_time", KvList),
%% sex = http_util:get_param("sex", KvList),
%% career = http_util:get_param("career", KvList),
%% guild = http_util:get_param("guild", KvList),
MailTitle = http_util:get_param("mail_title", KvList),
MailConten = http_util:get_param("mail_content", KvList),
MoneyAmounts = http_util:get_param("money_amounts", KvList), % 使money_type币种对应
MoneyTypes = http_util:get_param("money_types", KvList), % 1=2=3=4= 5=
ItemIds = http_util:get_param("item_ids", KvList), % id使id
ItemTypes = http_util:get_param("item_types", KvList), % :1= 0=
ItemCounts = http_util:get_param("item_counts", KvList), % :item_ids顺序对应
%% item_levels = http_util:get_param("item_levels", KvList),
UserNameList = string:tokens(UserNames, ","),
UserIdList = [list_to_integer(Uid) || Uid <- string:tokens(UserIds, ",")],
MoneyAmountList = string:tokens(MoneyAmounts, ","),
MoneyTypeList = string:tokens(MoneyTypes, ","),
ItemIdList = string:tokens(ItemIds, ","),
%% ItemTypeList = string:tokens(ItemTypes, ","),
ItemCountList = string:tokens(ItemCounts, ","),
?TRACE("MoneyAmountList:~p ~n MoneyTypeList:~p ~n ItemIdList:~p ~n ItemCountList:~p ~n", [MoneyAmountList, MoneyTypeList, ItemIdList, ItemCountList]),
{Res, GoodsList} = get_gooods_list(MoneyAmountList, MoneyTypeList, ItemIdList, ItemCountList),
?TRACE("Res:~p List:~p ~n", [Res, GoodsList]),
case Res =:= fail of
true -> gen_tcp:send(Socket, ?PARAM_ERROR_CODE);
false ->
if
Action =:= 0 -> %
cast_to_server(lib_mail, send_mail, [all, GoodsList]);
Action =:= 1 -> % user_names user_ids
case length(UserNameList) > 0 of
true ->
cast_to_server(lib_mail, send_goods_money_mail, [UserNameList, GoodsList]);
false ->
skip
end,
case length(UserIdList) > 0 of
true ->
cast_to_server(lib_mail, send_goods_money_mail, [UserIdList, GoodsList]);
false ->
skip
end;
Action =:= 2 -> % "条件参数"
cast_to_server(lib_mail, send_mail, [all, MinLv, MaxLv, GoodsList]);
Action =:= 3 -> % 线
cast_to_server(lib_mail, send_mail, [online, GoodsList]);
true ->
ok
end,
?INFO_MSG("Action:~p title:~ts content:~ts ~n", [Action, MailTitle, MailConten]),
gen_tcp:send(Socket, ?SUCCESS_CODE)
end;
%%
do_handle_request("user_props_list", KvList, Socket) ->
UserId = http_util:get_param("user_id", KvList),
UserName = http_util:get_param("user_name", KvList),
Account = http_util:get_param("account", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [UserId, UserName, Account]),
?INFO_MSG("UserId:~p UserName:~ts Account:~ts ~n", [UserId, UserName, Account]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("user_horse_list", KvList, Socket) ->
UserId = http_util:get_param("user_id", KvList),
UserName = http_util:get_param("user_name", KvList),
Account = http_util:get_param("account", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [UserId, UserName, Account]),
?INFO_MSG("UserId:~p UserName:~ts Account:~ts ~n", [UserId, UserName, Account]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("user_pet_list", KvList, Socket) ->
UserId = http_util:get_param("user_id", KvList),
UserName = http_util:get_param("user_name", KvList),
Account = http_util:get_param("account", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [UserId, UserName, Account]),
?INFO_MSG("UserId:~p UserName:~ts Account:~ts ~n", [UserId, UserName, Account]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("user_skill_list", KvList, Socket) ->
UserId = http_util:get_param("user_id", KvList),
UserName = http_util:get_param("user_name", KvList),
Account = http_util:get_param("account", KvList),
%% call_to_server(lib_mail, broadcast_sys_msg, [UserId, UserName, Account]),
?INFO_MSG("UserId:~p UserName:~ts Account:~ts ~n", [UserId, UserName, Account]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
do_handle_request("broad", KvList, Socket) ->
AnnId = http_util:get_param("annid", KvList),
cast_to_server(mod_misc, load_sys_announce, [AnnId, annid]),
%% lib_chat:broadcast_sys_msg("test"),
?INFO_MSG("type:~p content ~n", [AnnId]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
%%
do_handle_request("charge", KvList, Socket) ->
AccountId = list_to_integer(http_util:get_param("account_id", KvList)),
OrderId = list_to_integer(http_util:get_param("order_id", KvList)),
cast_to_server(lib_admin, handle_charge, [AccountId, OrderId]),
?INFO_MSG("Account:~p OrderId:~p ~n", [AccountId, OrderId]),
gen_tcp:send(Socket, ?SUCCESS_CODE);
do_handle_request(Other, Kvlist, Socket) ->
?INFO_MSG("admin unknown cmd ~p, ~p", [Other, Kvlist]),
gen_tcp:send(Socket, ?PARAM_ERROR_CODE).
%% ========================================================
cast_to_server(Module, Method, Args) ->
GameSvrNode = config:get_server_node(local_gateway),
rpc:cast(GameSvrNode, Module, Method, Args).
call_to_server(Module, Method, Args) ->
GameSvrNode = config:get_server_node(local_gateway),
rpc:call(GameSvrNode, Module, Method, Args).
get_gooods_list(MoneyAmountList, MoneyTypeList, ItemIdList, ItemCountList) ->
if
length(MoneyAmountList) /= length(MoneyTypeList) ->
{fail, []};
length(ItemIdList) /= length(ItemCountList) ->
{fail, []};
true ->
F = fun(Type, {List, Seq, MList}) ->
MoneyType = list_to_integer(Type),
if
MoneyType =:= 1 -> {[{?MONEY_GOLD_T_ID, list_to_integer(lists:nth(Seq, MList))} | List], Seq + 1, MList};
MoneyType =:= 2 ->
{[{?MONEY_BGOLD_T_ID, list_to_integer(lists:nth(Seq, MList))} | List], Seq + 1, MList};
MoneyType =:= 3 -> {[{?MONEY_COIN_T_ID, list_to_integer(lists:nth(Seq, MList))} | List], Seq + 1, MList};
MoneyType =:= 4 ->
{[{?MONEY_BCOIN_T_ID, list_to_integer(lists:nth(Seq, MList))} | List], Seq + 1, MList};
true -> {List, Seq, MList}
end
end,
{GoodsList, _Seq, _L} = lists:foldl(F, {[], 1, MoneyAmountList}, MoneyTypeList),
F1 = fun(Gtid, {List1, Seq1, CountList}) ->
{[{list_to_integer(Gtid), list_to_integer(lists:nth(Seq1, CountList))} | List1], Seq1 + 1, CountList}
end,
{GoodsList1, _Seq1, _L1} = lists:foldl(F1, {[], 1, ItemCountList}, ItemIdList),
{ok, GoodsList ++ GoodsList1}
end.
%% 退()
safe_quit() ->
timer:sleep(10 * 1000),
mod_guild:safe_quit(),
main:server_stop(),
ok.
stop_server_node([NodeName]) ->
rpc:cast(NodeName, main, server_stop, []).
stop_local_gateway_node([NodeName]) ->
rpc:cast(NodeName, main, local_gateway_stop, []).
stop_game_node([NodeName]) ->
rpc:cast(NodeName, main, gateway_stop, []).
%% ,
clear_data() ->
AllTables = db_esql:get_all("show tables"),
Fun = fun(Item) ->
[TName | _] = Item,
TableName = util:bitstring_to_term(TName),
ListTableName = atom_to_list(TableName),
case lists:sublist(ListTableName, 1, 5) =:= "temp_" orelse
lists:sublist(ListTableName, 1, 7) =:= "config_" of
true ->
skip;
false ->
TruncatSql = lists:concat(["truncate table ", TableName]),
db_esql:execute_sql(TruncatSql),
io:format("==truncated table:~p~n", [TableName])
end
end,
lists:foreach(Fun, AllTables),
timer:sleep(1000),
erlang:halt().
%% Sql = lists:concat(["show tables"]),
%% case db_esql:get_row(Sql) of
%% {db_error, _} ->
%% error;
%% [_, A|_]->
%% CreateTableList = re:split(A,"[\n]",[{return, binary}]),
%% search_auto_increment(CreateTableList)
%% end.

+ 132
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/php_parser.erl Dosyayı Görüntüle

@ -0,0 +1,132 @@
%% Author: Richard Jones
%% Modified: bisonwu
%% Description: Takes a serialized php object and turns it into an erlang data structure
-module(php_parser).
%%
%% Include files
%%
%%
%% Exported Functions
%%
-export([unserialize/1]).
-export([serialize_map/1, serialize_map/2]).
%%
%% API Functions
%%
%% @spec serialize_map/1
%% @doc serialize for key-value list
serialize_map(KeyValueList) when is_list(KeyValueList) ->
serialize_map(KeyValueList, {"i", "d"}).
%% @spec serialize_map/2
%% @doc serialize for key-value list
%% result eg:"a:2:{i:7;d:1277086515;i:8;d:1277086522;}"
serialize_map(KeyValueList, {KeyType, ValType}) when is_list(KeyValueList) ->
%% eg:[{7,1277086515},{8,1277086522}]
Len = length(KeyValueList),
Items = lists:foldr(fun(X, Items) ->
{Key, Val} = X,
lists:concat([KeyType, ":", Key, ";", ValType, ":", Val, ";", Items])
end, "", KeyValueList),
lists:concat(["a:", Len, ":{", Items, "}"]).
%% @spec unserialize/1
%% Usage: {Result, Leftover} = php_parser:unserialize()
unserialize(S) when is_binary(S) -> unserialize(binary_to_list(S));
unserialize(S) when is_list(S) -> takeval(S, 1).
% Internal stuff
takeval(Str, Num) ->
{Parsed, Remains} = takeval(Str, Num, []),
{lists:reverse(Parsed), Remains}.
takeval([$} | Leftover], 0, Acc) -> {Acc, Leftover};
takeval(Str, 0, Acc) -> {Acc, Str};
takeval([], 0, Acc) -> Acc;
takeval(Str, Num, Acc) ->
{Val, Rest} = phpval(Str),
%Lots of tracing if you enable this:
%io:format("\nState\n Str: ~s\n Num: ~w\n Acc:~w\n", [Str,Num,Acc]),
%io:format("-Val: ~w\n-Rest: ~s\n\n",[Val, Rest]),
takeval(Rest, Num - 1, [Val | Acc]).
%
% Parse induvidual php values.
% a "phpval" here is T:val; where T is the type code for int, object, array etc..
%
% Simple ones:
phpval([]) -> [];
phpval([$} | Rest]) -> phpval(Rest); % skip }
phpval([$N, $; | Rest]) -> {null, Rest}; % null
phpval([$b, $:, $1, $; | Rest]) -> {true, Rest}; % true
phpval([$b, $:, $0, $; | Rest]) -> {false, Rest}; % false
% r seems to be a recursive reference to something, represented as an int.
phpval([$r, $: | Rest]) ->
{RefNum, [$; | Rest1]} = string:to_integer(Rest),
{{php_ref, RefNum}, Rest1};
% int
phpval([$i, $: | Rest]) ->
{Num, [$; | Rest1]} = string:to_integer(Rest),
{Num, Rest1};
% double / float
% NB: php floats can be ints, and string:to_float doesnt like that.
phpval(_X = [$d, $: | Rest]) ->
{Num, [$; | Rest1]} = case string:to_float(Rest) of
{error, no_float} -> string:to_integer(Rest);
{N, R} -> {N, R}
end,
{Num, Rest1};
% string
phpval([$s, $: | Rest]) ->
{Len, [$: | Rest1]} = string:to_integer(Rest),
S = list_to_binary(string:sub_string(Rest1, 2, Len + 1)),
{S, lists:nthtail(Len + 3, Rest1)};
% array
phpval([$a, $: | Rest]) ->
{NumEntries, [$:, ${ | Rest1]} = string:to_integer(Rest),
{Array, Rest2} = takeval(Rest1, NumEntries * 2),
{arraytidy(Array), Rest2};
% object O:4:\"User\":53:{
phpval([$O, $: | Rest]) ->
{ClassnameLen, [$: | Rest1]} = string:to_integer(Rest),
% Rest1: "classname":NumEnt:{..
Classname = string:sub_string(Rest1, 2, ClassnameLen + 1),
Rest1b = lists:nthtail(ClassnameLen + 3, Rest1),
{NumEntries, [$:, ${ | Rest2]} = string:to_integer(Rest1b),
{Classvals, Rest3} = takeval(Rest2, NumEntries * 2),
{{class, Classname, arraytidy(Classvals)}, Rest3}.
%%
%% Helpers:
%%
% convert [ k1,v1,k2,v2,k3,v3 ] into [ {k1,v2}, {k2,v2}, {k3,v3} ]
arraytidy(L) ->
lists:reverse(lists:foldl(fun arraytidy/2, [], L)).
arraytidy(El, [{key___partial, K} | L]) -> [{atomize(K), El} | L];
arraytidy(El, L) -> [{key___partial, El} | L].
%% Make properties or keys into atoms
atomize(K) when is_binary(K) ->
atomize(binary_to_list(K));
atomize(K) when is_list(K) ->
list_to_atom(string:to_lower(K));
atomize(K) -> K.

+ 651
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/tool.erl Dosyayı Görüntüle

@ -0,0 +1,651 @@
-module(tool).
-compile(export_all).
-define(IOFILE(Str, Args), (fun() ->
Command = io_lib:format(Str, Args),
file:write_file("../logs/data/proto_data.log", Command, [append])
end)()).
%%
stat_proto_data() ->
List = ets:tab2list(proto_stat),
NewList = lists:map(fun({Cmd, ProtoNum}) ->
{ProtoNum, Cmd}
end, List),
lists:foreach(fun({ProtoNum, Cmd}) ->
?IOFILE("协议->~p使用次数为->~p ~n", [Cmd, ProtoNum])
end
, lists:sort(NewList)).
%%
trace_profile_result() ->
eprof:stop_profiling(),
eprof:analyze(total).
%%
split(N, SrcList) ->
case length(SrcList) > N of
true ->
lists:split(N, SrcList);
false ->
{SrcList, []}
end.
%% @doc get IP address string from Socket
ip(Socket) ->
{ok, {IP, _Port}} = inet:peername(Socket),
{Ip0, Ip1, Ip2, Ip3} = IP,
list_to_binary(integer_to_list(Ip0) ++ "." ++ integer_to_list(Ip1) ++ "." ++ integer_to_list(Ip2) ++ "." ++ integer_to_list(Ip3)).
%% @doc quick sort
sort([]) ->
[];
sort([H | T]) ->
sort([X || X <- T, X < H]) ++ [H] ++ sort([X || X <- T, X >= H]).
%% for
for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I) | for(I + 1, Max, F)].
%%---------------------------------------------------
%% by chenzm
%%@spec for(n,m,fun()) -> []
%%---------------------------------------------------
add_index([]) ->
[];
add_index(List) ->
for(1, length(List), fun(I) ->
Elem = lists:nth(I, List),
if
is_tuple(Elem) ->
list_to_tuple([I] ++ tuple_to_list(Elem));
true ->
{I, Elem}
end
end).
add_index_to_record(List) ->
case List of
[] ->
[];
_ ->
for(1, length(List), fun(I) ->
Elem = lists:nth(I, List),
{I, Elem}
end)
end.
%% @doc convert float to string, f2s(1.5678) -> 1.57
f2s(N) when is_integer(N) ->
integer_to_list(N) ++ ".00";
f2s(F) when is_float(F) ->
[A] = io_lib:format("~.2f", [F]),
A.
%% @doc convert other type to atom
to_atom(Msg) when is_atom(Msg) ->
Msg;
to_atom(Msg) when is_binary(Msg) ->
tool:list_to_atom2(binary_to_list(Msg));
to_atom(Msg) when is_list(Msg) ->
tool:list_to_atom2(Msg);
to_atom(_) ->
throw(other_value). %%list_to_atom("").
%% @doc convert other type to list
to_list(Msg) when is_list(Msg) ->
Msg;
to_list(Msg) when is_atom(Msg) ->
atom_to_list(Msg);
to_list(Msg) when is_binary(Msg) ->
binary_to_list(Msg);
to_list(Msg) when is_integer(Msg) ->
integer_to_list(Msg);
to_list(Msg) when is_float(Msg) ->
f2s(Msg);
to_list(_) ->
throw(other_value).
%% @doc convert other type to binary
to_binary(Msg) when is_binary(Msg) ->
Msg;
to_binary(Msg) when is_atom(Msg) ->
list_to_binary(atom_to_list(Msg));
%%atom_to_binary(Msg, utf8);
to_binary(Msg) when is_list(Msg) ->
list_to_binary(Msg);
to_binary(Msg) when is_integer(Msg) ->
list_to_binary(integer_to_list(Msg));
to_binary(Msg) when is_float(Msg) ->
list_to_binary(f2s(Msg));
to_binary(_Msg) ->
throw(other_value).
%% @doc convert other type to float
to_float(Msg) ->
Msg2 = to_list(Msg),
list_to_float(Msg2).
%% @doc convert other type to integer
%% -spec to_integer(Msg :: any()) -> integer(). %%liujing 2012-8-9 cancel
to_integer(Msg) when is_integer(Msg) ->
Msg;
to_integer(Msg) when is_binary(Msg) ->
Msg2 = binary_to_list(Msg),
list_to_integer(Msg2);
to_integer(Msg) when is_list(Msg) ->
list_to_integer(Msg);
to_integer(Msg) when is_float(Msg) ->
round(Msg);
to_integer(_Msg) ->
throw(other_value).
to_bool(D) when is_integer(D) ->
D =/= 0;
to_bool(D) when is_list(D) ->
length(D) =/= 0;
to_bool(D) when is_binary(D) ->
to_bool(binary_to_list(D));
to_bool(D) when is_boolean(D) ->
D;
to_bool(_D) ->
throw(other_value).
%% @doc convert other type to tuple
to_tuple(T) when is_tuple(T) -> T;
to_tuple(T) -> {T}.
%% @doc get data type {0=integer,1=list,2=atom,3=binary}
get_type(DataValue, DataType) ->
case DataType of
0 ->
DataValue2 = binary_to_list(DataValue),
list_to_integer(DataValue2);
1 ->
binary_to_list(DataValue);
2 ->
DataValue2 = binary_to_list(DataValue),
list_to_atom(DataValue2);
3 ->
DataValue
end.
%% @spec is_string(List)-> yes|no|unicode
is_string([]) -> yes;
is_string(List) -> is_string(List, non_unicode).
is_string([C | Rest], non_unicode) when C >= 0, C =< 255 -> is_string(Rest, non_unicode);
is_string([C | Rest], _) when C =< 65000 -> is_string(Rest, unicode);
is_string([], non_unicode) -> yes;
is_string([], unicode) -> unicode;
is_string(_, _) -> no.
%% @doc get random list
list_random(List) ->
case List of
[] ->
{};
_ ->
RS = lists:nth(random:uniform(length(List)), List),
ListTail = lists:delete(RS, List),
{RS, ListTail}
end.
%% @doc get a random integer between Min and Max
random(Min, Max) ->
Min2 = Min - 1,
random:uniform(Max - Min2) + Min2.
%% @doc
random_dice(Face, Times) ->
if
Times == 1 ->
random(1, Face);
true ->
lists:sum(for(1, Times, fun(_) -> random(1, Face) end))
end.
%% @doc
odds(Numerator, Denominator) ->
Odds = random:uniform(Denominator),
if
Odds =< Numerator ->
true;
true ->
false
end.
odds_list(List) ->
Sum = odds_list_sum(List),
odds_list(List, Sum).
odds_list([{Id, Odds} | List], Sum) ->
case odds(Odds, Sum) of
true ->
Id;
false ->
odds_list(List, Sum - Odds)
end.
odds_list_sum(List) ->
{_List1, List2} = lists:unzip(List),
lists:sum(List2).
%% @doc X的最小整数
ceil(X) ->
T = trunc(X),
if
X - T == 0 ->
T;
true ->
if
X > 0 ->
T + 1;
true ->
T
end
end.
%% @doc X的最大整数
floor(X) ->
T = trunc(X),
if
X - T == 0 ->
T;
true ->
if
X > 0 ->
T;
true ->
T - 1
end
end.
%% 45
%% round(X)
%% subatom
subatom(Atom, Len) ->
list_to_atom(lists:sublist(atom_to_list(Atom), Len)).
%% @doc
sleep(Msec) ->
receive
after Msec ->
true
end.
md5(S) ->
Md5_bin = erlang:md5(S),
Md5_list = binary_to_list(Md5_bin),
lists:flatten(list_to_hex(Md5_list)).
list_to_hex(L) ->
lists:map(fun(X) -> int_to_hex(X) end, L).
int_to_hex(N) when N < 256 ->
[hex(N div 16), hex(N rem 16)].
hex(N) when N < 10 ->
$0 + N;
hex(N) when N >= 10, N < 16 ->
$a + (N - 10).
list_to_atom2(List) when is_list(List) ->
case catch (list_to_existing_atom(List)) of
{'EXIT', _} -> erlang:list_to_atom(List);
Atom when is_atom(Atom) -> Atom
end.
combine_lists(L1, L2) ->
Rtn =
lists:foldl(
fun(T, Acc) ->
case lists:member(T, Acc) of
true ->
Acc;
false ->
[T | Acc]
end
end, lists:reverse(L1), L2),
lists:reverse(Rtn).
get_process_info_and_zero_value(InfoName) ->
PList = erlang:processes(),
ZList = lists:filter(
fun(T) ->
case erlang:process_info(T, InfoName) of
{InfoName, 0} -> false;
_ -> true
end
end, PList),
ZZList = lists:map(
fun(T) -> {T, erlang:process_info(T, InfoName), erlang:process_info(T, registered_name)}
end, ZList),
[length(PList), InfoName, length(ZZList), ZZList].
get_process_info_and_large_than_value(InfoName, Value) ->
PList = erlang:processes(),
ZList = lists:filter(
fun(T) ->
case erlang:process_info(T, InfoName) of
{InfoName, VV} ->
if VV > Value -> true;
true -> false
end;
_ -> true
end
end, PList),
ZZList = lists:map(
fun(T) -> {T, erlang:process_info(T, InfoName), erlang:process_info(T, registered_name)}
end, ZList),
[length(PList), InfoName, Value, length(ZZList), ZZList].
get_msg_queue() ->
io:fwrite("process count:~p~n~p value is not 0 count:~p~nLists:~p~n",
get_process_info_and_zero_value(message_queue_len)).
get_memory() ->
io:fwrite("process count:~p~n~p value is large than ~p count:~p~nLists:~p~n",
get_process_info_and_large_than_value(memory, 1048576)).
get_memory(Value) ->
io:fwrite("process count:~p~n~p value is large than ~p count:~p~nLists:~p~n",
get_process_info_and_large_than_value(memory, Value)).
get_heap() ->
io:fwrite("process count:~p~n~p value is large than ~p count:~p~nLists:~p~n",
get_process_info_and_large_than_value(heap_size, 1048576)).
get_heap(Value) ->
io:fwrite("process count:~p~n~p value is large than ~p count:~p~nLists:~p~n",
get_process_info_and_large_than_value(heap_size, Value)).
get_processes() ->
io:fwrite("process count:~p~n~p value is large than ~p count:~p~nLists:~p~n",
get_process_info_and_large_than_value(memory, 0)).
list_to_term(String) ->
{ok, T, _} = erl_scan:string(String ++ "."),
case erl_parse:parse_term(T) of
{ok, Term} ->
Term;
{error, Error} ->
Error
end.
substr_utf8(Utf8EncodedString, Length) ->
substr_utf8(Utf8EncodedString, 1, Length).
substr_utf8(Utf8EncodedString, Start, Length) ->
ByteLength = 2 * Length,
Ucs = xmerl_ucs:from_utf8(Utf8EncodedString),
Utf16Bytes = xmerl_ucs:to_utf16be(Ucs),
SubStringUtf16 = lists:sublist(Utf16Bytes, Start, ByteLength),
Ucs1 = xmerl_ucs:from_utf16be(SubStringUtf16),
xmerl_ucs:to_utf8(Ucs1).
ip_str(IP) ->
case IP of
{A, B, C, D} ->
lists:concat([A, ".", B, ".", C, ".", D]);
{A, B, C, D, E, F, G, H} ->
lists:concat([A, ":", B, ":", C, ":", D, ":", E, ":", F, ":", G, ":", H]);
Str when is_list(Str) ->
Str;
_ ->
[]
end.
%%0
int_format(Num) ->
if Num >= 0 ->
Num;
true ->
0
end.
%%
remove_string_black(L) ->
F = fun(S) ->
if S == 32 -> [];
true -> S
end
end,
Result = [F(lists:nth(I, L)) || I <- lists:seq(1, length(L))],
lists:filter(fun(T) -> T =/= [] end, Result).
%%true->false ->
%%spec is_operate_ok/1 param: Type -> (atom); return: true->false ->
is_operate_ok(Type, TimeStamp) ->
NowTime = util:longunixtime(),
case get(Type) of
undefined ->
put(Type, NowTime),
true;
Value ->
case (NowTime - Value) >= TimeStamp of
true ->
put(Type, NowTime),
true;
false ->
false
end
end.
%%
pack_string(Str) ->
StrBin = tool:to_binary(Str),
Len = byte_size(StrBin),
{Len, StrBin}.
%%[{GetName, Rate},..],undefined
get_rand_single(RateList) ->
Fun = fun({_Tmp, R}, RNum) ->
RNum + R
end,
AllR = lists:foldl(Fun, 0, RateList),
GetRNum = util:rand(1, AllR),
Fun1 = fun({Atom, Rat}, [BGet, Ra, FirstNum, GetAtom1]) ->
EndNum = FirstNum + Rat,
if BGet =:= 0 andalso Ra =< EndNum ->
[1, Ra, EndNum, Atom];
true ->
[BGet, Ra, EndNum, GetAtom1]
end
end,
[_NewBGet, _NewRa, _FirstNum, GetAtom] = lists:foldl(Fun1, [0, GetRNum, 0, undefined], RateList),
GetAtom.
%%[{GetName, Rate, MinNum, MaxNum},..],undefined
get_rand_single2(RateList) ->
Fun = fun({_Tmp, R, _Mn, _Mx}, RNum) ->
RNum + R
end,
AllR = lists:foldl(Fun, 0, RateList),
GetRNum = util:rand(1, AllR),
Fun1 = fun({Atom, Rat, MinNum, MaxNum}, [BGet, Ra, FirstNum, GetAtom1]) ->
EndNum = FirstNum + Rat,
if BGet =:= 0 andalso Ra =< EndNum ->
[1, Ra, EndNum, {Atom, MinNum, MaxNum}];
true ->
[BGet, Ra, EndNum, GetAtom1]
end
end,
[_NewBGet, _NewRa, _FirstNum, GetAtom] = lists:foldl(Fun1, [0, GetRNum, 0, undefined], RateList),
GetAtom.
%%======2012-9-17 from liujing======
%%()
get_handle_table_name() ->
TableList = lib_player_rw:get_all_tables(),
F = fun(TableName, GetList) ->
TableName1 = util:term_to_string(TableName),
case TableName1 =/= "cards" andalso TableName1 =/= "sys_acm" andalso string:str(TableName1, "admin") =/= 1
andalso TableName1 =/= "auto_ids" andalso TableName1 =/= "shop" andalso string:str(TableName1, "base") =/= 1
andalso TableName1 =/= "slaves" andalso TableName1 =/= "battle_cache_data" andalso string:str(TableName1, "arena") =/= 1
andalso string:str(TableName1, "log_") =/= 1 andalso string:str(TableName1, "th") =/= 1
andalso TableName1 =/= "rela" of
false -> GetList;
true ->
GetList ++ [util:string_to_term(tool:to_list(TableName1))]
end
end,
lists:foldl(F, [], TableList).
ini_faraway_mongo_db(PoolId, Num) ->
Host =
case Num of
1 ->
"113.105.250.125";
2 ->
"113.105.251.123";
4 ->
"183.61.130.69";
_ ->
%%192.168.51.174
"192.168.51.174"
end,
%% Host = io:get_line("remote database ip:") ,
Port = 27017,
case Num of
0 ->
DB = "csj_dev_S1";
_ ->
DB = lists:concat(["csj_dev_S", Num])
end,
io:format("====dest db:~p~n", [[Host, DB]]),
EmongoSize = 1,
emongo_sup:start_link(),
emongo_app:initialize_pools([PoolId, Host, Port, DB, EmongoSize]).
ini_local_mongo_db(PoolId, Num) ->
Host = "192.168.51.174",
%% Host = io:get_line("sorce database ip:") ,
Port = 27017,
case Num of
0 ->
DB = "csj_dev_src_S1";
_ ->
DB = lists:concat(["csj_dev_src_S", Num])
end,
io:format("====src db:~p~n", [DB]),
EmongoSize = 1,
emongo_sup:start_link(),
emongo_app:initialize_pools([PoolId, Host, Port, DB, EmongoSize]).
get_mongo_to_mysql(UidList, ServerNum) ->
%% CONFIG_FILE = "../config/gateway.config",
FarPoolId = lists:concat(["master_mongo_tmp", ServerNum]),
LocalPoolId = "master_mongo_l",
TableList = get_handle_table_name(),
ini_faraway_mongo_db(FarPoolId, ServerNum),
ini_local_mongo_db(LocalPoolId, ServerNum),
Fun1 = fun(TableName, GetUid) ->
case TableName of
player ->
io:format("========_1_~n"),
[WhereOpertion, FieldOpertion] = db_mongoutil:make_select_opertion(db_mongo:transfer_fields(TableName, "*"), [{id, GetUid}], [], []),
L = emongo:find_all(LocalPoolId, tool:to_list(TableName), WhereOpertion, FieldOpertion),
io:format("========_1_~p~n", [L]),
RList = db_mongo:handle_all_result(TableName, db_mongo:transfer_fields(TableName, "*"), L),
[DelOpertion] = db_mongoutil:make_delete_opertion([{id, GetUid}]),
emongo:delete(FarPoolId, tool:to_list(TableName), DelOpertion),
case RList of
[] ->
GetUid;
_ ->
FieldList = db_mongo:get_all_fields(TableName),
Fun2 = fun(RL) ->
FullKeyValuelist = db_mongo:fullKeyValue(TableName, lists:zip(FieldList, RL)),
FullKeyValuelist1 = checkF(FullKeyValuelist),
Opertion = db_mongoutil:make_insert_opertion(FullKeyValuelist1),
emongo:insert(FarPoolId, tool:to_list(TableName), Opertion)
end,
lists:foreach(Fun2, RList),
GetUid
end;
_ ->
io:format("========_3_[~p]~n", [TableName]),
FieldList = db_mongo:get_all_fields(TableName),
case FieldList of
undefined ->
GetUid;
[] ->
GetUid;
_ ->
[WhereOpertion, FieldOpertion] = db_mongoutil:make_select_opertion(db_mongo:transfer_fields(TableName, "*"), [{uid, GetUid}], [], []),
L = emongo:find_all(LocalPoolId, tool:to_list(TableName), WhereOpertion, FieldOpertion),
RList = db_mongo:handle_all_result(TableName, db_mongo:transfer_fields(TableName, "*"), L),
[DelOpertion] = db_mongoutil:make_delete_opertion([{uid, GetUid}]),
emongo:delete(FarPoolId, tool:to_list(TableName), DelOpertion),
case RList of
[] ->
GetUid;
_ ->
Fun2 = fun(RL) ->
FullKeyValuelist = db_mongo:fullKeyValue(TableName, lists:zip(FieldList, RL)),
FullKeyValuelist1 = checkF(FullKeyValuelist),
Opertion = db_mongoutil:make_insert_opertion(FullKeyValuelist1),
emongo:insert(FarPoolId, tool:to_list(TableName), Opertion)
end,
lists:foreach(Fun2, RList),
GetUid
end
end
end
end,
Fun = fun(Uid) ->
lists:foldl(Fun1, Uid, TableList)
end,
lists:foreach(Fun, UidList).
checkF(KeyVList) ->
Fun = fun({Key, Val}) ->
case Val of
[] ->
{Key, <<"[]">>};
undefined ->
{Key, <<"[]">>};
_ ->
{Key, Val}
end
end,
lists:map(Fun, KeyVList).
%%,
%%dynamic_compile死活编译不过
recinfo(FieldList, Rec) ->
RecordName = lists:nth(1, tuple_to_list(Rec)),
ValueList = lists:nthtail(1, tuple_to_list(Rec)),
Length = min(length(FieldList), length(ValueList)),
OutStr = "#" ++ tool:to_list(RecordName) ++ "{\r\n",
OutStr1 = lists:foldl(fun(Idx, Str) ->
Str ++ io_lib:format(" ~p = ~p,~n", [lists:nth(Idx, FieldList), lists:nth(Idx, ValueList)])
end, OutStr, lists:seq(1, Length - 1)),
OutStr1 ++ io_lib:format(" ~p = ~p}~n", [lists:nth(Length, FieldList), lists:nth(Length, ValueList)]).
gcd(A, 0) ->
A;
gcd(A, B) when A >= B ->
gcd(A rem B, B);
gcd(A, B) ->
gcd(B, A).
%%
hcd([H | T]) ->
gcd(H, hcd(T));
hcd([]) ->
0.

+ 563
- 0
src/srvNodeMgr/tools/gameWorld/test/misc/util.erl Dosyayı Görüntüle

@ -0,0 +1,563 @@
%%%-----------------------------------
%%% @Module : util
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description:
%%%-----------------------------------
-module(util).
-include("common.hrl").
-include("record.hrl").
-compile(export_all).
%% List中的每两个元素之间插入一个分隔符
implode(_S, []) ->
[<<>>];
implode(S, L) when is_list(L) ->
implode(S, L, []).
implode(_S, [H], NList) ->
lists:reverse([thing_to_list(H) | NList]);
implode(S, [H | T], NList) ->
L = [thing_to_list(H) | NList],
implode(S, T, [S | L]).
%%X在[Min, Max]
minmax(X, Min, Max) ->
min(max(X, Min), Max).
%% ->
explode(S, B) ->
re:split(B, S, [{return, list}]).
explode(S, B, int) ->
[list_to_integer(Str) || Str <- explode(S, B), length(Str) > 0].
thing_to_list(X) when is_integer(X) -> integer_to_list(X);
thing_to_list(X) when is_float(X) -> float_to_list(X);
thing_to_list(X) when is_atom(X) -> atom_to_list(X);
thing_to_list(X) when is_binary(X) -> binary_to_list(X);
thing_to_list(X) when is_list(X) -> X.
%%
log(T, F, A, Mod, Line) ->
{ok, Fl} = file:open("logs/error_log.txt", [write, append]),
Format = list_to_binary("#" ++ T ++ " ~s[~w:~w] " ++ F ++ "\r\n~n"),
{{Y, M, D}, {H, I, S}} = erlang:localtime(),
Date = list_to_binary([integer_to_list(Y), "-", integer_to_list(M), "-", integer_to_list(D), " ", integer_to_list(H), ":", integer_to_list(I), ":", integer_to_list(S)]),
file:close(Fl).
%% unix时间戳
unixtime() ->
{M, S, _} = game_timer:now(),%%os:timestamp()
M * 1000000 + S.
longunixtime() ->
{M, S, Ms} = game_timer:now(),
(M * 1000000000000 + S * 1000000 + Ms) div 1000.
%% HEX格式的md5
md5(S) ->
lists:flatten([io_lib:format("~2.16.0b", [N]) || N <- binary_to_list(erlang:md5(S))]).
%% Min到Max之间的随机整数
rand(Same, Same) -> Same;
rand(Min, Max) ->
M = Min - 1,
if
Max - M =< 0 ->
0;
true ->
%%
case get("rand_seed") of
undefined ->
RandSeed = mod_rand:get_seed(),
random:seed(RandSeed),
put("rand_seed", RandSeed);
_ -> skip
end,
RanNum = random:uniform(Max - M) + M,
RanNum
end.
%%length(List) >= Num
%%[1,2,3,4,5,6,7,8,9][1,2,4]
get_random_list(List, Num) ->
ListSize = length(List),
F = fun(N, List1) ->
Random = rand(1, (ListSize - N + 1)),
Elem = lists:nth(Random, List1),
List2 = lists:delete(Elem, List1),
List2
end,
Result = lists:foldl(F, List, lists:seq(1, Num)),
List -- Result.
%%[{a,7},{b,8},{c,90},{d,100}],a为7%,
%%Num不能大于lenth(List)
get_random_list_probability(List, Num) ->
F = fun(Elem, ProbabilityValue) ->
lists:duplicate(ProbabilityValue, Elem)
end,
Result1 = lists:flatten([F(Elem, ProbabilityValue) || {Elem, ProbabilityValue} <- List]),
ProbabilityList = lists:reverse(lists:sort([ProbabilityValue || {_Elem, ProbabilityValue} <- List])),
MaxProbabilityValue = lists:sum([lists:nth(N, ProbabilityList) || N <- lists:seq(1, Num)]),
Result2 = get_random_list(Result1, Num + MaxProbabilityValue - length(List)),
Result3 = lists:usort(Result2),
Result4 = get_random_list(Result3, Num),
Result4.
get_randomId_by_value([], _) ->
fail;
get_randomId_by_value(Data, Random) ->
case lists:nth(1, Data) of
{Id, Weight} ->
case Weight >= Random of
true ->
Id;
false ->
get_randomId_by_value(Data -- [{Id, Weight}], Random - Weight)
end;
_ ->
io:format("get_randomId_by_value no match")
end.
%%[{a,7},{b,8},{c,9},{d,10}],a为7权重,b为8权重
get_random_by_weight(List) ->
F = fun({Id, Weight}, Sum) ->
Sum + Weight
end,
Sum2 = lists:foldl(F, 0, List),
RandomVa = random:uniform(Sum2),
RandomId = get_randomId_by_value(List, RandomVa).
%%
ceil(N) ->
T = trunc(N),
case N == T of
true -> T;
false -> 1 + T
end.
%%
floor(X) ->
T = trunc(X),
case (X < T) of
true -> T - 1;
_ -> T
end.
sleep(T) ->
receive
after T -> ok
end.
sleep(T, F) ->
receive
after T -> F()
end.
get_list([], _) ->
[];
get_list(X, F) ->
F(X).
%% for循环
for(Max, Max, F) ->
F(Max);
for(I, Max, F) ->
F(I),
for(I + 1, Max, F).
%% for循环
%% @return {ok, State}
for(Max, Min, _F, State) when Min < Max ->
{ok, State};
for(Max, Max, F, State) -> F(Max, State);
for(I, Max, F, State) -> {ok, NewState} = F(I, State), for(I + 1, Max, F, NewState).
for_new(Min, Max, _F, State) when (Min > Max) ->
{ok, State};
for_new(Min, Max, F, State) ->
{ok, NewState} = F(Min, State),
for_new(Min + 1, Max, F, NewState).
%% term序列化term转换为string格式e.g., [{a},1] => "[{a},1]"
term_to_string(Term) ->
binary_to_list(list_to_binary(io_lib:format("~w", [Term]))).
%% term序列化term转换为bitstring格式e.g., [{a},1] => <<"[{a},1]">>
term_to_bitstring(Term) ->
erlang:list_to_bitstring(io_lib:format("~w", [Term])).
%% term反序列化string转换为terme.g., "[{a},1]" => [{a},1]
string_to_term(String) ->
case String of
[] -> [];
_ ->
case erl_scan:string(String ++ ".") of
{ok, Tokens, _} ->
case erl_parse:parse_term(Tokens) of
{ok, Term} -> Term;
_Err -> undefined
end;
_Error ->
undefined
end
end.
%%string [a,b,c] -> "a,b,c"
list_to_string(List) ->
case List == [] orelse List == "" of
true -> "";
false ->
F = fun(E) ->
tool:to_list(E) ++ ","
end,
L1 = [F(E) || E <- List],
L2 = lists:concat(L1),
string:substr(L2, 1, length(L2) - 1)
end.
%% term反序列化bitstring转换为terme.g., <<"[{a},1]">> => [{a},1]
bitstring_to_term(undefined) -> undefined;
bitstring_to_term(BitString) ->
string_to_term(tool:to_list(BitString)).
%%
%% -----------------------------------------------------------------
%% 1970
%% -----------------------------------------------------------------
seconds_to_localtime(Seconds) ->
DateTime = calendar:gregorian_seconds_to_datetime(Seconds + ?DIFF_SECONDS_0000_1900),
calendar:universal_time_to_local_time(DateTime).
%% -----------------------------------------------------------------
%%
%% -----------------------------------------------------------------
is_same_date(Seconds1, Seconds2) ->
NDay = (Seconds1 + 8 * 3600) div 86400,
ODay = (Seconds2 + 8 * 3600) div 86400,
NDay =:= ODay.
%% -----------------------------------------------------------------
%%
%% -----------------------------------------------------------------
is_same_week(Seconds1, Seconds2) ->
{{Year1, Month1, Day1}, Time1} = seconds_to_localtime(Seconds1),
%
Week1 = calendar:day_of_the_week(Year1, Month1, Day1),
%
Diff1 = calendar:time_to_seconds(Time1),
Monday = Seconds1 - Diff1 - (Week1 - 1) * ?ONE_DAY_SECONDS,
Sunday = Seconds1 + (?ONE_DAY_SECONDS - Diff1) + (7 - Week1) * ?ONE_DAY_SECONDS,
if ((Seconds2 >= Monday) and (Seconds2 < Sunday)) -> true;
true -> false
end.
%% -----------------------------------------------------------------
%% 00
%% -----------------------------------------------------------------
get_midnight_seconds(Seconds) ->
{{_Year, _Month, _Day}, Time} = seconds_to_localtime(Seconds),
%
Diff = calendar:time_to_seconds(Time),
% 0
Today = Seconds - Diff,
% 0
NextDay = Seconds + (?ONE_DAY_SECONDS - Diff),
{Today, NextDay}.
%%
get_next_day_seconds(Now) ->
{{_Year, _Month, _Day}, Time} = util:seconds_to_localtime(Now),
%
Diff = calendar:time_to_seconds(Time),
Now + (?ONE_DAY_SECONDS - Diff).
%% -----------------------------------------------------------------
%%
%% -----------------------------------------------------------------
get_diff_days(Seconds1, Seconds2) ->
{{Year1, Month1, Day1}, _} = seconds_to_localtime(Seconds1),
{{Year2, Month2, Day2}, _} = seconds_to_localtime(Seconds2),
Days1 = calendar:date_to_gregorian_days(Year1, Month1, Day1),
Days2 = calendar:date_to_gregorian_days(Year2, Month2, Day2),
DiffDays = abs(Days2 - Days1),
DiffDays + 1.
%%
get_today_current_second() ->
{_, Time} = calendar:now_to_local_time(game_timer:now()),
NowSec = calendar:time_to_seconds(Time),
NowSec.
%%
get_date() ->
calendar:day_of_the_week(date()).
%%
get_pre_week_duringtime() ->
OrealTime = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
{Year, Month, Day} = date(),
CurrentTime = calendar:datetime_to_gregorian_seconds({{Year, Month, Day}, {0, 0, 0}}) - OrealTime - 8 * 60 * 60,%%1970
WeekDay = calendar:day_of_the_week(Year, Month, Day),
Day1 =
case WeekDay of %%
1 -> 7;
2 -> 7 + 1;
3 -> 7 + 2;
4 -> 7 + 3;
5 -> 7 + 4;
6 -> 7 + 5;
7 -> 7 + 6
end,
StartTime = CurrentTime - Day1 * 24 * 60 * 60,
EndTime = StartTime + 7 * 24 * 60 * 60,
{StartTime, EndTime}.
%%
get_this_week_duringtime() ->
OrealTime = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
{Year, Month, Day} = date(),
CurrentTime = calendar:datetime_to_gregorian_seconds({{Year, Month, Day}, {0, 0, 0}}) - OrealTime - 8 * 60 * 60,%%1970
WeekDay = calendar:day_of_the_week(Year, Month, Day),
Day1 =
case WeekDay of %%
1 -> 0;
2 -> 1;
3 -> 2;
4 -> 3;
5 -> 4;
6 -> 5;
7 -> 6
end,
StartTime = CurrentTime - Day1 * 24 * 60 * 60,
EndTime = StartTime + 7 * 24 * 60 * 60,
{StartTime, EndTime}.
%%e=2.718281828459L为底的对数
lnx(X) ->
math:log10(X) / math:log10(?E).
check_same_day(Timestamp) ->
NDay = (util:unixtime() + 8 * 3600) div 86400,
ODay = (Timestamp + 8 * 3600) div 86400,
NDay =:= ODay.
%% desc: ()
get_now_to_next_hour() ->
3600 - (1 + (calendar:time_to_seconds(time()) rem 3600)).
%% desc: 1970000
calc_today_0_sec() ->
unixtime() - calendar:time_to_seconds(time()).
%% 1970000
get_seconds_yesterday() ->
LastDayEnd = calc_today_0_sec(),
LastDayBegin = LastDayEnd - 3600 * 24,
{LastDayBegin, LastDayEnd}.
%%list进行去重
%%Replicat 01
%%Sort 01
filter_list(List, Replicat, Sort) ->
if Replicat == 0 andalso Sort == 0 ->
List;
true ->
if Replicat == 1 andalso Sort == 1 ->
lists:usort(List);
true ->
if Sort == 1 ->
lists:sort(List);
true ->
lists:reverse(filter_replicat(List, []))
end
end
end.
%%list去重
filter_replicat([], List) ->
List;
filter_replicat([H | Rest], List) ->
Bool = lists:member(H, List),
List1 =
if Bool == true ->
[[] | List];
true ->
[H | List]
end,
List2 = lists:filter(fun(T) -> T =/= [] end, List1),
filter_replicat(Rest, List2).
%%
between(Item, Min, Max) ->
case Max > Min of
true ->
Item >= Min andalso Item =< Max;
false ->
Item >= Max andalso Item =< Min
end.
%%-----------------------------------------------------
%% @spec ,4
get_screen(X, Y, SolutX, SolutY) ->
{HalfScreenWidth, HalfScreenHeight} =
if
SolutX =/= 0 andalso SolutY =/= 0 ->
{util:ceil(SolutX / 2), util:ceil(SolutY / 2)};
true ->
{util:ceil(?SOLUT_X / 2), util:ceil(?SOLUT_Y / 2)}
end,
{X - HalfScreenWidth, Y - HalfScreenHeight, X + HalfScreenWidth, Y + HalfScreenHeight}.
%% X,Y是否在所在的框里面
is_same_screen(X, Y, {X1, Y1, X2, Y2}) ->
X1 =< X andalso X2 >= X andalso Y1 =< Y andalso Y2 >= Y.
%%
is_same_screen([X1, Y1, X2, Y2], [SolutX, SolutY]) ->
{ScreenWidth, ScreenHeight} =
if
SolutX =/= 0 andalso SolutY =/= 0 ->
{SolutX, SolutY};
true ->
{?SOLUT_X, ?SOLUT_Y}
end,
%% io:format("=====~p:~p~n",[ScreenWidth,ScreenHeight]) ,
SX1 = X1 div ScreenWidth,
SY1 = Y1 div ScreenHeight,
SX2 = X2 div ScreenWidth,
SY2 = Y2 div ScreenHeight,
SX1 == SX2 andalso SY1 == SY2.
%% (?SLICEWIDTH*?SLICEHEIGHT)
%% 1/2
get_matrix(X, Y) ->
X1 = X div ?SLICEWIDTH * ?SLICEWIDTH,
Y1 = Y div ?SLICEHEIGHT * ?SLICEHEIGHT,
{X1 - ?SLICEWIDTH, Y1 - ?SLICEHEIGHT, X1 + ?SLICEWIDTH * 2, Y1 + ?SLICEHEIGHT * 2}.
get_matrix(X, Y, SolutX, SolutY) ->
{SliceWidth, SliceHeight} = get_slice_area(SolutX, SolutY),
X1 = X div SliceWidth * SliceWidth,
Y1 = Y div SliceHeight * SliceHeight,
{X1 - SliceWidth, Y1 - SliceHeight, X1 + SliceWidth * 2, Y1 + SliceHeight * 2}.
%%
get_slice_area(SolutX, SolutY) ->
case SolutX =:= 0 andalso SolutY =:= 0 of
true ->
{?SLICEWIDTH, ?SLICEWIDTH};
false ->
{round(SolutX / 2), round(SolutY / 2)}
end.
%%
get_slice(X, Y) ->
{SliceWidth, SliceHeight} = get_slice_area(0, 0),
X1 = SliceWidth div 2,
Y1 = SliceHeight div 2,
{X - X1, Y - Y1, X + X1, Y + Y1}.
%%
get_slice(X, Y, SolutX, SolutY) ->
{SliceWidth, SliceHeight} = get_slice_area(SolutX, SolutY),
X1 = SliceWidth div 2,
Y1 = SliceHeight div 2,
{X - X1, Y - Y1, X + X1, Y + Y1}.
%% X,Y是否在所在的九宫格边界内
is_in_matrix(X, Y, {X1, Y1, X2, Y2}) ->
if
X1 =< X andalso X2 >= X andalso Y1 =< Y andalso Y2 >= Y ->
true;
true ->
false
end.
%
is_same_slice(X1, Y1, X2, Y2) ->
SX1 = X1 div ?SLICEWIDTH,
SY1 = Y1 div ?SLICEHEIGHT,
SX2 = X2 div ?SLICEWIDTH,
SY2 = Y2 div ?SLICEHEIGHT,
if
SX1 == SX2 andalso SY1 == SY2 ->
true;
true ->
false
end.
is_same_slice(X1, Y1, X2, Y2, SolutX, SolutY) ->
{SliceWidth, SliceHeight} = get_slice_area(SolutX, SolutY),
SX1 = X1 div SliceWidth,
SY1 = Y1 div SliceHeight,
SX2 = X2 div SliceWidth,
SY2 = Y2 div SliceHeight,
if
SX1 == SX2 andalso SY1 == SY2 ->
true;
true ->
false
end.
get_xy_slice(X1, Y1) ->
SX1 = X1 div ?SLICEWIDTH,
SY1 = Y1 div ?SLICEHEIGHT,
{SX1, SY1}.
is_in_range(X1, Y1, X2, Y2, Range) ->
X = abs(X1 - X2),
Y = abs(Y1 - Y2),
X =< Range andalso Y =< Range.
%%@spec 线
distance({X1, Y1}, {X2, Y2}) ->
round(math:sqrt((X2 - X1) * (X2 - X1) + (Y2 - Y1) * (Y2 - Y1))).
%%lists:flodl
make_list(SrcList, Item) when is_integer(SrcList) ->
[Item];
make_list(SrcList, Item) ->
SrcList ++ [Item].
%%{H,M,S}
conver_time(Time) ->
case Time of
{H, M, S} ->
H * 10000 + M * 100 + S;
_ ->
?ERROR_MSG("data parse in conver_time data is ~p ~n", [Time]),
0
end.
check_list(Src) ->
case Src of
0 -> [];
List -> List
end.
getDataFirstTime() ->
NowTime = unixtime(),
{{Year, Month, Day}, {Hour, Min, Second}} = calendar:local_time(),
DataFirstTime = NowTime - (Hour * 3600 + Min * 60 + Second),
DataFirstTime.
%%N进制 ex: v10toVn(999999,36,[])
v10toVn(I0, Base, R0) ->
D = I0 rem Base,
I1 = I0 div Base,
R1 = if D >= 10 ->
[D - 10 + $A | R0];
true ->
[D + $0 | R0]
end,
if I1 =:= 0 ->
R1;
true ->
v10toVn(I1, Base, R1)
end.

+ 51
- 0
src/srvNodeMgr/tools/gameWorld/test/mysql_test.erl Dosyayı Görüntüle

@ -0,0 +1,51 @@
%%%---------------------------------------------
%%% @Module : mysql_test
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description: mysql测试
%%%---------------------------------------------
-module(mysql_test).
-compile(export_all).
-define(DB, mysql_conn_poll).
-define(DB_HOST, "localhost").
-define(DB_PORT, 3386).
-define(DB_USER, "root").
-define(DB_PASS, "root").
-define(DB_NAME, "csj").
-define(DB_ENCODE, utf8).
conn() ->
mysql:start_link(?DB, ?DB_HOST, ?DB_PORT, ?DB_USER, ?DB_PASS, ?DB_NAME, fun(_, _, _, _) -> ok end, ?DB_ENCODE),
mysql:connect(?DB, ?DB_HOST, ?DB_PORT, ?DB_USER, ?DB_PASS, ?DB_NAME, ?DB_ENCODE, true),
% mysql:fetch(?DB, <<"drop table if exists test">>),
% mysql:fetch(?DB, <<"create table test (id int not null auto_increment,row varchar(50) not null,r int not null, primary key (id)) engine = myisam">>),
mysql:fetch(?DB, <<"truncate table test">>),
ok.
test() ->
mysql:fetch(?DB, <<"truncate table test">>),
mysql:fetch(?DB, <<"begin">>),
F = fun() ->
db_sql:execute(io_lib:format(<<"insert into `test` (`row`,`r`) values ('~s',~p)">>, ["我是来测试性能的", 123])),
db_sql:execute(io_lib:format(<<"update `test` set `row` = '~s' where id = ~p">>, ["我是来测试性能的", 1]))
% mysql:fetch(?DB, io_lib:format(<<"insert into `test` (`row`,`r`) values ('~s',~p)">>,["我是来测试性能的",123]))
end,
prof:run(F, 10000),
mysql:fetch(?DB, <<"commit">>),
% mysql:fetch(?DB, <<"begin">>),
%
% F1 = fun() ->
% mysql:fetch(?DB, io_lib:format(<<"update `test` set `row` = '~s' where id = ~p">>,["我是来测试性能的",123]))
% end,
% prof:run(F1, 10000),
% mysql:fetch(?DB, <<"commit">>),
%
% F2 = fun() ->
% mysql:fetch(?DB, <<"select * from `test` where id = 1">>)
% end,
% prof:run(F2, 10000),
ok.

+ 402
- 0
src/srvNodeMgr/tools/gameWorld/test/mysql_to_emongo.erl Dosyayı Görüntüle

@ -0,0 +1,402 @@
%%%--------------------------------------
%%% @Module : mysql_to_emongo
%%% @Author : csj
%%% @Created : 2010.10.20
%%% @Description: mysql->emongo数据库转换处理模块
%%%--------------------------------------
-module(mysql_to_emongo).
-compile([export_all]).
-include("common.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
-define(PoolId, mysql_conn_for_mongodb).
-define(AUTO_IDS, "auto_ids").
%% ,
start_base() ->
start("base_"),
ok.
%% ,
start_all() ->
start(""),
ok.
start_single([Atom]) ->
Prefix = util:term_to_string(Atom),
start(Prefix),
ok.
start_single2([Atom]) ->
Prefix = util:term_to_string(Atom),
start2(Prefix),
ok.
%%,
start_clear() ->
TableList = lib_player_rw:get_all_tables(),
F = fun(TableName) ->
TableName1 = util:term_to_string(TableName),
case TableName1 =/= "cards" andalso TableName1 =/= "sys_acm" andalso string:str(TableName1, "admin") =/= 1
andalso TableName1 =/= "auto_ids" andalso TableName1 =/= "shop" andalso string:str(TableName1, "base") =/= 1 of
false -> skip;
true ->
emongo:delete(tool:to_list(?MASTER_POOLID), TableName1, [])
end
end,
[F(TableName) || TableName <- TableList],
ok.
%%
start(Prefix) ->
case get_mysql_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB_name, Encode] ->
mysql:start_link(?PoolId, Host, Port, User, Password, DB_name, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?PoolId, Host, Port, User, Password, DB_name, Encode, true),
case get_mongo_config(?CONFIG_FILE) of
[MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize] ->
init_mongo([MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize]),
io:format("Mysql~p ==>Mongo ~p~n", [[Host, Port, User, Password, DB_name], [EmongoHost, EmongoPort, EmongoDatabase]]),
io:format("Prefix ==>Mongo ~p~n", [Prefix]),
read_write_tables(DB_name, Prefix),
ok;
_ -> emongo_config_fail
end,
ok;
_ -> mysql_config_fail
end,
halt(),
ok.
%%
start2(Prefix) ->
case get_mysql_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB_name, Encode] ->
mysql:start_link(?PoolId, Host, Port, User, Password, DB_name, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?PoolId, Host, Port, User, Password, DB_name, Encode, true),
case get_mongo_config(?CONFIG_FILE) of
[MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize] ->
init_mongo([MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize]),
io:format("Mysql~p ==>Mongo ~p~n", [[Host, Port, User, Password, DB_name], [EmongoHost, EmongoPort, EmongoDatabase]]),
io:format("Prefix ==>Mongo ~p~n", [Prefix]),
read_write_tables(DB_name, Prefix),
ok;
_ -> emongo_config_fail
end,
ok;
_ -> mysql_config_fail
end,
ok.
get_mysql_config(Config_file) ->
try
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(mysql_config, 1, C),
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode]
catch
_:_ -> no_config
end.
get_mongo_config(Config_file) ->
try
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Emongo_config} = lists:keyfind(emongo_config, 1, C),
{_, MongoPoolId} = lists:keyfind(poolId, 1, Emongo_config),
{_, EmongoHost} = lists:keyfind(emongoHost, 1, Emongo_config),
{_, EmongoPort} = lists:keyfind(emongoPort, 1, Emongo_config),
{_, EmongoDatabase} = lists:keyfind(emongoDatabase, 1, Emongo_config),
{_, EmongoSize} = lists:keyfind(emongoSize, 1, Emongo_config),
[MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize]
catch
_:_ -> no_config
end.
%%emongoDB链接
init_mongo([MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize]) ->
emongo_sup:start_link(),
emongo_app:initialize_pools([MongoPoolId, EmongoHost, EmongoPort, EmongoDatabase, EmongoSize]),
%% emongo:insert(tool:to_list(?MASTER_POOLID),"b",[{id, 111},{name,"111ls"},{age,130}]),
%% Bin1 = emongo:find_one(tool:to_list(?MASTER_POOLID), "player", [{"id", 1424}]),
ok.
%%mysql数据转换为emongo文档对象
%% SELECT column_name,data_type, column_key, extra FROM information_schema.columns WHERE table_schema='csj_dev' and table_name='adminkind'
read_write_tables(DB_name, Prefix) ->
timer:sleep(5 * 1000),
if Prefix =:= "" ->
emongo:delete(tool:to_list(?MASTER_POOLID), ?AUTO_IDS, []);
true ->
no_action
end,
Sql = "SELECT table_name FROM information_schema.tables WHERE table_schema='" ++ DB_name ++ "' and table_type ='BASE TABLE'",
emongo:ensure_index(tool:to_list(?MASTER_POOLID), "auto_ids", [{<<"id">>, 1}]),
emongo:ensure_index(tool:to_list(?MASTER_POOLID), "auto_ids", [{<<"name">>, 1}]),
Data = mysql:fetch(?PoolId, list_to_binary(Sql)),
R = handleResult(Data),%%R is [[<<"adminchange">>],[<<"admingroup">>],[<<"adminkind">>]]
F = fun(D) ->
[R1] = D, %%R1 is <<"adminchange">>
Index = string:str(binary_to_list(R1), Prefix),
if Prefix =:= "" orelse Index =:= 1 orelse
((Prefix =:= "" orelse Prefix =:= "base_") andalso R1 =:= <<"shop">>)
orelse R1 =:= <<"adminkind">> ->
Sql1 = "SELECT column_name,data_type,column_key,extra FROM information_schema.columns WHERE table_schema= '" ++ DB_name ++ "' AND table_name= '" ++ binary_to_list(R1) ++ "'",
Sql2 = "SELECT * FROM " ++ binary_to_list(R1),
Result1 = mysql:fetch(?PoolId, list_to_binary(Sql1)),
Result2 = mysql:fetch(?PoolId, list_to_binary(Sql2)),
ColumnAndType = handleResult(Result1),%%ColumnAndType is [[<<"id">>,<<"int">>],[<<"name">>,<<"varchar">>],[<<"pid">>,<<"varchar">>],[<<"url">>,<<"varchar">>]],
TableRecord = handleResult(Result2),
records_to_documents(DB_name, binary_to_list(R1), ColumnAndType, TableRecord),
if R1 =:= <<"adminkind">> ->
%%
emongo:update(tool:to_list(?MASTER_POOLID), <<"adminkind">>,
[{<<"name">>, <<"资源管理">>}], [{"$set", [{<<"show">>, <<"NO">>}]}]),
ok;
true -> no_action
end;
true -> skip
end
end,
[F(D) || D <- R],
%%base数据时同步更新其它非base表的索引
if Prefix =:= "base_" ->
add_other_table_index(DB_name, R);
true ->
skip
end,
ok.
%%start_base时将其它非base表的索引也同步过来,base表已在前面同步过
%%R is [[<<"adminchange">>],[<<"admingroup">>],[<<"adminkind">>]]
add_other_table_index(DB_name, R) ->
F = fun(D) ->
[R1] = D, %%R1 is <<"adminchange">>
binary_to_list(R1)%%R1 is "adminchange"
end,
TableList = [F(D) || D <- R],
OtherTables = [T || T <- TableList, string:str(T, "base") =/= 1],%%base开头的表
F1 = fun(TableName) ->
Sql1 = "SELECT column_name,data_type,column_key,extra FROM information_schema.columns WHERE table_schema= '" ++ DB_name ++ "' AND table_name= '" ++ TableName ++ "'",
Result1 = mysql:fetch(?PoolId, list_to_binary(Sql1)),
ColumnAndType = handleResult(Result1),%%ColumnAndType is [[<<"id">>,<<"int">>],[<<"name">>,<<"varchar">>],[<<"pid">>,<<"varchar">>],[<<"url">>,<<"varchar">>]],
KeyList = [Key || [_Name, _Type, Key, _Extra] <- ColumnAndType, Key =:= <<"UNI">> orelse Key =:= <<"MUL">> orelse Key =:= <<"PRI">>],
case length(KeyList) of
0 ->
io:format("~s Warning...No Key Table: [~p]\n", [misc:time_format(now()), TableName]);
_ ->
skip
end,
%%
lists:foreach(fun(FieldAndType) ->
[Name, _Type, Key, Extra] = FieldAndType,
if Key =:= <<"PRI">>, Extra =:= <<"auto_increment">> ->
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, [{Name, 1}]);
Key =:= <<"UNI">> orelse Key =:= <<"MUL">> orelse Key =:= <<"PRI">> ->
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, [{Name, 1}]);
true ->
ok
end
end,
ColumnAndType),
%%
IndexSql = "SELECT column_name FROM information_schema.columns WHERE table_schema= '" ++ DB_name ++ "' AND table_name= '" ++ (TableName) ++ "' AND column_key ='MUL'",
IndexResult = handleResult(mysql:fetch(?PoolId, list_to_binary(IndexSql))),
case IndexResult of
[] -> skip;
_ ->
IndexResultSize = length(IndexResult),
F3 = fun(II) ->
[RR] = lists:nth(II, IndexResult),
{binary_to_list(RR), 1}
end,
LL = [F3(II) || II <- lists:seq(1, IndexResultSize)],
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, LL)
end
end,
[F1(Table) || Table <- OtherTables],
ok.
%%["a"] -> "a"
term_to_string(Term) ->
binary_to_list(list_to_binary(io_lib:format("~p", [Term]))).
string_to_term(String) ->
case erl_scan:string(String ++ ".") of
{ok, Tokens, _} ->
case erl_parse:parse_term(Tokens) of
{ok, Term} -> Term;
_Err -> undefined
end;
_Error ->
undefined
end.
%%mysql记录转换为emongo的document
%%TableName like "test"
%%ColumnAndType like [[<<"id">>,<<"int">>],
%% [<<"row">>,<<"varchar">>],
%% [<<"r">>,<<"int">>]]
%%TableRecord like [[1,111111,<<"111111">>],
%% [2,9898,<<"9898bf">>]]
records_to_documents(DB_name, TableName, ColumnAndType, TableRecord) ->
ErrList = [Head || [Head | Tail] <- TableRecord, len_chk([Head | Tail]) =/= true],
if
length(ErrList) > 0 andalso TableName =/= "base_talk" ->
io:format("Waring for length!!!!! Table Name ~p.....Head:~p....... ~n", [TableName, ErrList]);
true ->
skip
end,
case length(TableRecord) of
0 ->
H0 = lists:map(fun(FieldAndType) ->
[Name, _, _, _] = FieldAndType,
{tool:to_atom(Name), 0}
end,
ColumnAndType),
EmptyCollection = true,
H = [H0];
_ ->
EmptyCollection = false,
F = fun(R) ->
CtList = mergeList(ColumnAndType),
ColumnSize = length(CtList),
[{lists:nth(I, CtList), lists:nth(I, R)} || I <- lists:seq(1, ColumnSize)]
end,
H = [F(Record) || Record <- TableRecord] %% H like [[{<<"id">>,1},{<<"name">>,<<"zs">>}],[[{<<"id">>,2},{<<"name">>,<<"ls">>}]]
end,
%%cards表及管理员表
case TableName =/= "cards"
andalso TableName =/= "base_com_gift" %%
%% start_all sys_acm表
%% andalso TableName =/= "sys_acm"
andalso string:str(TableName, "admin") =/= 1 of
false -> skip;
true ->
emongo:delete(tool:to_list(?MASTER_POOLID), TableName, []),
Mysql_count = length(TableRecord),
io:format("handle: ~p ...", [TableName]),
insert_to_emongo(TableName, H),
case EmptyCollection of
true -> emongo:delete(tool:to_list(?MASTER_POOLID), TableName, []);
false -> no_action
end,
KeyList = [Key || [_Name, _Type, Key, _Extra] <- ColumnAndType, Key =:= <<"UNI">> orelse Key =:= <<"MUL">> orelse Key =:= <<"PRI">>],
case length(KeyList) of
0 ->
io:format("\n ############## Warning...No Key Table: [~p] #################\n", [TableName]);
_ ->
skip
end,
%%
lists:foreach(fun(FieldAndType) ->
[Name, _Type, Key, Extra] = FieldAndType,
if Key =:= <<"PRI">>, Extra =:= <<"auto_increment">> ->
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, [{Name, 1}]),
create_max_id(TableName, Name);
Key =:= <<"UNI">> orelse Key =:= <<"MUL">> orelse Key =:= <<"PRI">> ->
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, [{Name, 1}]);
true ->
ok
end
end,
ColumnAndType),
%%
IndexSql = "SELECT column_name FROM information_schema.columns WHERE table_schema= '" ++ DB_name ++ "' AND table_name= '" ++ (TableName) ++ "' AND column_key ='MUL'",
IndexResult = handleResult(mysql:fetch(?PoolId, list_to_binary(IndexSql))),
case IndexResult of
[] -> skip;
_ ->
IndexResultSize = length(IndexResult),
F3 = fun(II) ->
[RR] = lists:nth(II, IndexResult),
{binary_to_list(RR), 1}
end,
LL = [F3(II) || II <- lists:seq(1, IndexResultSize)],
emongo:ensure_index(tool:to_list(?MASTER_POOLID), TableName, LL)
end,
Mongo_count =
case emongo:count(tool:to_list(?MASTER_POOLID), tool:to_list(TableName), []) of
undefined -> 0;
Val -> Val
end,
if Mysql_count =:= Mongo_count ->
io:format(" [~p]==>[~p] finished! ~n", [Mysql_count, Mongo_count]);
true ->
io:format(" [~p]==>[~p] ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!! ~n", [Mysql_count, Mongo_count])
end
end,
ok.
%%mysql:fetch(?DB,Bin)[[A]],
handleResult(Data) ->
{_, Bin} = Data,
{_, _, R, _, _} = Bin, %%R is [[<<"adminchange">>],[<<"admingroup">>],[<<"adminkind">>]]
R.
%%[[<<"id">>,<<"int">>],[[<<"name">>,<<"varchar">>],<<"age">>,<<"int">>]] -> [<<"id">>,<<"name">>,<<"age">>]
mergeList(List) ->
F = fun(L1) ->
[Name, _Type, _Key, _Extra] = L1,
Name
end,
[F(L) || L <- List].
%%
insert_to_emongo(TableName, H) ->
%% emongo:insert(tool:to_list(?MASTER_POOLID),"b",[{id, 111},{name,"111ls"},{age,130}]),
F = fun(R) ->
%% io:format("R is ~p~n",[R]),
emongo:insert(tool:to_list(?MASTER_POOLID), TableName, R)
end,
[F(R) || R <- H],
ok.
%% id
create_max_id(TableName, Name) ->
try
%% io:format("create_max_id_0_~p~n",[[TableName, Name]]),
Sql = "select max(" ++ tool:to_list(Name) ++ ") from " ++ tool:to_list(TableName),
%% io:format("create_max_id_1_~p~n",[Sql]),
Result = mysql:fetch(?PoolId, list_to_binary(Sql)),
[[MaxId]] = handleResult(Result),
%% io:format("create_max_id_1_~p~n",[MaxId]),
MaxId_1 =
case MaxId of
null -> 0;
undefined -> 0;
_ -> MaxId
end,
%% io:format("create_max_id_2_~p~n",[[TableName, Name, MaxId]]),
emongo:delete(tool:to_list(?MASTER_POOLID), ?AUTO_IDS, [{name, TableName}]),
emongo:insert(tool:to_list(?MASTER_POOLID), ?AUTO_IDS, [{name, TableName}, {Name, MaxId_1}])
catch
_:_ -> error
end,
ok.
%%mysql字段长度检测
len_chk([]) ->
true;
len_chk(ChkList) ->
[H | T] = ChkList,
Length = length(tool:to_list(H)),
if
Length > 250 ->
%% io:format("len_chk_2_~p~n",[Length]),
false;
true ->
len_chk(T)
end.

+ 54
- 0
src/srvNodeMgr/tools/gameWorld/test/performance/cast_and_call.erl Dosyayı Görüntüle

@ -0,0 +1,54 @@
%%%---------------------------------------------
%%% @module : cast_and_call
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @description: gen_server cast and call
%%% @resultcast call 0.006
%%%---------------------------------------------
-module(cast_and_call).
-behaviour(gen_server).
%%Interface functions.
-export([start/0, test/0]).
%%gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start() ->
gen_server:start(?MODULE, [], []).
init([]) ->
{ok, 1}.
handle_cast('TEST', Status) ->
%%io:format("This is cast. ~n"),
{noreply, Status}.
handle_call('TEST', _FROM, Status) ->
%%io:format("This is call. ~n"),
{reply, ok, Status}.
handle_info(_Info, Status) ->
{noreply, Status}.
terminate(normal, Status) ->
{ok, Status}.
code_change(_OldVsn, Status, _Extra) ->
{ok, Status}.
test() ->
{ok, Pid} = start(),
fprof:apply(gen_server, call, [Pid, 'TEST']),
fprof:profile(),
fprof:analyse({dest, "call.analysis"}),
fprof:apply(gen_server, cast, [Pid, 'TEST']),
fprof:profile(),
fprof:analyse({dest, "cast.analysis"}),
F1 = fun() -> gen_server:call(Pid, 'TEST') end,
F2 = fun() -> gen_server:cast(Pid, 'TEST') end,
prof:run(F1, 100000),
prof:run(F2, 100000).

+ 34
- 0
src/srvNodeMgr/tools/gameWorld/test/performance/loop.erl Dosyayı Görüntüle

@ -0,0 +1,34 @@
%%%---------------------------------------------
%%% @Module : loop
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description:
%%% @Resule : F2 F1 20 10000
%%%---------------------------------------------
-module(loop).
-compile(export_all).
do_loop([], _Data) -> ok;
do_loop([[_S] | T], Data) ->
do_loop(T, Data).
do_loop2([], _Data, _X) -> ok;
do_loop2([[S] | T], Data, X) when S == X ->
do_loop2(T, Data, X);
do_loop2([[_S] | T], Data, X) ->
do_loop2(T, Data, X).
test() ->
F1 = fun() ->
L = [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]],
do_loop2(L, <<16:16>>, [8])
end,
F2 = fun() ->
L = [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]],
do_loop(lists:delete([8], L), <<16:16>>)
end,
prof:run(F1, 100000),
prof:run(F2, 100000).

+ 25
- 0
src/srvNodeMgr/tools/gameWorld/test/performance/prof.erl Dosyayı Görüntüle

@ -0,0 +1,25 @@
%%%---------------------------------------------
%%% @Module : prof
%%% @Author : csj
%%% @Created : 2010.10.05
%%% @Description:
%%%---------------------------------------------
-module(prof).
-compile(export_all).
%%
%%Fun:
%%Loop:
run(Fun, Loop) ->
statistics(wall_clock),
for(1, Loop, Fun),
{_, T1} = statistics(wall_clock),
io:format("~p loops, using time: ~pms~n", [Loop, T1]),
ok.
for(Max, Max, Fun) ->
Fun();
for(I, Max, Fun) ->
Fun(), for(I + 1, Max, Fun).

+ 160
- 0
src/srvNodeMgr/tools/gameWorld/test/random_test.erl Dosyayı Görüntüle

@ -0,0 +1,160 @@
%% Author: Administrator
%% Created: 2011-11-1
%% Description: TODO: Add description to random_test
-module(random_test).
%%
%% Include files
%%
-include("common.hrl").
-include("record.hrl").
%%
%% Exported Functions
%%
-compile(export_all).
%%
%% API Functions
%%
random_test() ->
?DEBUG("Start ~p", [[0]]),
random_test_loop(1000000),
?DEBUG("Finish ~p", [[0]]).
random_test_loop(T) ->
case T < 1 of
true ->
[];
_ ->
R = util:rand(1, 10000),
io:format("~p\n", [R]),
random_test_loop(T - 1)
end.
%% acid_to_player() ->
%% PlayerDB = ?DB_MODULE:select_all(player, "*", []),
%% F = fun(CD) ->
%% Cin = list_to_tuple([player | CD]),
%% case Cin#player.acid of
%% 0 ->
%% case ?DB_MODULE:select_row(user,"*",[{acnm,Cin#player.acnm}]) of
%% [] ->
%% ACId = ?DB_MODULE:insert(user, [acid,acnm,state,idcrs,sn], [0,Cin#player.acnm,0,0,0]),
%% ?DB_MODULE:update(user, [{acid,ACId}], [{id,ACId}]);
%% D ->
%% [ACId,_acid,_acnm,_st,_idc,_sn] = D
%% end,
%% ?DB_MODULE:update(player,[{acid, ACId}],[{id, Cin#player.id}]);
%% _ ->
%% []
%% end
%% end,
%% lists:foreach(F, PlayerDB).
online_clear() ->
PlayerDB = ?DB_MODULE:select_all(player, "*", [{olflg, 1}]),
%% Ftime = util:unixtime(),
%% ?DEBUG("Start ~p",[Ftime]),
%% PlayerDB = ?DB_MODULE:select_all(player, "*", []),
F = fun(CD) ->
Cin = list_to_tuple([player | CD]),
case lib_player:is_online(Cin#player.id) of
true ->
[];
_ ->
?DB_MODULE:update(player, [{olflg, 0}], [{id, Cin#player.id}])
end
end,
lists:foreach(F, PlayerDB).
%% Etime = util:unixtime(),
%% ?DEBUG("End ~p",[Etime]).
idcrs_clear() ->
UsrDB = ?DB_MODULE:select_all(user, "*", []),
F = fun(CD) ->
[Id, _ACId, _Acnm, _St, _Id, _sn] = CD,
?DB_MODULE:update(user, [{idcrs, 0}], [{id, Id}])
end,
lists:foreach(F, UsrDB).
%% relationship2relaTrans() ->
%% Relationship = ?DB_MODULE:select_all(relationship, "*", [{rela,0}]),
%% F = fun(CD) ->
%% [Id,IDA,IDB,Re,Al,Bsex,Bnick,Bcar,Bg,Bj,Asex,Anick,Acar,Ag,Aj] = CD,
%% RD = db_agent_rela:insert_rela(IDA,0,Anick,Asex,Acar,0,"",1),
%% Cin = list_to_tuple([ets_rela | RD]),
%% NFR = {IDB,Bnick,Bsex,Bcar,0,[]},
%% NFRALL = [NFR|Cin#ets_rela.frid],
%% NCin = Cin#ets_rela{frid = NFRALL,fn = Cin#ets_rela.fn+1},
%% db_agent_rela:update_rela_by_uid(NCin)
%% end,
%% lists:foreach(F, Relationship).
fore_test() ->
lists:foreach(fun(D) ->
io:format(" ~p ", [D])
end, [1, 2, 3, 4]).
log_player() ->
D = ?DB_MODULE:select_all(player, "id,acid,acnm,nick,sex,crr", []),
%% ?DEBUG("~p",[D]),
F = fun(CD) ->
[Uid, Acid, Acnm, Nick, Sex, Crr] = CD,
?DB_LOG_MODULE:insert(log_player, [uid, acid, acnm, nick, sex, crr], [Uid, Acid, Acnm, Nick, Sex, Crr])
end,
lists:foreach(F, D).
lists_find() ->
Lis = data_name_list:get_list(),
Start = util:unixtime(),
io:format("Start Time ~p~n", [Start]),
find_test(Lis, 100000),
End = util:unixtime(),
io:format("End Time ~p~n", [End]).
find_test(Lis, Num) ->
if Num < 1 ->
ok;
true ->
FindNum = 100001 + random:uniform(1000),
lists:keyfind(FindNum, 1, Lis),
find_test(Lis, Num - 1)
end.
get_player(Lv) ->
D = ?DB_MODULE:select_all(player, "acnm,lv", [{lv, ">=", Lv}]),
%% ?DEBUG("~p",[D]).
F = fun(CD) ->
[Acnm, NLv] = CD,
Acm = util:string_to_term(tool:to_list(Acnm)),
{Acm, NLv}
%% ?DB_LOG_MODULE:insert(log_player,[uid,acid,acnm,nick], [Uid,Acid,Acnm,Nick])
end,
Res = lists:map(F, D),
Start = util:unixtime(),
FileName = io_lib:format("./~p.txt", [Start]),
{ok, FileIo} = file:open(FileName, [write]),
File = io_lib:format("~p", [Res]),
file:write(FileIo, File),
file:close(FileIo).

+ 49
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/chat_script.erl Dosyayı Görüntüle

@ -0,0 +1,49 @@
%% @author Administrator
%% @doc @todo Add description to chat_script.
-module(chat_script).
-define(HEADER_LENGTH, 4). %
%% ====================================================================
%% API functions
%% ====================================================================
-compile(export_all).
call(11010, {Content}, Sokcet) ->
Len1 = byte_size(Content),
Data = <<Len1:16, Content/binary>>,
gen_tcp:send(Sokcet, pack(11010, Data));
call(11070, {Id, Content}, Sokcet) ->
Len1 = byte_size(Content),
Data = <<Id:32, Len1:16, Content/binary>>,
gen_tcp:send(Sokcet, pack(11070, Data)).
%% <<Id:32, Len:16, Nick1/binary, Len1:16, Bin1/binary>>
handle_socket(11010, BinData) ->
io:format("rec package ~p~n", [11010]),
<<Id:32, Len1:16, Rest1/binary>> = BinData,
<<Nick:Len1/binary-unit:8, Len2:16, Rest2/binary>> = Rest1,
<<Content:Len2/binary-unit:8>> = Rest2,
Nick1 = binary_to_list(Nick),
Content1 = binary_to_list(Content),
io:format(" nick name ~p , content ~p~n", [Nick1, Content1]),
BinData;
handle_socket(11070, BinData) ->
io:format("rec package ~p~n", [11070]),
<<Id:32, Len1:16, Rest1/binary>> = BinData,
<<Nick:Len1/binary-unit:8, Len2:16, Rest2/binary>> = Rest1,
<<Content:Len2/binary-unit:8>> = Rest2,
Nick1 = binary_to_list(Nick),
Content1 = binary_to_list(Content),
io:format(" nick name ~p , content ~p~n", [Nick1, Content1]),
BinData;
handle_socket(_, _) ->
void.
%% ====================================================================
%% Internal functions
%% ====================================================================
%%
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 84
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/mail_script.erl Dosyayı Görüntüle

@ -0,0 +1,84 @@
%% @author Johanthe_Yip
%% @doc ,
%%
-module(mail_script).
%% ====================================================================
%% API functions
%% ====================================================================
-compile(export_all).
-define(HEADER_LENGTH, 4). %
%%----------- 1900x c_2_s ------------
%%=======================
call(19004, {Mail_type, Mail_page}, Sokcet) ->
gen_tcp:send(Sokcet, pack(19004, <<Mail_type:8, Mail_page:8>>));
%%====================
call(19006, {Mail_id}, Sokcet) ->
gen_tcp:send(Sokcet, pack(19006, <<Mail_id:32>>));
%%----------- 190x c_2_s---------------
%%===================
call(19051, {Page_index}, Sokcet) ->
gen_tcp:send(Sokcet, pack(19051, <<Page_index:16>>)).
%%----------- 1900x s_2_c ------------
%%=======================
handle_socket(19004, BinData) ->
<<Result:8, Rest/binary>> = BinData,
if Result =/= 0 ->
<<Mail_num:8, Mail_page:8, MailNum:16, BinList/binary>> = Rest,
io:format("rec package ~p~n", [19004]),
{Maillist, _} = get_list([], BinList, MailNum),
io:format("package info: ~p~n", [Maillist]);
true ->
io:format("rec package but no data ~p ~n", [19004]) end,
BinData;
%%====================
handle_socket(19006, BinData) ->
io:format("rec package ~p~n", [19006]),
<<Result:16, MailId:32>> = BinData,
io:format("package info Result:~p MailId:~p~n", [Result, MailId]);
%%----------- 190x s_2_c---------------
%%===================
handle_socket(19051, BinData) ->
io:format("rec package ~p~n", [19051]),
BinData;
handle_socket(_, _) ->
void.
%% [Id, Type,State, Timestamp, SName, Uid,Title, Content,Goods_list,Coin,Gold]
%% <<Id:32, Type:8, State:8, Timestamp:32, Len1:16, SName/binary, Len2:16, Title/binary, Len3:16, Content/binary, GLen:16, GoodsBin/binary, Gold:32, Coin:32>>
%% AccList 使[]
get_list(AccList, Bin, N) when N > 0 ->
case Bin of
<<Id:32, Type:8, State:8, Timestamp:32, Len1:16, Rest/binary>> ->
<<SName:Len1/binary-unit:8, Len2:16, Rest2/binary>> = Rest,
<<Title:Len2/binary-unit:8, Len3:16, Rest3/binary>> = Rest2,
<<Content:Len3/binary-unit:8, Len4:16, Rest4/binary>> = Rest3,
<<GoodsBin:Len4/binary-unit:8, Gold:32, Coin:32, Rest5/binary>> = Rest4,
SName1 = binary_to_list(SName),
Title1 = binary_to_list(Title),
Content1 = binary_to_list(Content),
GoodsBin1 = binary_to_list(GoodsBin),
Item = [Id, Type, State, Timestamp, SName, Title, Content, GoodsBin, Coin, Gold],
%io:format("Item: ~p~n", [Item]),
NewList = [Item | AccList],
get_list(NewList, Rest5, N - 1);
_R1 ->
error
end;
get_list(AccList, Bin, _) ->
{lists:reverse(AccList), Bin}.
%%
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 850
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/new_robot.erl Dosyayı Görüntüle

@ -0,0 +1,850 @@
%%% -------------------------------------------------------------------
%%% @Author : Johanathe_Yip
%%% @Created : 2013.01.13
%%% -------------------------------------------------------------------
-module(new_robot).
-behaviour(gen_server).
-compile(export_all).
-include("common.hrl").
-include("record.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
%% gateway配置
-define(GATEWAY_ADD, "127.0.0.1").
%% -define(GATEWAY_ADD,"192.168.51.131").
-define(GATEWAY_PORT, 7777).
-define(ACTION_SPEED_CONTROL, 10).
-define(ACTION_INTERVAL, ?ACTION_SPEED_CONTROL * 1000). %
-define(ACTION_MIN, 3000). %
-define(TCP_OPTS, [
binary,
{packet, 0}, % no packaging
{reuseaddr, true}, % allow rebind without waiting
{nodelay, false},
{delay_send, true},
{active, false},
{exit_on_close, false}
]).
-define(ETS_ROBOT, ets_robot).
-define(CHECK_ROBOT_STATUS, 1 * 60 * 1000).
%% -define(debug,1).
%%
-ifdef(debug).
-define(TRACE(Str), io:format(Str)).
-define(TRACE(Str, Args), io:format(Str, Args)).
% unicode版
-define(TRACE_W(Str), io:format("~ts", [list_to_binary(io_lib:format(Str, []))])).
-define(TRACE_W(Str, Args), io:format("~ts", [list_to_binary(io_lib:format(Str, Args))])).
-else.
-define(TRACE(Str), void).
-define(TRACE(Str, Args), void).
-define(TRACE_W(Str), void).
-define(TRACE_W(Str, Args), void).
-endif.
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(robot, {
orig_n,
login,
acid, %%account id
socket, %%socket
socket2,
socket3,
pid, %%process id
x, %%x坐标
y, %%y坐标
scene,
tox,
toy,
hp,
id, %% id
act, %%
status, %%
dstScene,
step,
frda, %%
bkda, %% ,
sgda %%
}).
%%%
%%% API
start() ->
start(30000, 1),
ok.
%%StartId AccountID
%%Num int
%%Mod 1 ,2
start(StartId, Num) ->
sleep(100),
F = fun(N) ->
?TRACE("start robot-~p~n", [N]),
sleep(100),
?MODULE:start_link(StartId + N)
end,
for(0, Num, F),
ok.
%% ROBOT
start_link(N) ->
case gen_server:start(?MODULE, [N], []) of
{ok, _Pid} ->
?TRACE("--robot~p start finish!-~n", [N]);
%gen_server:cast(Pid, {start_action});
_ ->
fail
end.
%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% --------------------------------------------------------------------
%%
init([N]) ->
process_flag(trap_exit, true),
Pid = self(),
case login(N, Pid) of
{ok, Socket} ->
Scene = 10101,
Robot = #robot{socket = Socket,
login = 0,
acid = N,
id = 0,
pid = Pid,
act = none,
status = none,
scene = Scene,
dstScene = Scene,
tox = rand(1, 40),
toy = rand(1, 20),
orig_n = N,
step = 0,
frda = [], %%
bkda = [], %% ,
sgda = []%%
},
%%
%% %%
%% mail_script:call(19004,{1,1},Socket),
%%
%% mail_script:call(19006,{1},Socket),
%% chat_script:call(11010,{<<"11">>},Socket),
%% chat_script:call(11070,{1,<<"11">>},Socket),
%% task_script:call(30003,1,Socket),
%% task_script:call(30003,2,Socket),
{ok, Robot};
_Error ->
?TRACE("init: error, reason: ~p~n", [_Error]),
{stop, normal, {}}
end.
%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call({act}, _From, State) ->
%%act有跑步run或者静止undefined
handle(State#robot.act, a, State#robot.socket),
{reply, ok, State};
handle_call({get_state}, _From, State) ->
{reply, State, State};
handle_call({get_socket}, _From, State) ->
Reply = State#robot.socket,
{reply, Reply, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast({login_ok, _Code}, State) ->
?TRACE("login successful~n"),
NewState = State#robot{login = 1},
{noreply, NewState};
handle_cast(login_failed, State) ->
?TRACE("login failed~n"),
{stop, normal, State};
handle_cast({playerid, Id}, State) ->
NewState = State#robot{id = Id},
{noreply, NewState};
handle_cast(enter_ok, State) ->
NewState = State#robot{act = run, status = standing},
gen_server:cast(self(), {start_action}),
{noreply, NewState};
handle_cast({start_action}, State) ->
if is_port(State#robot.socket) ->
%%
spawn_link(fun() -> handle(heart, a, State#robot.socket) end),
%%Pid= self(),
%%
handle(get_self_info, 0, State#robot.socket),
%handle(chat,"-加经验 1000000",State#robot.socket),
%handle(chat,"-全功能",State#robot.socket),
{noreply, State};
true ->
?TRACE("start_action stop_1: /~p/,~n", [State]),
{stop, normal, State}
end;
handle_cast({add_child_socket, N, Socket}, State) ->
NewState =
if
is_pid(State#robot.pid) andalso is_port(Socket) ->
case N of
2 -> State#robot{socket2 = Socket};
3 -> State#robot{socket3 = Socket};
_ -> State
end;
true ->
?TRACE(" start_child_socket err : /~p/,~n", [State]),
State
end,
{noreply, NewState};
handle_cast({upgrade_state, NewState}, _State) ->
{noreply, NewState};
handle_cast({get_state_13001}, State) ->
handle(get_self_info, a, State#robot.socket),
{noreply, State};
handle_cast({upgrade_state_13001, [Scene, X, Y, Hp]}, State) ->
NewState = State#robot{x = X, y = Y, hp = Hp, scene = Scene},
{noreply, NewState};
handle_cast({upgrade_state_13099, [IdLists]}, State) ->
IdLists1 = [[State#robot.id] | IdLists],
NewState = State#robot{frda = IdLists1},
{noreply, NewState};
handle_cast({run}, State) ->
State2 = State#robot{act = run},
{noreply, State2};
handle_cast({stop}, State) ->
State2 = State#robot{act = undefined},
{noreply, State2};
handle_cast({stop, Reason}, State) ->
?TRACE("~s_quit_2: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, Reason]),
{stop, normal, State};
handle_cast(_Msg, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info({stop, Reason}, State) ->
?TRACE("~s ------ robot stop: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, Reason]),
{stop, normal, State};
handle_info({event, action_random, PlayerId, Socket}, State) ->
Random_interval = random:uniform(?ACTION_INTERVAL * 2) + ?ACTION_MIN * 6,
%% ?TRACE("~s_action_random: ~p~n", [misc:time_format(now()), Random_interval]),
handle_action_random(PlayerId, Socket),
%%
NewState = handle_action_friend(State),
erlang:send_after(Random_interval, self(), {event, action_random, PlayerId, Socket}),
{noreply, NewState};
handle_info(close, State) ->
gen_tcp:close(State#robot.socket),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(Reason, State) ->
?TRACE(" ----------terminate-----------~s_quit_4: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, Reason]),
if is_port(State#robot.socket) ->
gen_tcp:close(State#robot.socket);
true -> no_socket
end,
ok.
%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%=========================================================================
%%
%%=========================================================================
%%
login(N, Pid) ->
case get_game_server() of
{Ip, Port} ->
case connect_server(Ip, Port) of
{ok, Socket} ->
?TRACE("~s ---connect to IP:~p Port: ~p ok...~n", [misc:time_format(now()), Ip, Port]),
Accid = N,
AccName = "Guest" ++ integer_to_list(Accid),
handle(login, {Accid, AccName}, Socket),
spawn_link(fun() -> do_parse_packet(Socket, Pid) end),
{ok, Socket};
_Reason2 ->
?TRACE("Connect to server failed: ~p~n", [_Reason2]),
error
end;
_Reason1 ->
?TRACE("get server failed: ~p~n", [_Reason1]),
error_110
end.
%%
get_gateway_config(Config_file) ->
try
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(tcp_listener, 1, C),
{_, Ip} = lists:keyfind(ip, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
[Ip, Port]
catch
_:_ -> [?GATEWAY_ADD, ?GATEWAY_PORT]
end.
%%
get_game_server() ->
[Gateway_Ip, Gateway_Port] = [?GATEWAY_ADD, ?GATEWAY_PORT],
case gen_tcp:connect(Gateway_Ip, Gateway_Port, ?TCP_OPTS, 10000) of
{ok, Socket} ->
?TRACE("get_game_server connected to gateway: Ip:~p, Port: ~p ~n", [Gateway_Ip, Gateway_Port]),
Data = pack(60000, <<>>),
gen_tcp:send(Socket, Data),
try
case gen_tcp:recv(Socket, ?HEADER_LENGTH) of
{ok, <<Len:16, 60000:16>>} ->
BodyLen = Len - ?HEADER_LENGTH,
case gen_tcp:recv(Socket, BodyLen, 3000) of
{ok, <<Bin/binary>>} ->
<<Rlen:16, RB/binary>> = Bin,
case Rlen of
1 ->
<<Bin1/binary>> = RB,
{IP, Bin2} = pt:read_string(Bin1),
<<Port:16, _Num:8>> = Bin2,
?TRACE("get_game_server IP, Port: /~p/~p/~n", [IP, Port]),
{IP, Port};
_Len ->
?TRACE("recv 60000: Unknown Len: ~p~n", [_Len]),
no_gameserver
end;
_Reason1 ->
gen_tcp:close(Socket),
?TRACE("error when recv 60000: Reason:~p ~n", [_Reason1]),
error_10
end;
{error, _Reason2} ->
?TRACE("get_game_server error:~p/~n", [_Reason2]),
gen_tcp:close(Socket),
error_20
end
catch
_:_ -> gen_tcp:close(Socket),
error_30
end;
{error, _Reason3} ->
?TRACE("get_game_server--------------error:~p/~n", [_Reason3]),
error_40
end.
%%
connect_server(Ip, Port) ->
gen_tcp:connect(Ip, Port, ?TCP_OPTS, 10000).
%%
async_recv(Sock, Length, Timeout) when is_port(Sock) ->
case prim_inet:async_recv(Sock, Length, Timeout) of
{error, Reason} -> throw({Reason});
{ok, Res} -> Res;
Res -> Res
end.
%% -
%%Socketsocket id
%%Client: client记录
do_parse_packet(Socket, Pid) ->
Ref = async_recv(Socket, ?HEADER_LENGTH, ?HEART_TIMEOUT),
receive
{inet_async, Socket, Ref, {ok, <<Len:16, Cmd:16>>}} ->
?TRACE("receive command: ~p, length: ~p", [Cmd, Len]),
BodyLen = Len - ?HEADER_LENGTH,
RecvData =
case BodyLen > 0 of
true ->
Ref1 = async_recv(Socket, BodyLen, ?TCP_TIMEOUT),
receive
{inet_async, Socket, Ref1, {ok, Binary}} ->
?TRACE("Data: ~p~n", [Binary]),
{ok, Binary};
Other ->
?TRACE("Data recv Error: ~p~n", [Other]),
{fail, Other}
end;
false ->
{ok, <<>>}
end,
case RecvData of
{ok, BinData} ->
case Cmd of
10000 ->
<<Code:8, _Bin1/binary>> = BinData,
case Code of
0 ->
gen_server:cast(Pid, {login_ok, 0}),
<<_:32, PlayerId:64, _Bin2/binary>> = _Bin1,
handle(enter_player, {PlayerId}, Socket),
ok;
1 ->
<<Accid:32, _Bin2/binary>> = _Bin1,
gen_server:cast(Pid, {login_ok, 1}),
handle(select_role, Accid, Socket),
ok;
_ ->
gen_server:cast(Pid, login_failed),
?TRACE("login failed: Code: ~p~n", [Code]),
failed
end;
10003 ->
<<Code:8, PlayerId:64, _Bin/binary>> = BinData,
?TRACE("10003: Code: ~p PlayerId~p~n", [Code, PlayerId]),
if Code =:= 1 ->
handle(enter_player, {PlayerId}, Socket),
gen_server:cast(Pid, {playerid, PlayerId});
true ->
gen_server:cast(Pid, {stop})
end;
10004 ->
<<Code:8, _Bin/binary>> = BinData,
?TRACE("10004: Code: ~p ~n", [Code]),
if Code =/= 0 ->
gen_server:cast(Pid, enter_ok);
true ->
gen_server:cast(Pid, {stop})
end;
13001 ->
<<Uid:64, Gender:8, Level:8, Speed:8, Scene:16, X:8, Y:8, Hp:32, _Other/binary>> = BinData,
?TRACE("13001: Uid:~p, Gender ~p, Level ~p, Speed ~p, Scene ~p, X ~p, Y ~p, Hp ~p~n", [Uid, Gender, Level, Speed, Scene, X, Y, Hp]),
%%
gen_server:cast(Pid, {upgrade_state_13001, [Scene, X, Y, Hp]}),
{ok, Data} = ptr_30:write(30003, [4]),
gen_tcp:send(Socket, Data),
ok;
10007 ->
<<_Code:16>> = BinData,
ok;
30501 ->
Result = ptr_30:read(30501, BinData),
?TRACE("~p : ~p", [30501, Result]),
{ok, List} = Result,
lists:foreach(fun(Tid) ->
{ok, Data} = ptr_30:write(30004, [Tid]),
gen_tcp:send(Socket, Data)
end,
List);
O ->
Result = ptr_30:read(O, BinData),
?TRACE("~p : ~p", [O, Result])
end,
do_parse_packet(Socket, Pid);
{fail, _} ->
?TRACE("do_parse_packet recv data failed:/~p/~p/~n~p~n", [Socket, Pid, RecvData]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_1})
end;
%%
{inet_async, Socket, Ref, {error, timeout}} ->
?TRACE("do_parse_packet timeout:/~p/~p/~n", [Socket, Pid]),
do_parse_packet(Socket, Pid);
%%
Reason ->
?TRACE("do_parse_packet: Error Reason:/~p/~p/~n", [Socket, Reason]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_3})
end.
%%
handle_action_random(PlayerId, Socket) ->
Actions = [chat],
Action = lists:nth(random:uniform(length(Actions)), Actions),
Module = list_to_atom(lists:concat(["robot_", Action])),
catch Module:handle(PlayerId, Socket),
ok.
handle_action_friend(State) ->
Socket = State#robot.socket,
Friend = State#robot.frda,
case Friend of
[] ->
gen_tcp:send(Socket, pack(13099, <<40:8, 200:8>>)),
State;
_ ->
Index = random:uniform(length(Friend)),
PlayerId = lists:nth(Index, Friend),
Fri = lists:delete(PlayerId, Friend),
Actions = [friend],
Action = lists:nth(random:uniform(length(Actions)), Actions),
Module = list_to_atom(lists:concat(["robot_", Action])),
catch Module:handle(PlayerId, Socket),
State#robot{frda = Fri}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
handle(heart, _, Socket) ->
case gen_tcp:send(Socket, pack(10006, <<>>)) of
ok ->
sleep(24 * 1000),
handle(heart, a, Socket);
_ ->
error
end;
%%socket链接
handle(start_child_socket, {State, N}, _) ->
sleep(5000),
case get_game_server() of
{Ip, Port} ->
case connect_server(Ip, Port - N * 100) of
{ok, Socket} ->
Accid = State#robot.acid,
Pid = State#robot.pid,
Data = pack(10008, <<9999:16, Accid:32, N:8>>),
gen_tcp:send(Socket, Data),
try
Ref = async_recv(Socket, ?HEADER_LENGTH, ?TCP_TIMEOUT),
receive
{inet_async, Socket, Ref, {ok, <<Len:16, Cmd:16>>}} ->
%%?TRACE("--------------------------cmd:~p~n",[Cmd]),
BodyLen = Len - ?HEADER_LENGTH,
case BodyLen > 0 of
true ->
Ref1 = async_recv(Socket, BodyLen, ?TCP_TIMEOUT),
receive
{inet_async, Socket, Ref1, {ok, Binary}} when Cmd =:= 10008 ->
%%?TRACE("----------------------rev--10008~n",[]),
<<Code:16, N:8>> = Binary,
%%?TRACE("----------------------rev--10008:~p~n",[Code]),
if
Code == 1 ->
%%spawn_link(fun()->do_parse_packet(Socket, Pid) end),
gen_server:cast(Pid, {add_child_socket, N, Socket}),
{ok, N};
true ->
error_50
end;
Other ->
?TRACE("---------------child-----------cmd--other:~p~n", [Other]),
gen_tcp:close(Socket),
error_60
end;
false ->
error_70
end;
%%
Other ->
?TRACE("---------------------child------------other-----err---------~p~n", [Other]),
gen_tcp:close(Socket),
error_80
end
catch
_:_ -> gen_tcp:close(Socket),
error_90
end;
_ ->
error_100
end;
_ -> error_110
end;
%%
handle(login, {Accid, AccName}, Socket) ->
?TRACE("sending login request entry socket: ~p ~p ~p~n", [Accid, AccName, Socket]),
AccStamp = 1273027133,
Tick = integer_to_list(Accid) ++ AccName ++ integer_to_list(AccStamp) ++ ?TICKET,
TickMd5 = util:md5(Tick),
TickMd5Bin = list_to_binary(TickMd5),
TLen = byte_size(TickMd5Bin),
AccNameLen = byte_size(list_to_binary(AccName)),
AccNameBin = list_to_binary(AccName),
Data = <<9999:16, Accid:32, AccStamp:32, AccNameLen:16, AccNameBin/binary, TLen:16, TickMd5Bin/binary>>,
?TRACE("sending login request: ~p ~p~n", [Accid, AccName]),
gen_tcp:send(Socket, pack(10000, Data)),
ok;
%%
handle(list_player, _, Socket) ->
gen_tcp:send(Socket, pack(10002, <<1:16>>)),
ok;
%%
handle(select_role, Accid, Socket) ->
NickName = "GUEST-" ++ integer_to_list(Accid),
NameBin = list_to_binary(NickName),
TLen = byte_size(NameBin),
gen_tcp:send(Socket, pack(10003, <<9999:16, 1:8, 1:8, TLen:16, NameBin/binary>>)),
ok;
%%
handle(enter_player, {PlayerId}, Socket) ->
gen_tcp:send(Socket, pack(10004, <<9999:16, PlayerId:64, 30:8, 20:8>>)),
ok;
%%
handle(run, a, Socket) ->
X = util:rand(15, 45),
Y = util:rand(15, 45),
gen_tcp:send(Socket, pack(12001, <<X:16, Y:16>>));
%%ai模式跑步
handle(run, {X, Y, SX, SY}, Socket) ->
?TRACE("----running:[~p][~p]~n", [X, Y]),
gen_tcp:send(Socket, pack(12001, <<X:8, Y:8, SX:8, SY:8>>));
%%
handle(enter_scene, Sid, Socket) ->
gen_tcp:send(Socket, pack(12005, <<Sid:32>>)),
gen_tcp:send(Socket, pack(12002, <<>>)); %%12002,
%%
handle(chat1, PlayerId, Socket) ->
Actions = [chat],
Action = lists:nth(random:uniform(length(Actions)), Actions),
Module = list_to_atom(lists:concat(["robot_", Action])),
catch Module:handle(PlayerId, Socket),
ok;
%%
handle(chat, Data, Socket) ->
Bin = list_to_binary(Data),
L = byte_size(Bin),
gen_tcp:send(Socket, pack(11010, <<L:16, Bin/binary>>));
%%
handle(undefined, a, _Socket) ->
ok;
%%
handle(get_player_info, Id, Socket) ->
gen_tcp:send(Socket, pack(13004, <<Id:16>>));
%%
handle(get_self_info, _, Socket) ->
?TRACE("get_self_info: sending 13001~n"),
gen_tcp:send(Socket, pack(13001, <<>>));
%%
handle(revive, _, Socket) ->
gen_tcp:send(Socket, pack(20004, <<3:8>>)),
Action = tool:to_binary("-加血 100000"),
ActionLen = byte_size(Action),
Data = <<ActionLen:16, Action/binary>>,
Packet = pack(11020, Data),
gen_tcp:send(Socket, Packet);
handle(Handle, Data, Socket) ->
?TRACE("handle error: /~p/~p/~n", [Handle, Data]),
{reply, handle_no_match, Socket}.
%%
read(<<L:32, 10002:16, Num:16, Bin/binary>>) ->
?TRACE("client read: ~p ~p ~p~n", [L, 10002, Num]),
F = fun(Bin1) ->
<<Id:32, S:16, C:16, Sex:16, Lv:16, Bin2/binary>> = Bin1,
{Name, Rest} = read_string(Bin2),
?TRACE("player list: Id=~p Status=~p Pro=~p Sex=~p Lv=~p Name=~p~n", [Id, S, C, Sex, Lv, Name]),
Rest
end,
for(0, Num, F, Bin),
?TRACE("player list end.~n");
read(<<L:32, Cmd:16>>) ->
?TRACE("client read: ~p ~p~n", [L, Cmd]);
read(<<L:32, Cmd:16, Status:16>>) ->
?TRACE("client read: ~p ~p ~p~n", [L, Cmd, Status]);
read(<<L:32, Cmd:16, Bin/binary>>) ->
?TRACE("client read: ~p ~p ~p~n", [L, Cmd, Bin]);
read(Bin) ->
?TRACE("client rec: ~p~n", [Bin]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%
read_string(Bin) ->
case Bin of
<<Len:16, Bin1/binary>> ->
case Bin1 of
<<Str:Len/binary-unit:8, Rest/binary>> ->
{binary_to_list(Str), Rest};
_R1 ->
{[], <<>>}
end;
_R1 ->
{[], <<>>}
end.
random_sleep(T) ->
N = random:uniform(T),
timer:sleep(N * 100).
sleep(T) ->
receive
after T -> ok
end.
for(Max, Max, _F) ->
[];
for(Min, Max, F) ->
[F(Min) | for(Min + 1, Max, F)].
for(Max, Max, _F, X) ->
X;
for(Min, Max, F, X) ->
F(X),
for(Min + 1, Max, F, X).
sleep_send({T, S}) ->
receive
after T -> handle(run, a, S)
end.
get_pid(Name) ->
case whereis(Name) of
undefined ->
err;
Pid -> Pid
end.
ping(Node) ->
case net_adm:ping(Node) of
pang ->
?TRACE("ping ~p error.~n", [Node]);
pong ->
?TRACE("ping ~p success.~n", [Node]);
Error ->
?TRACE("error: ~p ~n", [Error])
end.
do_act(Pid) ->
State = gen_server:call(Pid, {get_state}),
handle(State#robot.act, a, State#robot.socket),
sleep(2000),
do_act(Pid).
%%
%%
ai(Pid) ->
%%?TRACE("start ai ~p.~n",[Pid]),
%%
gen_server:cast(Pid, {get_state_13001}),
Random_interval = random:uniform(6000) + 3000,
sleep(Random_interval),
State = gen_server:call(Pid, {get_state}),
case State#robot.act of
run ->
case State#robot.hp > 0 of
true ->
case State#robot.status of
standing ->
if State#robot.step == 0 ->
Tox = rand(5, 27),
Toy = rand(30, 45),
New_step = 1;
true ->
Tox = rand(5, 27),%%State#robot.tox,
Toy = rand(30, 45),%%State#robot.toy,
New_step = 0
end,
State2 = State#robot{tox = Tox, toy = Toy, step = New_step, status = running},
gen_server:cast(State#robot.pid, {upgrade_state, State2});
running ->
if State#robot.x =/= State#robot.tox orelse State#robot.y =/= State#robot.toy -> %%
handle(run, {State#robot.x, State#robot.y, State#robot.tox, State#robot.toy}, State#robot.socket),
Random_interval2 = round(abs(State#robot.tox - State#robot.x) / 4) * 1000,
sleep(Random_interval2),
handle(run, {State#robot.tox, State#robot.toy, State#robot.tox, State#robot.toy}, State#robot.socket);
true ->
State2 = State#robot{status = standing}, %%,
gen_server:cast(State#robot.pid, {upgrade_state, State2}) %%
end;
_ ->
?TRACE("robot status error!~n")
end;
false ->
ok%handle(revive,a,State#robot.socket)
end;
undefined ->
ok
end,
ai(Pid).
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.
rand(Same, Same) -> Same;
rand(Min, Max) ->
M = Min - 1,
if
Max - M =< 0 ->
0;
true ->
random:uniform(Max - M) + M
end.

+ 218
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/ptr_30.erl Dosyayı Görüntüle

@ -0,0 +1,218 @@
%%--------------------------------------
%% @Module: ptr_30
%% Author: Auto Generated
%% Created: Thu Feb 28 15:17:18 2013
%% Description:
%%--------------------------------------
-module(ptr_30).
%%--------------------------------------
%% Include files
%%--------------------------------------
-include("common.hrl").
-include("record.hrl").
%%--------------------------------------
%% Exported Functions
%%--------------------------------------
-compile(export_all).
%%--------------------------------------
%%Protocol:30003
%%--------------------------------------
read(30003, <<Result:16>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol 30004
%%--------------------------------------
read(30004, <<Result:16>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol:30005 npc状态
%%--------------------------------------
read(30005, <<BinData/binary>>) ->
<<NpcListLen:16, NpcListBin/binary>> = BinData,
Fun_NpcList = fun(_Idx, {RestBin, ResultList}) ->
<<NpcId:16, NpcState:8, _NpcList_RestBin/binary>> = RestBin,
{_NpcList_RestBin, [[NpcId, NpcState] | ResultList]}
end,
{_NpcList_DoneBin, NpcList} = lists:foldl(Fun_NpcList, {NpcListBin, []}, lists:seq(1, NpcListLen)),
{ok, [lists:reverse(NpcList)]};
%%--------------------------------------
%%Protocol:30006
%%--------------------------------------
read(30006, <<BinData/binary>>) ->
<<TaskListLen:16, TaskListBin/binary>> = BinData,
Fun_TaskList = fun(_Idx, {RestBin, ResultList}) ->
<<TaskId:16, TaskState:8, TaskProcess:32, _TaskList_RestBin/binary>> = RestBin,
{_TaskList_RestBin, [[TaskId, TaskState, TaskProcess] | ResultList]}
end,
{_TaskList_DoneBin, TaskList} = lists:foldl(Fun_TaskList, {TaskListBin, []}, lists:seq(1, TaskListLen)),
{ok, lists:reverse(TaskList)};
%%--------------------------------------
%%Protocol:30007
%%--------------------------------------
read(30007, <<Result:16>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 30501
%%--------------------------------------
read(30501, <<BinData/binary>>) ->
<<TaskListLen:16, TaskListBin/binary>> = BinData,
Fun_TaskList = fun(_Idx, {RestBin, ResultList}) ->
<<TaskId:16, _TaskList_RestBin/binary>> = RestBin,
{_TaskList_RestBin, [TaskId | ResultList]}
end,
{_TaskList_DoneBin, TaskList} = lists:foldl(Fun_TaskList, {TaskListBin, []}, lists:seq(1, TaskListLen)),
{ok, lists:reverse(TaskList)};
%%--------------------------------------
%%Protocol: 30502
%%--------------------------------------
read(30502, <<BinData/binary>>) ->
<<TaskListLen:16, TaskListBin/binary>> = BinData,
Fun_TaskList = fun(_Idx, {RestBin, ResultList}) ->
<<TaskId:16, FinNum:8, NowNum:8, _TaskList_RestBin/binary>> = RestBin,
{_TaskList_RestBin, [[TaskId, FinNum, NowNum] | ResultList]}
end,
{_TaskList_DoneBin, TaskList} = lists:foldl(Fun_TaskList, {TaskListBin, []}, lists:seq(1, TaskListLen)),
{ok, lists:reverse(TaskList)};
%%--------------------------------------
%%Protocol:30503 ()
%%--------------------------------------
read(30503, <<BinData/binary>>) ->
<<TaskListLen:16, TaskListBin/binary>> = BinData,
Fun_TaskList = fun(_Idx, {RestBin, ResultList}) ->
<<TaskId:16, _TaskList_RestBin/binary>> = RestBin,
{_TaskList_RestBin, [TaskId | ResultList]}
end,
{_TaskList_DoneBin, TaskList} = lists:foldl(Fun_TaskList, {TaskListBin, []}, lists:seq(1, TaskListLen)),
{ok, [lists:reverse(TaskList)]};
%%--------------------------------------
%%Protocol:30505
%%--------------------------------------
read(30505, <<TaskId:16>>) ->
{ok, [TaskId]};
%%--------------------------------------
%%Protocol:30506
%%--------------------------------------
read(30506, <<TaskId:16>>) ->
{ok, [TaskId]};
%%--------------------------------------
%%Protocol:30507
%%--------------------------------------
read(30507, <<BinData/binary>>) ->
<<TaskListLen:16, TaskListBin/binary>> = BinData,
Fun_TaskList = fun(_Idx, {RestBin, ResultList}) ->
<<Type:8, _TaskList_RestBin/binary>> = RestBin,
{_TaskList_RestBin, [Type | ResultList]}
end,
{_TaskList_DoneBin, TaskList} = lists:foldl(Fun_TaskList, {TaskListBin, []}, lists:seq(1, TaskListLen)),
{ok, [lists:reverse(TaskList)]};
%%--------------------------------------
%% undefined command
%%--------------------------------------
read(_Cmd, _R) ->
{error, no_match}.
%%--------------------------------------
%%Protocol:30003
%%--------------------------------------
write(30003, [TaskId]) ->
{ok, pt:pack(30003, <<TaskId:16>>)};
%%--------------------------------------
%%Protocol:30004
%%--------------------------------------
write(30004, [TaskId]) ->
{ok, pt:pack(30004, <<TaskId:16>>)};
%%--------------------------------------
%%Protocol:30005 npc状态
%%--------------------------------------
write(30005, [NpcList]) ->
Fun_NpcList = fun([NpcId]) ->
<<NpcId:16>>
end,
NpcList_Len = length(NpcList),
NpcList_ABin = any_to_binary(lists:map(Fun_NpcList, NpcList)),
NpcList_ABinData = <<NpcList_Len:16, NpcList_ABin/binary>>,
{ok, pt:pack(30005, <<NpcList_ABinData/binary>>)};
%%--------------------------------------
%%Protocol:30006
%%--------------------------------------
write(30006, [Len]) ->
{ok, pt:pack(30006, <<Len:8>>)};
%%--------------------------------------
%%Protocol:30007
%%--------------------------------------
write(30007, [TaskId]) ->
{ok, pt:pack(30007, <<TaskId:16>>)};
%%--------------------------------------
%%Protocol: 30501
%%--------------------------------------
write(30501, _) ->
{ok, pt:pack(30501, <<>>)};
%%--------------------------------------
%%Protocol: 30502
%%--------------------------------------
write(30502, _) ->
{ok, pt:pack(30502, <<>>)};
%%--------------------------------------
%%Protocol:30503 ()
%%--------------------------------------
write(30503, _) ->
{ok, pt:pack(30503, <<>>)};
%%--------------------------------------
%%Protocol:30505
%%--------------------------------------
write(30505, _) ->
{ok, pt:pack(30505, <<>>)};
%%--------------------------------------
%%Protocol:30506
%%--------------------------------------
write(30506, _) ->
{ok, pt:pack(30506, <<>>)};
%%--------------------------------------
%%Protocol:30507
%%--------------------------------------
write(30507, _) ->
{ok, pt:pack(30507, <<>>)};
%%--------------------------------------
%% undefined command
%%--------------------------------------
write(Cmd, _R) ->
?ERROR_MSG("~s_errorcmd_[~p] ", [misc:time_format(game_timer:now()), Cmd]),
{ok, pt:pack(0, <<>>)}.
%%------------------------------------
%% internal function
%%------------------------------------
pack_string(Str) ->
BinData = tool:to_binary(Str),
Len = byte_size(BinData),
<<Len:16, BinData/binary>>.
any_to_binary(Any) ->
tool:to_binary(Any).

+ 30
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/new_robot/task_script.erl Dosyayı Görüntüle

@ -0,0 +1,30 @@
%% @author Administrator
%% @doc @todo Add description to task_script.
-module(task_script).
-define(HEADER_LENGTH, 4). %
%% ====================================================================
%% API functions
%% ====================================================================
-export([call/3]).
%% ====================================================================
%% Internal functions
%% ====================================================================
call(30003, TaskId, Socket) ->
gen_tcp:send(Socket, pack(30003, <<TaskId:16>>));
call(30004, TaskId, Socket) ->
gen_tcp:send(Socket, pack(30004, <<TaskId:16>>));
call(30007, TaskId, Socket) ->
gen_tcp:send(Socket, pack(30007, <<TaskId:16>>));
call(30005, NpcList, Socket) ->
gen_tcp:send(Socket, pack(30005, NpcList));
call(30006, Size, Socket) ->
gen_tcp:send(Socket, pack(30006, <<Size:8>>)).
%%
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 144
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_11.erl Dosyayı Görüntüle

@ -0,0 +1,144 @@
%%--------------------------------------
%% @Module: ptr_11
%% Author: Auto Generated
%% Created: Fri Mar 01 19:14:40 2013
%% Description:
%%--------------------------------------
-module(ptr_11).
%%--------------------------------------
%% Include files
%%--------------------------------------
-include("common.hrl").
-include("record.hrl").
%%--------------------------------------
%% Exported Functions
%%--------------------------------------
-compile(export_all).
%%--------------------------------------
%%Protocol: 11000
%%--------------------------------------
read(11000, <<Uid:64, BinData/binary>>) ->
{Name, _Name_DoneBin} = pt:read_string(BinData),
<<Type:8, _Type_DoneBin/binary>> = _Name_DoneBin,
{Content, _Content_DoneBin} = pt:read_string(_Type_DoneBin),
{ok, [Uid, Name, Type, Content]};
%%--------------------------------------
%%Protocol: 11001
%%--------------------------------------
read(11001, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 11002
%%--------------------------------------
read(11002, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 11003
%%--------------------------------------
read(11003, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 11004
%%--------------------------------------
read(11004, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 11005 GM指令
%%--------------------------------------
read(11005, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 11010 /广
%%--------------------------------------
read(11010, <<Type:8, BinData/binary>>) ->
{Content, _Content_DoneBin} = pt:read_string(BinData),
{ok, [Type, Content]};
%%--------------------------------------
%%Protocol: 11099
%%--------------------------------------
%%--------------------------------------
%% undefined command
%%--------------------------------------
read(_Cmd, _R) ->
{error, no_match}.
%%--------------------------------------
%%Protocol: 11000
%%--------------------------------------
%%--------------------------------------
%%Protocol: 11001
%%--------------------------------------
write(11001, [ShowState, Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11001, <<ShowState:8, Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 11002
%%--------------------------------------
write(11002, [Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11002, <<Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 11003
%%--------------------------------------
write(11003, [Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11003, <<Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 11004
%%--------------------------------------
write(11004, [PeerId, Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11004, <<PeerId:64, Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 11005 GM指令
%%--------------------------------------
write(11005, [Type, Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11005, <<Type:8, Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 11010 /广
%%--------------------------------------
%%--------------------------------------
%%Protocol: 11099
%%--------------------------------------
write(11099, [Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(11099, <<Content_StrBin/binary>>)};
%%--------------------------------------
%% undefined command
%%--------------------------------------
write(Cmd, _R) ->
?ERROR_MSG("~s_errorcmd_[~p] ", [misc:time_format(game_timer:now()), Cmd]),
{ok, pt:pack(0, <<>>)}.
%%------------------------------------
%% internal function
%%------------------------------------
pack_string(Str) ->
BinData = tool:to_binary(Str),
Len = byte_size(BinData),
<<Len:16, BinData/binary>>.
any_to_binary(Any) ->
tool:to_binary(Any).

+ 198
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_19.erl Dosyayı Görüntüle

@ -0,0 +1,198 @@
%%--------------------------------------
%% @Module: ptr_19
%% Author: Auto Generated
%% Created: Tue Mar 05 09:35:33 2013
%% Description:
%%--------------------------------------
-module(ptr_19).
%%--------------------------------------
%% Include files
%%--------------------------------------
-include("common.hrl").
-include("record.hrl").
%%--------------------------------------
%% Exported Functions
%%--------------------------------------
-compile(export_all).
%%--------------------------------------
%%Protocol: 19001 GM
%%--------------------------------------
read(19001, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 19002 GM反馈
%%--------------------------------------
read(19002, <<BinData/binary>>) ->
<<FbListLen:16, FbListBin/binary>> = BinData,
Fun_FbList = fun(_Idx, {RestBin, ResultList}) ->
<<FbId:32, Type:8, State:8, _ContentList_RestBin/binary>> = RestBin,
<<ContentListLen:16, ContentListBin/binary>> = _ContentList_RestBin,
Fun_ContentList = fun(_Idx, {RestBin, ResultList}) ->
{Name, _Name_DoneBin} = pt:read_string(RestBin),
{Content, _Content_DoneBin} = pt:read_string(_Name_DoneBin),
<<Date:32, _ContentList_RestBin/binary>> = _Content_DoneBin,
{_ContentList_RestBin, [[Name, Content, Date] | ResultList]}
end,
{_ContentList_DoneBin, ContentList} = lists:foldl(Fun_ContentList, {ContentListBin, []}, lists:seq(1, ContentListLen)),
{_ContentList_DoneBin, [[FbId, Type, State, lists:reverse(ContentList)] | ResultList]}
end,
{_FbList_DoneBin, FbList} = lists:foldl(Fun_FbList, {FbListBin, []}, lists:seq(1, FbListLen)),
{ok, [lists:reverse(FbList)]};
%%--------------------------------------
%%Protocol: 19010
%%--------------------------------------
read(19010, <<Num:8>>) ->
{ok, [Num]};
%%--------------------------------------
%%Protocol: 19011
%%--------------------------------------
read(19011, <<BinData/binary>>) ->
<<MailListLen:16, MailListBin/binary>> = BinData,
Fun_MailList = fun(_Idx, {RestBin, ResultList}) ->
<<MailId:32, Type:8, State:8, Date:32, _SName_RestBin/binary>> = RestBin,
{SName, _SName_DoneBin} = pt:read_string(_SName_RestBin),
{Title, _Title_DoneBin} = pt:read_string(_SName_DoneBin),
{_Title_DoneBin, [[MailId, Type, State, Date, SName, Title] | ResultList]}
end,
{_MailList_DoneBin, MailList} = lists:foldl(Fun_MailList, {MailListBin, []}, lists:seq(1, MailListLen)),
{ok, [lists:reverse(MailList)]};
%%--------------------------------------
%%Protocol: 19012
%%--------------------------------------
read(19012, <<StCode:8, MailId:32, BinData/binary>>) ->
{Content, _Content_DoneBin} = pt:read_string(BinData),
<<GoodListLen:16, GoodListBin/binary>> = _Content_DoneBin,
Fun_GoodList = fun(_Idx, {RestBin, ResultList}) ->
<<GoodTypeId:32, GoodsNum:8, Exist:8, _GoodList_RestBin/binary>> = RestBin,
{_GoodList_RestBin, [[GoodTypeId, GoodsNum, Exist] | ResultList]}
end,
{_GoodList_DoneBin, GoodList} = lists:foldl(Fun_GoodList, {GoodListBin, []}, lists:seq(1, GoodListLen)),
{ok, [StCode, MailId, Content, lists:reverse(GoodList)]};
%%--------------------------------------
%%Protocol: 19013
%%--------------------------------------
read(19013, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 19014
%%--------------------------------------
read(19014, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 19015
%%--------------------------------------
read(19015, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 19016
%%--------------------------------------
read(19016, <<Result:8, BinData/binary>>) ->
<<ErrRecvListLen:16, ErrRecvListBin/binary>> = BinData,
Fun_ErrRecvList = fun(_Idx, {RestBin, ResultList}) ->
{ErrName, _ErrName_DoneBin} = pt:read_string(RestBin),
{_ErrName_DoneBin, [ErrName | ResultList]}
end,
{_ErrRecvList_DoneBin, ErrRecvList} = lists:foldl(Fun_ErrRecvList, {ErrRecvListBin, []}, lists:seq(1, ErrRecvListLen)),
{ok, [Result, lists:reverse(ErrRecvList)]};
%%--------------------------------------
%% undefined command
%%--------------------------------------
read(_Cmd, _R) ->
{error, no_match}.
%%--------------------------------------
%%Protocol: 19001 GM
%%--------------------------------------
write(19001, [Type, Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(19001, <<Type:8, Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 19002 GM反馈
%%--------------------------------------
write(19002, _) ->
{ok, pt:pack(19002, <<>>)};
%%--------------------------------------
%%Protocol: 19010
%%--------------------------------------
write(19010, _) ->
{ok, pt:pack(19010, <<>>)};
%%--------------------------------------
%%Protocol: 19011
%%--------------------------------------
write(19011, _) ->
{ok, pt:pack(19011, <<>>)};
%%--------------------------------------
%%Protocol: 19012
%%--------------------------------------
write(19012, [MailId]) ->
{ok, pt:pack(19012, <<MailId:32>>)};
%%--------------------------------------
%%Protocol: 19013
%%--------------------------------------
write(19013, [MailId, Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(19013, <<MailId:32, Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 19014
%%--------------------------------------
write(19014, [MailId]) ->
{ok, pt:pack(19014, <<MailId:32>>)};
%%--------------------------------------
%%Protocol: 19015
%%--------------------------------------
write(19015, [MailId]) ->
{ok, pt:pack(19015, <<MailId:32>>)};
%%--------------------------------------
%%Protocol: 19016
%%--------------------------------------
write(19016, [Title, Content, RecvList]) ->
Title_StrBin = pack_string(Title),
Content_StrBin = pack_string(Content),
Fun_RecvList = fun([Name]) ->
Name_StrBin = pack_string(Name),
<<Name_StrBin/binary>>
end,
RecvList_Len = length(RecvList),
RecvList_ABin = any_to_binary(lists:map(Fun_RecvList, RecvList)),
RecvList_ABinData = <<RecvList_Len:16, RecvList_ABin/binary>>,
{ok, pt:pack(19016, <<Title_StrBin/binary, Content_StrBin/binary, RecvList_ABinData/binary>>)};
%%--------------------------------------
%% undefined command
%%--------------------------------------
write(Cmd, _R) ->
?ERROR_MSG("~s_errorcmd_[~p] ", [misc:time_format(game_timer:now()), Cmd]),
{ok, pt:pack(0, <<>>)}.
%%------------------------------------
%% internal function
%%------------------------------------
pack_string(Str) ->
BinData = tool:to_binary(Str),
Len = byte_size(BinData),
<<Len:16, BinData/binary>>.
any_to_binary(Any) ->
tool:to_binary(Any).

+ 427
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_40.erl Dosyayı Görüntüle

@ -0,0 +1,427 @@
%%--------------------------------------
%% @Module: ptr_40
%% Author: Auto Generated
%% Created: Wed Mar 06 20:35:00 2013
%% Description:
%%--------------------------------------
-module(ptr_40).
%%--------------------------------------
%% Include files
%%--------------------------------------
-include("common.hrl").
-include("record.hrl").
-include("debug.hrl").
%%--------------------------------------
%% Exported Functions
%%--------------------------------------
-compile(export_all).
%%--------------------------------------
%%Protocol: 40001 ()
%%--------------------------------------
%read(40001,<<CurPageNo:8,TotalPage:8,BinData/binary>>) ->
read(40001, Data) ->
NewData = zlib:uncompress(Data),
<<CurPageNo:8, TotalPage:8, BinData/binary>> = NewData,
%?TRACE("read 40001 CurPageNo= ~p ,TotalPage=~p ~n", [CurPageNo,TotalPage]),
<<GuildListLen:16, GuildListBin/binary>> = BinData,
%?TRACE("read 40001 GuildListLen: ~p ~n", [GuildListLen]),
Fun_GuildList = fun(_Idx, {RestBin, ResultList}) ->
<<GuildId:32, _GuildName_RestBin/binary>> = RestBin,
%?TRACE("read 40001 GuildId: ~p ~n", [GuildId]),
{GuildName, _GuildName_DoneBin} = pt:read_string(_GuildName_RestBin),
<<CurNum:8, MaxNum:8, Level:8, Uid:64, _Name_RestBin/binary>> = _GuildName_DoneBin,
{Name, _Name_DoneBin} = pt:read_string(_Name_RestBin),
{Announce, _Announce_DoneBin} = pt:read_string(_Name_DoneBin),
{_Announce_DoneBin, [[GuildId, GuildName, CurNum, MaxNum, Level, Uid, Name, Announce] | ResultList]}
end,
{_GuildList_DoneBin, GuildList} = lists:foldl(Fun_GuildList, {GuildListBin, []}, lists:seq(1, GuildListLen)),
%?TRACE("read 40001 GuildList: ~p", [GuildList]),
{ok, [CurPageNo, TotalPage, lists:reverse(GuildList)]};
%%--------------------------------------
%%Protocol: 40002
%%--------------------------------------
read(40002, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40003
%%--------------------------------------
read(40003, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40004 退
%%--------------------------------------
read(40004, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40005
%%--------------------------------------
read(40005, <<StCode:8>>) ->
{ok, [StCode]};
read(40005, <<StCode:8, BinData/binary>>) ->
<<MemListLen:16, MemListBin/binary>> = BinData,
Fun_MemList = fun(_Idx, {RestBin, ResultList}) ->
<<Uid:64, _Name_RestBin/binary>> = RestBin,
{Name, _Name_DoneBin} = pt:read_string(_Name_RestBin),
<<Level:8, Career:8, Gender:8, Position:8, Contrib:32, LastLoginTime:32, Online:8, _MemList_RestBin/binary>> = _Name_DoneBin,
{_MemList_RestBin, [[Uid, Name, Level, Career, Gender, Position, Contrib, LastLoginTime, Online] | ResultList]}
end,
{_MemList_DoneBin, MemList} = lists:foldl(Fun_MemList, {MemListBin, []}, lists:seq(1, MemListLen)),
{ok, [StCode, lists:reverse(MemList)]};
%%--------------------------------------
%%Protocol: 40006
%%--------------------------------------
read(40006, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40007
%%--------------------------------------
read(40007, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40008
%%--------------------------------------
read(40008, <<StCode:8>>) ->
{ok, [StCode]};
read(40008, <<StCode:8, BinData/binary>>) ->
<<RejectListLen:16, RejectListBin/binary>> = BinData,
Fun_RejectList = fun(_Idx, {RestBin, ResultList}) ->
<<Uid:64, Pos:8, State:8, AgreeNum:8, DisagreeNum:8, RemainTime:32, _RejectList_RestBin/binary>> = RestBin,
{_RejectList_RestBin, [[Uid, Pos, State, AgreeNum, DisagreeNum, RemainTime] | ResultList]}
end,
{_RejectList_DoneBin, RejectList} = lists:foldl(Fun_RejectList, {RejectListBin, []}, lists:seq(1, RejectListLen)),
{ok, [StCode, lists:reverse(RejectList)]};
%%--------------------------------------
%%Protocol: 40009
%%--------------------------------------
read(40009, <<BinData/binary>>) ->
<<LogListLen:16, LogListBin/binary>> = BinData,
Fun_LogList = fun(_Idx, {RestBin, ResultList}) ->
<<Uid:32, _Name_RestBin/binary>> = RestBin,
{Name, _Name_DoneBin} = pt:read_string(_Name_RestBin),
<<TimeStamp:32, _Content_RestBin/binary>> = _Name_DoneBin,
{Content, _Content_DoneBin} = pt:read_string(_Content_RestBin),
{_Content_DoneBin, [[Uid, Name, TimeStamp, Content] | ResultList]}
end,
{_LogList_DoneBin, LogList} = lists:foldl(Fun_LogList, {LogListBin, []}, lists:seq(1, LogListLen)),
{ok, [lists:reverse(LogList)]};
%%--------------------------------------
%%Protocol: 40030 (//)
%%--------------------------------------
read(40030, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40031 (/)
%%--------------------------------------
read(40031, <<BinData/binary>>) ->
<<ApplyListLen:16, ApplyListBin/binary>> = BinData,
Fun_ApplyList = fun(_Idx, {RestBin, ResultList}) ->
<<Uid:64, _Name_RestBin/binary>> = RestBin,
{Name, _Name_DoneBin} = pt:read_string(_Name_RestBin),
<<Level:8, Career:8, Gender:8, Force:32, TimeStamp:32, _ApplyList_RestBin/binary>> = _Name_DoneBin,
{_ApplyList_RestBin, [[Uid, Name, Level, Career, Gender, Force, TimeStamp] | ResultList]}
end,
{_ApplyList_DoneBin, ApplyList} = lists:foldl(Fun_ApplyList, {ApplyListBin, []}, lists:seq(1, ApplyListLen)),
{ok, [lists:reverse(ApplyList)]};
%%--------------------------------------
%%Protocol: 40032 (/)
%%--------------------------------------
read(40032, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40033 ()
%%--------------------------------------
read(40033, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40034 ()
%%--------------------------------------
read(40034, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40035 (/)
%%--------------------------------------
read(40035, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40036 (//)
%%--------------------------------------
read(40036, <<Result:8, UplevelCd:32>>) ->
{ok, [Result, UplevelCd]};
%%--------------------------------------
%%Protocol: 40037
%%--------------------------------------
read(40037, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40039
%%--------------------------------------
read(40039, <<Result:8>>) ->
{ok, [Result]};
%%--------------------------------------
%%Protocol: 40070 (广)
%%--------------------------------------
read(40070, <<Uid:64, BinData/binary>>) ->
{Name, _Name_DoneBin} = pt:read_string(BinData),
<<Level:8, _Level_DoneBin/binary>> = _Name_DoneBin,
<<Career:8, _Career_DoneBin/binary>> = _Level_DoneBin,
<<Gender:8, _Gender_DoneBin/binary>> = _Career_DoneBin,
{ok, [Uid, Name, Level, Career, Gender]};
%%--------------------------------------
%%Protocol: 40071 ()
%%--------------------------------------
read(40071, <<GuildId:32, BinData/binary>>) ->
{GuildName, _GuildName_DoneBin} = pt:read_string(BinData),
{ok, [GuildId, GuildName]};
%%--------------------------------------
%%Protocol: 40072
%%--------------------------------------
read(40072, <<Uid:64, BinData/binary>>) ->
{Name, _Name_DoneBin} = pt:read_string(BinData),
<<GuildId:32, _GuildId_DoneBin/binary>> = _Name_DoneBin,
<<MemNum:8, _MemNum_DoneBin/binary>> = _GuildId_DoneBin,
<<Level:8, _Level_DoneBin/binary>> = _MemNum_DoneBin,
{GuildName, _GuildName_DoneBin} = pt:read_string(_Level_DoneBin),
<<Uid:64, _Uid_DoneBin/binary>> = _GuildName_DoneBin,
{Name, _Name_DoneBin} = pt:read_string(_Uid_DoneBin),
{ok, [Uid, Name, GuildId, MemNum, Level, GuildName, Uid, Name]};
%%--------------------------------------
%%Protocol: 40073 (广)
%%--------------------------------------
read(40073, <<Uid:64, BinData/binary>>) ->
{Name, _Name_DoneBin} = pt:read_string(BinData),
<<OldPos:8, _OldPos_DoneBin/binary>> = _Name_DoneBin,
<<NewPos:8, _NewPos_DoneBin/binary>> = _OldPos_DoneBin,
{ok, [Uid, Name, OldPos, NewPos]};
%%--------------------------------------
%%Protocol: 40074 (广)
%%--------------------------------------
read(40074, <<OldUid:64, BinData/binary>>) ->
{OldName, _OldName_DoneBin} = pt:read_string(BinData),
<<NewUid:64, _NewUid_DoneBin/binary>> = _OldName_DoneBin,
{NewName, _NewName_DoneBin} = pt:read_string(_NewUid_DoneBin),
{ok, [OldUid, OldName, NewUid, NewName]};
%%--------------------------------------
%%Protocol: 40075 (广)
%%--------------------------------------
read(40075, <<OldLevel:8, NewLevel:8>>) ->
{ok, [OldLevel, NewLevel]};
%%--------------------------------------
%%Protocol: 40076 ()
%%--------------------------------------
read(40076, <<GuildId:32, BinData/binary>>) ->
{GuildName, _GuildName_DoneBin} = pt:read_string(BinData),
{ok, [GuildId, GuildName]};
%%--------------------------------------
%%Protocol: 40077
%%--------------------------------------
read(40077, <<BinData/binary>>) ->
{Content, _Content_DoneBin} = pt:read_string(BinData),
{ok, [Content]};
%%--------------------------------------
%%Protocol: 40078 ()
%%--------------------------------------
read(40078, <<GuildId:32, BinData/binary>>) ->
{GuildName, _GuildName_DoneBin} = pt:read_string(BinData),
{ok, [GuildId, GuildName]};
%%--------------------------------------
%% undefined command
%%--------------------------------------
read(_Cmd, _R) ->
{error, no_match}.
%%--------------------------------------
%%Protocol: 40001 ()
%%--------------------------------------
write(40001, [PageNo, IsNotFull, IsSameGroup]) ->
{ok, pt:pack(40001, <<PageNo:8, IsNotFull:8, IsSameGroup:8>>)};
%%--------------------------------------
%%Protocol: 40002
%%--------------------------------------
write(40002, [Name, Announce]) ->
Name_StrBin = pack_string(Name),
Announce_StrBin = pack_string(Announce),
{ok, pt:pack(40002, <<Name_StrBin/binary, Announce_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 40003
%%--------------------------------------
write(40003, [GuildId]) ->
{ok, pt:pack(40003, <<GuildId:32>>)};
%%--------------------------------------
%%Protocol: 40004 退
%%--------------------------------------
write(40004, _) ->
{ok, pt:pack(40004, <<>>)};
%%--------------------------------------
%%Protocol: 40005
%%<<GuildId:32,IsOnline:8>>
%%--------------------------------------
write(40005, [GuildId, IsOnline]) ->
{ok, pt:pack(40005, <<GuildId:32, IsOnline:8>>)};
%%--------------------------------------
%%Protocol: 40006
%%--------------------------------------
write(40006, _) ->
{ok, pt:pack(40006, <<>>)};
%%--------------------------------------
%%Protocol: 40007
%%--------------------------------------
write(40007, [Ops]) ->
{ok, pt:pack(40007, <<Ops:8>>)};
%%--------------------------------------
%%Protocol: 40008
%%--------------------------------------
write(40008, _) ->
{ok, pt:pack(40008, <<>>)};
%%--------------------------------------
%%Protocol: 40009
%%--------------------------------------
write(40009, _) ->
{ok, pt:pack(40009, <<>>)};
%%--------------------------------------
%%Protocol: 40030 (//)
%%--------------------------------------
write(40030, [PlayerId]) ->
{ok, pt:pack(40030, <<PlayerId:64>>)};
%%--------------------------------------
%%Protocol: 40031 (/)
%%--------------------------------------
write(40031, _) ->
{ok, pt:pack(40031, <<>>)};
%%--------------------------------------
%%Protocol: 40032 (/)
%%--------------------------------------
write(40032, [Uid, Ops]) ->
{ok, pt:pack(40032, <<Uid:64, Ops:8>>)};
%%--------------------------------------
%%Protocol: 40033 ()
%%--------------------------------------
write(40033, [Uid]) ->
{ok, pt:pack(40033, <<Uid:64>>)};
%%--------------------------------------
%%Protocol: 40034 ()
%%--------------------------------------
write(40034, _) ->
{ok, pt:pack(40034, <<>>)};
%%--------------------------------------
%%Protocol: 40035 (/)
%%--------------------------------------
write(40035, [PlayerId]) ->
{ok, pt:pack(40035, <<PlayerId:64>>)};
%%--------------------------------------
%%Protocol: 40036 (//)
%%--------------------------------------
write(40036, _) ->
{ok, pt:pack(40036, <<>>)};
%%--------------------------------------
%%Protocol: 40037
%%--------------------------------------
write(40037, [Uid]) ->
{ok, pt:pack(40037, <<Uid:64>>)};
%%--------------------------------------
%%Protocol: 40039
%%--------------------------------------
write(40039, [Content]) ->
Content_StrBin = pack_string(Content),
{ok, pt:pack(40039, <<Content_StrBin/binary>>)};
%%--------------------------------------
%%Protocol: 40070 (广)
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40071 ()
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40072
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40073 (广)
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40074 (广)
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40075 (广)
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40076 ()
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40077
%%--------------------------------------
%%--------------------------------------
%%Protocol: 40078 ()
%%--------------------------------------
%%--------------------------------------
%% undefined command
%%--------------------------------------
write(Cmd, _R) ->
?ERROR_MSG("~s_errorcmd_[~p] ", [misc:time_format(game_timer:now()), Cmd]),
{ok, pt:pack(0, <<>>)}.
%%------------------------------------
%% internal function
%%------------------------------------
pack_string(Str) ->
BinData = tool:to_binary(Str),
Len = byte_size(BinData),
<<Len:16, BinData/binary>>.
any_to_binary(Any) ->
tool:to_binary(Any).

+ 54
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/proto/ptr_44.erl Dosyayı Görüntüle

@ -0,0 +1,54 @@
%%--------------------------------------
%% @Module: ptr_11
%% Author: Auto Generated
%% Created: Fri Mar 01 19:14:40 2013
%% Description:
%%--------------------------------------
-module(ptr_44).
%%--------------------------------------
%% Include files
%%--------------------------------------
-include("common.hrl").
-include("record.hrl").
%%--------------------------------------
%% Exported Functions
%%--------------------------------------
-compile(export_all).
%%--------------------------------------
%%Protocol: 44001
%%--------------------------------------
write(44001, [UpgradeType]) ->
{ok, pt:pack(44001, <<UpgradeType:8>>)};
%%--------------------------------------
%%Protocol: 44006
%%--------------------------------------
write(44006, [AutoBuy, BatchUpgrade]) ->
{ok, pt:pack(44006, <<AutoBuy:8, BatchUpgrade:8>>)};
%%--------------------------------------
%%Protocol: 44007
%%--------------------------------------
write(44007, [AutoBuy]) ->
{ok, pt:pack(44007, <<AutoBuy:8>>)};
%%--------------------------------------
%% undefined command
%%--------------------------------------
write(Cmd, _R) ->
?ERROR_MSG("~s_errorcmd_[~p] ", [misc:time_format(game_timer:now()), Cmd]),
{ok, pt:pack(0, <<>>)}.
%%------------------------------------
%% internal function
%%------------------------------------
pack_string(Str) ->
BinData = tool:to_binary(Str),
Len = byte_size(BinData),
<<Len:16, BinData/binary>>.
any_to_binary(Any) ->
tool:to_binary(Any).

+ 921
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot.erl Dosyayı Görüntüle

@ -0,0 +1,921 @@
%%% -------------------------------------------------------------------
%%% Author: SMXX
%%% Description :
%%% Created :
%%% -------------------------------------------------------------------
-module(robot).
-behaviour(gen_server).
-include("robot.hrl").
-compile(export_all).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(START_ROBOT_GOODS, false).
%%%
%%% API
start() ->
start([1, 1500, ?SERVER_PORT, ?SERVER_ADD]), % IP
ok.
%%StartId AccountID
%%Num int
%%Mod 1 ,2 ip
start([StartId0, Num0, Port0, IP0]) ->
io:format("--Start"),
StartId = list_to_integer(atom_to_list(StartId0)),
Num = list_to_integer(atom_to_list(Num0)),
Port = list_to_integer(atom_to_list(Port0)),
IP = atom_to_list(IP0),
%io:format("--StartId:~p, Num:~p, Port:~p, IP:~p ~n",[StartId, Num, Port, IP]),
ets:new(?ETS_ZIP_PROTO, [named_table, public, set, {read_concurrency, true}]), %%ets表
ets:new(player_mon_info, [named_table, public, set, {read_concurrency, true}]), %%ets表
ets:new(off_line_static, [named_table, public, set, {read_concurrency, true}]),
ets:insert(off_line_static, {1, 0}),
ets:insert(off_line_static, {2, 0}),
io:format("--StartId:~p, Num:~p, Port:~p, IP:~p ~n", [StartId, Num, Port, IP]),
sleep(500),
F = fun(N) ->
io:format("start robot-~p~n", [N]),
sleep(150),
robot:start_link(N, Port, IP)
%io:format("----start robot-~p end ~n",[N])
end,
MaxNum = Num + StartId,
for(StartId, MaxNum, F),
[{_, NUM}] = ets:lookup(off_line_static, 2),
io:format("start finish total attr ~p ~n", [NUM]),
keep_alive().
keep_alive() ->
sleep(100000),
keep_alive().
%% ROBOT
start_link(N, Port, IP) ->
io:format("--N:~p, Port:~p, IP:~p ~n", [N, Port, IP]),
case gen_server:start(?MODULE, [N, Port, IP], []) of
{ok, Pid} ->
io:format("--robot~p start finish!-~n", [N]),
case ?START_ROBOT_GOODS of
true ->
gen_server:cast(Pid, {startGoodsTest});
_ ->
ok
end,
%gen_server:cast(Pid, {start_action});
Pid,
ok;
_ ->
io:format("--robot error!-~n"),
fail
end.
%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% --------------------------------------------------------------------
%%
init([N, Port, IP]) ->
io:format("**********200130916 001 robot init N=~p,Port=~p,IP=~p ~n", [N, Port, IP]),
process_flag(trap_exit, true),
Pid = self(),
case login(N, Pid, Port, IP) of
{ok, Socket} ->
random:seed(erlang:now()),
Flag = random:uniform(2),
io:format("--robot init ~p start finish! runing ~p -~n", [N, Flag > 1]),
if Flag > 1 ->
[{_, NUM}] = ets:lookup(off_line_static, 2),
ets:insert(off_line_static, {2, NUM + 1}),
Act = run;
true ->
Act = other
end,
Scene = 10101,
Robot = #robot{socket = Socket,
login = 0,
acid = N,
id = 0,
pid = Pid,
act = chat,%%
status = none,
scene = Scene,
dstScene = Scene,
tox = rand(1, 40),
toy = rand(1, 20),
orig_n = N,
step = 0,
guild = 0,
guild_post = 0,
frda = [], %%
bkda = [], %% ,
sgda = [] %%
},
%%
io:format("**********200130916 002 robot init finish ~n"),
case ?START_ROBOT_GOODS of
true ->
NewRobot = Robot#robot{act = test_goods};
_ ->
NewRobot = Robot
end,
{ok, NewRobot};
_Error ->
?TRACE("init: error, reason: ~p~n", [_Error]),
{stop, normal, {}}
end.
%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call({get_state}, _From, State) ->
{reply, State, State};
%%
handle_call({upgrade_state_30006, TaskList}, _From, State) ->
io:format("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV:::~p~n", [TaskList]),
NewState = State#robot{task_list = TaskList},
{reply, State, NewState};
%%
handle_call({Mod, Msg}, _From, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_call(State, Msg) of
{reply, Reply, NewState} when is_record(NewState, robot) ->
{reply, Reply, NewState};
_ ->
{reply, noreply, State}
end;
false ->
?TRACE("Error cast call: Mod:~p Msg: ~p~n", [Mod, Msg]),
{reply, error, State}
end;
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast({login_ok, _Code}, State) ->
?TRACE("login successful~n"),
NewState = State#robot{login = 1},
{noreply, NewState};
handle_cast(login_failed, State) ->
?TRACE("login failed~n"),
{stop, normal, State};
handle_cast(startGoodsTest, State) ->
io:format("******20130916 robot handle_cast startGoodsTest socket = ~p~n ~n", [State#robot.socket]),
Pid = self(),
spawn_link(fun() -> ai(Pid) end),
{noreply, State};
handle_cast(enter_ok, State) ->
io:format("========enter_ok:~p ~p~n", [State#robot.act, State#robot.status]),
robot_task:handle(get_task, {}, State#robot.socket),%%
gen_tcp:send(State#robot.socket, pack(21000, <<>>)),
gen_server:cast(self(), {start_action}),
{noreply, State};
handle_cast({playerid, Id}, State) ->
NewState = State#robot{id = Id},
{noreply, NewState};
handle_cast({after_fight, Len, TargetBin}, State) ->
DataList = get_robot_status(Len, TargetBin, []),
case lists:keyfind(State#robot.id, 1, DataList) of
{_, CurHp} ->
case CurHp > 0 of
true ->
NewState = State;
false ->
NewState = State#robot{status = dead}
end;
_ ->
NewState = State
end,
{noreply, NewState};
handle_cast({start_action}, State) ->
if is_port(State#robot.socket) ->
%%
spawn_link(fun() -> handle(heart, a, State#robot.socket) end),
Pid = self(),
spawn_link(fun() -> ai(Pid) end),
if ?INITIAL_GM >= 1 ->
spawn(fun() -> robot_gm:handle(State) end);
true -> skip end,
erlang:send_after(1000, Pid, {random}),
{noreply, State};
true ->
?TRACE("start_action stop_1: /~p/,~n", [State]),
{stop, normal, State}
end;
handle_cast({upgrade_state, NewState}, _State) ->
%%io:format("====upgrade_state ~p~n",[NewState#robot.status]) ,
{noreply, NewState};
handle_cast({get_state_13001}, State) ->
handle(get_self_info, a, State#robot.socket),
{noreply, State};
handle_cast({init_skill_list, SkillList_ABin}, _State) ->
NewSkillList = robot_battle:make_skill_list(SkillList_ABin, []),
{noreply, _State#robot{skill_list = NewSkillList}};
handle_cast({upgrade_state_13001, [Scene, X, Y, Hp]}, State) ->
random:seed(erlang:now()),
EnterX = 20 + random:uniform(10) - 5,
EnterY = 10 + random:uniform(10) - 5,
case Hp =< 0 of
true ->
NewState = State#robot{x = EnterX, y = EnterY, scene = Scene, hp = Hp, status = dead};
%%NewState = State#robot{x=X, y=Y,scene=Scene,hp = Hp, act = run, status = dead} ;
false ->
NewState = State#robot{x = EnterX, y = EnterY, scene = Scene, hp = Hp, status = standing}
%%NewState = State#robot{x=X, y=Y,scene=Scene,hp = Hp, act = %%run, status = standing}
end,
%% io:format("========upgrade_state_13001 enter scene:~p , ~p , ~p , ~p ~n", [Scene,Hp,NewState#robot.act,NewState#robot.status]) ,
handle(enter_scene, [Scene, EnterX, EnterY], NewState#robot.socket),
%%handle(enter_scene, [Scene,X,Y] ,NewState#robot.socket),
{noreply, NewState};
handle_cast({upgrade_state_revive, [NewSceneId, ReviveX, ReviveY]}, State) ->
NewState = State#robot{status = standing, x = ReviveX, y = ReviveY},
handle(enter_scene, [NewSceneId, ReviveX, ReviveY], State#robot.socket),
{noreply, NewState};
handle_cast({upgrade_state_13099, [IdLists]}, State) ->
IdLists1 = [[State#robot.id] | IdLists],
NewState = State#robot{frda = IdLists1},
{noreply, NewState};
handle_cast({run}, State) ->
State2 = State#robot{act = run},
{noreply, State2};
handle_cast({stop}, State) ->
State2 = State#robot{act = undefined},
{noreply, State2};
handle_cast({stop, _Reason}, State) ->
?TRACE("~s_quit_2: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
{stop, normal, State};
handle_cast({get_bag_list, [Location]}, State) ->
io:format("*********20130916 robot handle_cast get_bag_list Location = ~p~n", [Location]),
{noreply, State};
%%
handle_cast({Mod, Msg}, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_cast(Msg, State) of
{noreply, NewState} when is_record(NewState, robot) ->
NewState;
_ ->
State
end;
false ->
?TRACE("Error cast call: Mod:~p Msg: ~p~n", [Mod, Msg]),
State
end,
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info({random}, State) ->
NewState = handle_action_random(State),
erlang:send_after(?RANDOM_INTERVAL, self(), {random}),
{noreply, NewState};
handle_info({stop, _Reason}, State) ->
?TRACE("~s ------ robot stop: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
{stop, normal, State};
handle_info(close, State) ->
gen_tcp:close(State#robot.socket),
{noreply, State};
%%
handle_info({Mod, Msg}, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_info(Msg, State) of
{noreply, NewState} when is_record(NewState, robot) ->
NewState;
_ ->
State
end;
false ->
?TRACE("Error msg call: Mod:~p Msg: ~p~n", [Mod, Msg]),
State
end,
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(_Reason, State) ->
?TRACE(" ----------terminate-----------~s_quit_4: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
if is_port(State#robot.socket) ->
gen_tcp:close(State#robot.socket);
true -> no_socket
end,
ok.
%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%=========================================================================
%%
%%=========================================================================
%%
login(N, Pid, Port, IP) ->
case connect_server(IP, Port) of
{ok, Socket} ->
?TRACE("~s ---connect to IP:~p Port: ~p ok...~n", [misc:time_format(now()), IP, Port]),
Accid = N,
AccName = "ROBOT" ++ integer_to_list(Accid),
handle(login, {Accid, AccName}, Socket),
spawn_link(fun() -> do_parse_packet(Socket, Pid) end),
{ok, Socket};
_Reason2 ->
?TRACE("Connect to server failed: ~p~n", [_Reason2]),
error
end.
%%
connect_server(Ip, Port) ->
gen_tcp:connect(Ip, Port, ?TCP_OPTS, 10000).
%%
async_recv(Sock, Length, Timeout) when is_port(Sock) ->
case prim_inet:async_recv(Sock, Length, Timeout) of
{error, Reason} -> throw({Reason});
{ok, Res} -> Res;
Res -> Res
end.
%% -
%%Socketsocket id
%%Client: client记录
do_parse_packet(Socket, Pid) ->
Ref = async_recv(Socket, ?HEADER_LENGTH, ?HEART_TIMEOUT),
receive
{inet_async, Socket, Ref, {ok, <<Len:16, Cmd:16>>}} ->
?TRACE("receive command: ~p, length: ~p~n", [Cmd, Len]),
BodyLen = Len - ?HEADER_LENGTH,
RecvData =
case BodyLen > 0 of
true ->
Ref1 = async_recv(Socket, BodyLen, ?TCP_TIMEOUT),
receive
{inet_async, Socket, Ref1, {ok, Binary}} ->
{ok, Binary};
Other ->
?TRACE("Data recv Error: ~p~n", [Other]),
{fail, Other}
end;
false ->
{ok, <<>>}
end,
case RecvData of
{ok, BinData} ->
case Cmd of
10000 ->
<<Code:8, _Bin1/binary>> = BinData,
case Code of
0 ->
gen_server:cast(Pid, {login_ok, 0}),
<<_:32, PlayerId:64, _Bin2/binary>> = _Bin1,
handle(enter_player, {PlayerId}, Socket),
ok;
1 ->
<<Accid:32, _Bin2/binary>> = _Bin1,
gen_server:cast(Pid, {login_ok, 1}),
handle(select_role, Accid, Socket),
ok;
_ ->
gen_server:cast(Pid, login_failed),
?TRACE("login failed: Code: ~p~n", [Code]),
failed
end;
10003 ->
<<Code:8, PlayerId:64, _Bin/binary>> = BinData,
?TRACE("10003: Code: ~p PlayerId~p~n", [Code, PlayerId]),
if Code =:= 1 ->
handle(enter_player, {PlayerId}, Socket),
gen_server:cast(Pid, {playerid, PlayerId});
true ->
gen_server:cast(Pid, {stop})
end;
10004 ->
<<Code:8, _Bin/binary>> = BinData,
if
Code =/= 0 ->
%%
gen_server:cast(Pid, {get_state_13001});
true ->
gen_server:cast(Pid, {stop})
end;
13001 ->
?TRACE("hahhaha ~n", []),
NewData = zlib:uncompress(BinData),
<<_Uid:64, _Gender:8, _Level:8, _Career:8, _Speed:8, SceneId:16, X:8, Y:8, Hp:32, _Other/binary>> = NewData,
%%
gen_server:cast(Pid, {upgrade_state_13001, [SceneId, X, Y, Hp]}),
ok;
12001 ->
<<SceneId:16, _Other/binary>> = BinData,
%% io:format("========receive 12001:~p ~n", [SceneId]) ,
if
SceneId > 0 ->
gen_tcp:send(Socket, pack(12005, <<>>)),
%%
gen_server:cast(Pid, enter_ok);
true ->
gen_server:cast(Pid, {stop})
end,
ok;
12002 -> %%
NewData = zlib:uncompress(BinData),
State = gen_server:call(Pid, {get_state}),
robot_battle:reflesh_monster(State#robot.acid, NewData);
20003 -> %%
?TRACE("==20003 ~p~n", [BinData]),
<<_Id1:32, _Hp1:32, _Mp1:32, _Sid1:32, _Slv1:8, _X1:8, _Y1:8, _:32, DLen:16, TarBin/binary>> = BinData,
gen_server:cast(Pid, {after_fight, DLen, TarBin}),
ok;
21000 ->
?TRACE("==21000 ~p~n", [BinData]),
NewData = zlib:uncompress(BinData),
<<_:16, SkillList_ABin/binary>> = NewData,
gen_server:cast(Pid, {init_skill_list, SkillList_ABin});
12021 ->
<<Code:8, NewSceneId:16, ReviveX:8, ReviveY:8, _Other/binary>> = BinData,
case Code of
1 ->
gen_server:cast(Pid, {upgrade_state_revive, [NewSceneId, ReviveX, ReviveY]});
_ ->
gen_server:cast(Pid, {stop})
end,
ok;
10007 ->
<<_Code:8>> = BinData,
?TRACE("==10007 ~p~n", [_Code]),
ok;
30006 ->
NewData = zlib:uncompress(BinData),
<<DataLen:16, Data/binary>> = NewData,
TaskList = robot_task:parse_task_data(Data, []),
gen_server:call(Pid, {upgrade_state_30006, TaskList}),
ok;
_Chat when _Chat >= 11000 andalso _Chat < 12000 ->
skip;
%% robot_chat:do_parse_packet(Socket, Pid, Cmd, BinData);
_Guild when _Guild >= 40000 andalso _Guild < 41000 ->
?TRACE("==_Guild= ~p~n", [_Guild]),
robot_guild:do_parse_packet(Socket, Pid, Cmd, BinData);
%no_action
13021 ->%%
<<GuildId:32, _GuildName_RestBin/binary>> = BinData,
{GuildName, _GuildName_DoneBin} = pt:read_string(_GuildName_RestBin),
<<Position:8>> = _GuildName_DoneBin,
gen_server:cast(Pid, {refresh_robot_guild_state, [GuildId, Position]});
15002 ->
io:format("******20130916 robot recv 15002 ~n"),
gen_server:cast(Pid, {get_bag_list, [0]});
_ ->
no_action
end,
do_parse_packet(Socket, Pid);
{fail, _} ->
[{1, Num}] = ets:lookup(off_line_static, 1),
NewNum = Num + 1,
ets:insert(off_line_static, {1, NewNum}),
?TRACE("do_parse_packet total off ~p recv data failed:/~p/~p/~n~p~n", [NewNum, Socket, Pid, RecvData]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_1})
end;
%%
{inet_async, Socket, Ref, {error, timeout}} ->
io:format("do_parse_packet timeout:/~p/~p/~n", [Socket, Pid]),
do_parse_packet(Socket, Pid);
%%
Reason ->
[{1, Num}] = ets:lookup(off_line_static, 1),
NewNum = Num + 1,
ets:insert(off_line_static, {1, NewNum}),
io:format("do_parse_packet: total off ~p Error Reason:/~p/~p/~n", [NewNum, Socket, Reason]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_3})
end.
%%
handle_action_random(State) ->
Actions = ?RANDOM_MODULE,
if Actions =/= [] ->
Action = lists:nth(random:uniform(length(Actions)), Actions),
Module = list_to_atom(lists:concat(["robot_", Action])),
case catch Module:handle(State) of
NewState when is_record(NewState, robot) ->
NewState;
_Error ->
io:format("ERROR: ~p~n", [_Error]),
State
end;
true ->
State
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
handle(heart, _, Socket) ->
case gen_tcp:send(Socket, pack(10006, <<>>)) of
ok ->
sleep(24 * 1000),
handle(heart, a, Socket);
_ ->
error
end;
%%
handle(login, {Accid, AccName}, Socket) ->
?TRACE("sending login request entry socket: ~p ~p ~p~n", [Accid, AccName, Socket]),
AccStamp = 1273027133,
Tick = integer_to_list(Accid) ++ AccName ++ integer_to_list(AccStamp) ++ ?TICKET,
TickMd5 = util:md5(Tick),
TickMd5Bin = list_to_binary(TickMd5),
TLen = byte_size(TickMd5Bin),
AccNameLen = byte_size(list_to_binary(AccName)),
AccNameBin = list_to_binary(AccName),
Data = <<9999:16, Accid:32, AccStamp:32, AccNameLen:16, AccNameBin/binary, TLen:16, TickMd5Bin/binary>>,
?TRACE("sending login request: ~p ~p~n", [Accid, AccName]),
gen_tcp:send(Socket, pack(10000, Data)),
ok;
%%
handle(select_role, Accid, Socket) ->
NickName = "GUEST" ++ integer_to_list(Accid),
NameBin = list_to_binary(NickName),
TLen = byte_size(NameBin),
random:seed(erlang:now()),
Gender = random:uniform(2),
Career = random:uniform(3),
StrOsVersion = pt:pack_string("2.3.4"),
Device = pt:pack_string("test"),
Screen = pt:pack_string("test"),
gen_tcp:send(Socket, pack(10003, <<9999:16, Career:8, Gender:8, TLen:16, NameBin/binary, 0:8, StrOsVersion/binary, Device/binary, 0:8, 0:8, 0:8, Screen/binary>>)),
ok;
%%
handle(enter_player, {PlayerId}, Socket) ->
StrOsVersion = pt:pack_string("2.3.4"),
Device = pt:pack_string("test"),
Screen = pt:pack_string("test"),
%0:8,StrOsVersion/binary,Device/binary,0:8,Screen/binary,0:8,0:8
gen_tcp:send(Socket, pack(10004, <<9999:16, PlayerId:64, 30:8, 20:8, 0:8, StrOsVersion/binary, Device/binary, 0:8, 0:8, 0:8, Screen/binary>>)),
ok;
%%
handle(run, {DestX, DestY}, Socket) ->
gen_tcp:send(Socket, pack(12011, <<DestX:16, DestY:16>>));
%%
handle(broad_path, {DestX, DestY, Path}, Socket) ->
Len = length(Path),
Fun = fun({X, Y}) ->
<<X:16, Y:16>>
end,
MoveBin = tool:to_binary([Fun(M) || M <- Path]),
gen_tcp:send(Socket, pack(12010, <<DestX:16, DestY:16, Len:16, MoveBin/binary>>));
%% %%ai模式跑步
%% handle(run, {X,Y, SX, SY}, Socket) ->
%% ?TRACE("----running:[~p][~p]~n",[X,Y]),
%% gen_tcp:send(Socket, pack(12001, <<X:8, Y:8, SX:8, SY:8>>));
%%
handle(enter_scene, [SceneId, Posx, Posy], Socket) ->
%% Posx = random:uniform(30) ,
%% Posy = random:uniform(20) ,
%%io:format("========handle(enter_scene:~p ~n", [SceneId]) ,
gen_tcp:send(Socket, pack(12001, <<SceneId:16, Posx:16, Posy:16>>));
%%
handle(undefined, a, _Socket) ->
ok;
%%
handle(get_player_info, Id, Socket) ->
gen_tcp:send(Socket, pack(13004, <<Id:16>>));
%%
handle(get_self_info, _, Socket) ->
?TRACE("get_self_info: sending 13001~n"),
gen_tcp:send(Socket, pack(13001, <<>>));
%%
handle(revive, _, Socket) ->
%% gen_tcp:send(Socket, pack(20004, <<3:8>>)),
%% Action = tool:to_binary("-加血 100000"),
%% ActionLen= byte_size(Action),
%% Data = <<ActionLen:16, Action/binary>>,
%% Packet = pack(11020, Data),
%% gen_tcp:send(Socket, Packet);
io:format("====handle(revive ~p~n", [revive]),
gen_tcp:send(Socket, pack(12021, <<0:16>>));
handle(_Handle, _Data, Socket) ->
?TRACE("handle error: /~p/~p/~n", [_Handle, _Data]),
{reply, handle_no_match, Socket}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%
read_string(Bin) ->
case Bin of
<<Len:16, Bin1/binary>> ->
case Bin1 of
<<Str:Len/binary-unit:8, Rest/binary>> ->
{binary_to_list(Str), Rest};
_R1 ->
{[], <<>>}
end;
_R1 ->
{[], <<>>}
end.
random_sleep(T) ->
N = random:uniform(T),
timer:sleep(N * 100).
sleep(T) ->
receive
after T -> ok
end.
for(Max, Max, _F) ->
[];
for(Min, Max, F) ->
[F(Min) | for(Min + 1, Max, F)].
for(Max, Max, _F, X) ->
X;
for(Min, Max, F, X) ->
F(X),
for(Min + 1, Max, F, X).
sleep_send({T, S}) ->
receive
after T -> handle(run, a, S)
end.
get_pid(Name) ->
case whereis(Name) of
undefined ->
err;
Pid -> Pid
end.
ping(Node) ->
case net_adm:ping(Node) of
pang ->
?TRACE("ping ~p error.~n", [Node]);
pong ->
?TRACE("ping ~p success.~n", [Node]);
_Error ->
?TRACE("error: ~p ~n", [_Error])
end.
get_robot_status(0, _TargetBin, DataList) ->
DataList;
get_robot_status(Len, TargetBin, DataList) ->
<<_:8, UId:64, CurHp:32, _:32, _:32, _:32, _:8, OtherBin/binary>> = TargetBin,
NewDataList = DataList ++ [{UId, CurHp}],
get_robot_status(Len - 1, OtherBin, NewDataList).
%%
ai(Pid) ->
%%
%% gen_server:cast(Pid,{get_state_13001}),
Random_interval = random:uniform(1000) + 100,
sleep(Random_interval),
State = gen_server:call(Pid, {get_state}),
io:format("========ai(Pid):~p ~p~n", [State#robot.act, State#robot.status]),
case State#robot.act of
run ->
case State#robot.status of
standing ->
io:format("====ai(Pid)standing ~p~n", [standing]),
State2 = robot_battle:stand_call_back(State),
gen_server:cast(State2#robot.pid, {upgrade_state, State2}),
sleep(800);
running ->
io:format("====ai(Pid)running ~p~n", [running]),
if State#robot.step =/= [] -> %%
[{NextX, NextY} | LeftPath] = State#robot.step,
handle(run, {NextX, NextY}, State#robot.socket),
State2 = State#robot{x = NextX, y = NextY, step = LeftPath, status = running},
gen_server:cast(State#robot.pid, {upgrade_state, State2});
true ->
State2 = State#robot{status = standing}, %%,
gen_server:cast(State#robot.pid, {upgrade_state, State2}) %%
end;
dead ->
%io:format("====ai(Pid)dead ~p~n",[dead]) ,
handle(revive, a, State#robot.socket); %%
fighting ->
%io:format("====ai(Pid)fighting ~p~n",[fighting]) ,
robot_battle:begin_attrack(State),
sleep(800);
_ ->
?TRACE("robot status error!~n")
end,
ai(Pid);
test_goods ->
case ?START_ROBOT_GOODS of
true ->
io:format("***********20130916 test_goods ~n"),
robot_goods:start_robot_test(State),
sleep(800),
ai(Pid);
_ ->
ok
end;
do_task ->
TargetTask = robot_task:get_rand_taskPid(State#robot.task_list),
%%RandTid = rand(1,?MAX_TASK_NUM),
if
is_record(TargetTask, task_list) ->
RandAction = rand(1, 4),
if
RandAction =:= 1 ->
robot_task:accept_task(State#robot.socket, TargetTask#task_list.id);
RandAction =:= 2 ->
robot_task:finish_task(State#robot.socket, rand(1, ?MAX_TASK_NUM));
RandAction =:= 3 ->
robot_task:submit_task(State#robot.socket, TargetTask#task_list.id);
true ->
robot_task:handle(get_task, {}, State#robot.socket)%%
end;
true ->
skip
end,
ai(Pid);
chat ->
{X, Y, Z} = erlang:now(),
LastChatTime = get(last_chat_time),
if
LastChatTime == undefined ->
IsHandle = true;
true ->
io:format("Y = ~p LastChatTime = ~p~n", [Y, LastChatTime]),
if
Y - LastChatTime > 5 ->
IsHandle = true;
true ->
IsHandle = false
end
end,
if
IsHandle == true ->
robot_chat:handle(State),
put(last_chat_time, Y);
true ->
skip
end,
ai(Pid);
mail ->
robot_mail:handle(State),
ai(Pid);
mount ->
skip,
ai(Pid);
openfunc ->
skip,
ai(Pid);
newbie ->
skip,
ai(Pid);
_ ->
ok
end.
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.
rand(Same, Same) -> Same;
rand(Min, Max) ->
M = Min - 1,
if
Max - M =< 0 ->
0;
true ->
random:uniform(Max - M) + M
end.
%%@spec
make_move_path(StartX, StartY, EndX, EndY, Path) ->
if
StartX =:= EndX andalso StartY =:= EndY ->
Path;
StartX =:= EndX ->
NextX = StartX,
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
StartY =:= EndY ->
NextX = make_next_step(StartX, EndX),
NextY = EndY,
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
true ->
NextX = make_next_step(StartX, EndX),
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath)
end.
make_next_step(Current, Target) ->
if Current > Target ->
if Current - Target > 1 ->
Current - 1;
true ->
Target
end;
true ->
if Target - Current > 1 ->
Current + 1;
true ->
Target
end
end.
rand(Min) when Min =< 0 ->
0;
rand(Max) ->
case get("rand_seed") of
undefined ->
RandSeed = now(),
random:seed(RandSeed),
put("rand_seed", RandSeed);
_ -> skip
end,
random:uniform(Max).

+ 103
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot.hrl Dosyayı Görüntüle

@ -0,0 +1,103 @@
%%% -------------------------------------------------------------------
%%% Author:
%%% Description :
%%% Created :
%%% -------------------------------------------------------------------
-include("common.hrl").
-include("record.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
%%
-define(GATEWAY_ADD, "192.168.43.135").
-define(GATEWAY_PORT, 7777).
%% -define(SERVER_ADD,"192.168.51.175").
%% -define(SERVER_PORT,7777).
-define(SERVER_ADD, "192.168.43.135").
-define(SERVER_PORT, 7788).
-define(ACTION_SPEED_CONTROL, 10).
-define(ACTION_INTERVAL, ?ACTION_SPEED_CONTROL * 1000). %
-define(ACTION_MIN, 3000). %
%%robot_chat,
-define(RANDOM_MODULE, [guild]).
-define(RANDOM_INTERVAL, 1000). %%()
-define(MAX_TASK_NUM, 200). %%
%%1, GM指令加钱等
-define(INITIAL_GM, 1).
%%TCP Socket的参数
-define(TCP_OPTS, [
binary,
{packet, 0}, % no packaging
{reuseaddr, true}, % allow rebind without waiting
{nodelay, false},
{delay_send, true},
{active, false},
{exit_on_close, false}
]).
%%
%% -undefine行
%% -define(debug,1).
%-undefine(debug).
-ifdef(debug).
-define(TRACE(Str), io:format(Str)).
-define(TRACE(Str, Args), io:format(Str, Args)).
% unicode版
-define(TRACE_W(Str), io:format("~ts", [list_to_binary(io_lib:format(Str, []))])).
-define(TRACE_W(Str, Args), io:format("~ts", [list_to_binary(io_lib:format(Str, Args))])).
-else.
-define(TRACE(Str), void).
-define(TRACE(Str, Args), void).
-define(TRACE_W(Str), void).
-define(TRACE_W(Str, Args), void).
-endif.
%%
-record(robot, {
orig_n,
login,
acid, %%account id
accname, %%account id
socket, %%socket
pid, %%process id
rpid,
count = 0,
x, %%x坐标
y, %%y坐标
scene,
tox,
toy,
hp,
id, %% ID
act, %%
status, %%
dstScene,
skill_list = [],
attr_target = 0,
step,
guild, %%0
guild_post, %%1
frda, %%
bkda, %% ,
sgda, %%
task_list,
task_cd = 0,
move_cd = 0,
skill_cd = 0,
completeId = 0
}).
-record(task_list, {
id,
taskId,
state,
mark,
grade
}).

+ 131
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_battle.erl Dosyayı Görüntüle

@ -0,0 +1,131 @@
%% @author Administrator
%% @doc @todo Add description to robot_battle.
-module(robot_battle).
-include("robot.hrl").
%% ====================================================================
%% API functions
%% ====================================================================
-compile(export_all).
%--------------------------
%
%--------------------------
%
make_skill_list(<<SkillId:8, _:8, Rest/binary>>, List) ->
make_skill_list(Rest, [SkillId | List]);
make_skill_list(<<>>, List) ->
List.
%
reflesh_monster(AId, BinData) ->
{ok, [_, _, MonList, _]} = read(BinData),
NewMonsterList = lists:map(fun(MonItem) ->
[MonId, _, PosX, PosY, _, _, CurHp, MaxHp, _, _, _] = MonItem,
{MonId, PosX, PosY, CurHp, MaxHp}
end
, MonList),
ets:insert(player_mon_info, {AId, NewMonsterList}).
%%
make_default_path(State) ->
random:seed(erlang:now()),
DestX = State#robot.x + random:uniform(10) - 3,
DestY = State#robot.y + random:uniform(10) - 3,
Path = robot:make_move_path(State#robot.x, State#robot.y, DestX, DestY, []),
robot:handle(broad_path, {DestX, DestY, Path ++ [{DestX, DestY}]}, State#robot.socket),
State#robot{tox = DestX, toy = DestY, step = Path, status = running}.
%%
make_battle_path(State) ->
case ets:lookup(player_mon_info, State#robot.acid) of
[] ->
make_default_path(State);
[{_, []}] ->
make_default_path(State);
[{_, MonsterLists}] ->
Len = length(MonsterLists),
random:seed(erlang:now()),
Index = random:uniform(Len),
MonInfo = lists:nth(Index, MonsterLists),
{MonId, PosX, PosY, _, _} = MonInfo,
DestX = PosX + random:uniform(5),
DestY = PosY + random:uniform(5),
Path = robot:make_move_path(State#robot.x, State#robot.y, DestX, DestY, []),
robot:handle(broad_path, {DestX, DestY, Path ++ [{DestX, DestY}]}, State#robot.socket),
State#robot{tox = DestX, toy = DestY, step = Path, status = running, attr_target = MonId}
end.
%%
stand_call_back(State) ->
case State#robot.attr_target of
0 ->
make_battle_path(State);
TargetId ->
case ets:lookup(player_mon_info, State#robot.acid) of
[] ->
make_battle_path(State);
[{_, List}] ->
case lists:keyfind(TargetId, 1, List) of
{_, PosX, PosY, CurHp, _} ->
random:seed(erlang:now()),
Flag = random:uniform(10),
if CurHp > 0 andalso abs(State#robot.x - PosX) =< 2 andalso abs(State#robot.y - PosY) =< 2 andalso Flag > 7 ->
begin_attrack(State),
State#robot{status = fighting};
true ->
make_battle_path(State#robot{attr_target = 0})
end;
_ ->
make_battle_path(State#robot{attr_target = 0})
end
end
end.
%%
begin_attrack(State) ->
SkillId = get_random_skill(State),
MonId = State#robot.attr_target,
gen_tcp:send(State#robot.socket, robot:pack(21003, <<SkillId:8, 0:8, 123456:32, 0:16, 0:16, 2:8, MonId:32>>)).
%%使
get_random_skill(State) ->
case State#robot.skill_list of
[] ->
0;
List ->
Len = length(List),
Index = random:uniform(Len),
lists:nth(Index, List)
end.
%% ====================================================================
%%
%% ====================================================================
%%12002
read(<<ScenedId:16, BinData/binary>>) ->
<<PlayerListLen:16, PlayerListBin/binary>> = BinData,
Fun_PlayerList = fun(_Idx, {RestBin, ResultList}) ->
<<PosX:16, PosY:16, UId:64, _NmBin_RestBin/binary>> = RestBin,
{NmBin, _NmBin_DoneBin} = pt:read_string(_NmBin_RestBin),
<<Stts:8, Sex:8, Crr:8, CurHp:32, MaxHp:32, Magic:32, MagicMax:32, Weapon:32, Armor:32, Fashion:32, WwaponAcc:32, Wing:32, Mount:32, WeaponStrenLv:8, ArmorStrenLv:8, FashionStrenLv:8
, WaponAccStrenLv:8, WingStrenLv:8, PetStatus:8, PetQualityLv:8, PetFacade:16, _:16, _PetName_RestBin/binary>> = _NmBin_DoneBin,
{PetName, _PetName_DoneBin} = pt:read_string(_PetName_RestBin),
<<Level:8, _:8, _:8, _:16, _:8, _:32, GulidRestBin/binary>> = _PetName_DoneBin,
{_, _PlayerList_RestBin} = pt:read_string(GulidRestBin),
{_PlayerList_RestBin, [[PosX, PosY, UId, NmBin, Stts, Sex, Crr, CurHp, MaxHp, Magic, MagicMax, Weapon, Armor, Fashion, WwaponAcc, Wing, Mount, WeaponStrenLv, ArmorStrenLv, FashionStrenLv, WaponAccStrenLv, WingStrenLv, PetStatus, PetQualityLv, PetFacade, PetName, Level] | ResultList]}
end,
{_PlayerList_DoneBin, PlayerList} = lists:foldl(Fun_PlayerList, {PlayerListBin, []}, lists:seq(1, PlayerListLen)),
<<MonListLen:16, MonListBin/binary>> = _PlayerList_DoneBin,
Fun_MonList = fun(_Idx, {RestBin, ResultList}) ->
<<MonId:32, MonTId:32, PosX:16, PosY:16, Towards:16, Stts:8, CurHp:32, MaxHp:32, Magic:32, MagicMax:32, _:8, _:16, _BuffList_RestBin/binary>> = RestBin,
<<BuffListLen:16, BuffListBin/binary>> = _BuffList_RestBin,
Fun_BuffList = fun(_Idx, {RestBin1, ResultList}) ->
<<BuffId:16, ExpirTime:32, _BuffList_RestBin/binary>> = RestBin1,
{_BuffList_RestBin, [[BuffId, ExpirTime] | ResultList]}
end,
{_BuffList_DoneBin, BuffList} = lists:foldl(Fun_BuffList, {BuffListBin, []}, lists:seq(1, BuffListLen)),
{_BuffList_DoneBin, [[MonId, MonTId, PosX, PosY, Towards, Stts, CurHp, MaxHp, Magic, MagicMax, lists:reverse(BuffList)] | ResultList]}
end,
{_MonList_DoneBin, MonList} = lists:foldl(Fun_MonList, {MonListBin, []}, lists:seq(1, MonListLen)),
<<DropListLen:16, DropListBin/binary>> = _MonList_DoneBin,
Fun_DropList = fun(_Idx, {RestBin2, ResultList}) ->
<<DropId:32, MonId:32, GoodsId:32, GoodsNum:32, DropX:16, DropY:16, EftTime:16, _DropList_RestBin/binary>> = RestBin2,
{_DropList_RestBin, [[DropId, MonId, GoodsId, GoodsNum, DropX, DropY, EftTime] | ResultList]}
end,
{_DropList_DoneBin, DropList} = lists:foldl(Fun_DropList, {DropListBin, []}, lists:seq(1, DropListLen)),
{ok, [ScenedId, lists:reverse(PlayerList), lists:reverse(MonList), lists:reverse(DropList)]}.

+ 91
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_chat.erl Dosyayı Görüntüle

@ -0,0 +1,91 @@
-module(robot_chat).
-compile(export_all).
%-include("common.hrl").
-include("robot.hrl").
%%---------------------- ----------------------
-define(AUTO_CHAT_LIST, [
<<"伟大的中国共产党">>,
<<"跟随失败,队长不能自己跟随自己.">>,
<<"石家庄在下雪">>,
<<"是鹅毛大雪">>,
<<"像是宰了一群鹅">>,
<<"拔了好多鹅毛">>,
<<"也不装进袋子里">>,
<<"像是羽绒服破了">>,
<<"也不缝上">>,
<<"北京也在下雪">>,
<<"不是鹅毛大雪">>,
<<"是白沙粒">>,
<<"有些像白砂糖">>,
<<"有些像碘盐">>,
<<"廊坊夹在石家庄和北京之间">>,
<<"廊坊什么雪也不下">>,
<<"看不到鹅毛">>,
<<"也看不到白砂糖和碘盐">>,
<<"廊坊只管阴着天">>,
<<"像一个女人吊着脸">>,
<<"说话尖酸、刻薄">>,
<<"还冷飕飕的">>,
<<"汉皇①重色思倾国,御宇②多年求不得。杨家有女初长成,养在深闺人未识。">>,
<<"天生丽质难自弃,一朝选在君王侧。回眸一笑百媚生,六宫粉黛无颜色。 ">>,
<<"春寒赐浴华清池,温泉水滑洗凝脂。侍儿扶起娇无力,始是新承恩泽时。 ">>,
<<"云鬓花颜金步摇,芙蓉帐暖度春宵。春宵苦短日高起,从此君王不早朝。 ">>,
<<"承欢侍宴无闲暇,春从春游夜专夜。 后宫佳丽三千人,三千宠爱在一身。 ">>,
<<"金屋妆成娇侍夜,玉楼宴罢醉和春。姊妹弟兄皆列土,可怜光彩生门户③。">>,
<<"遂令天下父母心,不重生男重生女。骊宫高处入青云,仙乐风飘处处闻。 ">>,
<<"缓歌谩舞凝丝竹,尽日君王看不足。渔阳鼙鼓④动地来,惊破霓裳羽衣曲。">>,
<<"九重城阙烟尘生,千乘万骑西南行。翠华摇摇行复止,西出都门百余里。 ">>,
<<"六军不发无奈何,宛转蛾眉马前死。花钿委地无人收,翠翘金雀玉搔头。 ">>,
<<"君王掩面救不得,回看血泪相和流。黄埃散漫风萧索,云栈萦纡登剑阁。 ">>,
<<"峨嵋山下少人行,旌旗无光日色薄⑤。蜀江水碧蜀山青,圣主朝朝暮暮情。 ">>,
<<"行宫见月伤心色,夜雨闻铃肠断声。 天旋地转回龙驭,到此踌躇不能去。 ">>,
<<"马嵬坡下泥土中,不见玉颜空死处。君臣相顾尽沾衣,东望都门信⑥马归。">>,
<<"归来池苑皆依旧,太液芙蓉未央柳。芙蓉如面柳如眉,对此如何不泪垂。 ">>,
<<"春风桃李花开日,秋雨梧桐叶落时。 西宫南内多秋草,落叶满阶红不扫。 ">>,
<<"梨园弟子白发新,椒房阿监青娥老。夕殿萤飞思悄然,孤灯挑尽未成眠。 ">>,
<<"迟迟钟鼓初长夜,耿耿星河欲曙天。 鸳鸯瓦冷霜华重,翡翠衾寒谁与共。 ">>,
<<"悠悠生死别经年,魂魄不曾来入梦。 临邛道士鸿都客,能以精诚致魂魄。 ">>,
<<"为感君王辗转思,遂教方士殷勤觅。排空驭气奔如电,升天入地求之遍。 ">>,
<<"上穷碧落⑦下黄泉,两处茫茫皆不见。忽闻海上有仙山,山在虚无缥渺间。 ">>,
<<"楼阁玲珑五云起,其中绰约多仙子。中有一人字太真,雪肤花貌参差是。 ">>,
<<"金阙西厢叩玉扃⑧,转教小玉报双成。闻道汉家天子使,九华帐里梦魂惊。 ">>,
<<"揽衣推枕起徘徊,珠箔银屏迤逦开⑨。云鬓半偏新睡觉,花冠不整下堂来。 ">>,
<<"风吹仙袂飘飘举,犹似霓裳羽衣舞。玉容寂寞泪阑干⑩,梨花一枝春带雨。">>,
<<"含情凝睇谢君王,一别音容两渺茫。昭阳殿里恩爱绝,蓬莱宫中日月长。 ">>,
<<"回头下望人寰处,不见长安见尘雾。惟将旧物表深情,钿合金钗寄将去。 ">>,
<<"钗留一股合一扇,钗擘黄金合分钿。但教心似金钿坚,天上人间会相见。 ">>,
<<"临别殷勤重寄词,词中有誓两心知。 七月七日长生殿,夜半无人私语时。 ">>,
<<"在天愿作比翼鸟,在地愿为连理枝。 天长地久有时尽,此恨绵绵无绝期。">>,
<<"明年上国富春光">>,
<<"朝廷自昔选才良">>,
<<"时平空山老壮士">>,
<<"代言直似汉文章">>,
<<"生来自秀培来秀">>,
<<"日移花影上窗香">>,
<<"快意一时荷叶雨">>,
<<"乐来一顾遇孙阳">>,
<<"メールアドレス">>,
<<"バックアップファイルのパスを入力して下さい">>,
<<"項目を埋めて Jabber User を検索して下さい">>,
<<"ユーザー統計の取得">>,
<<"は提携が変更されたためキックされました">>,
<<"该点不可行走!">>
]).
handle(State) ->
io:format("chat handle"),
Cmds = [11001],
Chat_List = ?AUTO_CHAT_LIST,
Msg = tool:to_list(lists:nth(random:uniform(length(Chat_List)), Chat_List)),
Cmd = lists:nth(random:uniform(length(Cmds)), Cmds),
{ok, BinData} = ptr_11:write(Cmd, [1, Msg]),
gen_tcp:send(State#robot.socket, BinData),
State.
do_parse_packet(_Socket, _Pid, Cmd, BinData) ->
{ok, _Result} = ptr_11:read(Cmd, BinData),
?TRACE("Cmd: ~p, Result: ~p~n", [Cmd, _Result]).

+ 589
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_gateway.erl Dosyayı Görüntüle

@ -0,0 +1,589 @@
%%% -------------------------------------------------------------------
%%% Author: SMXX
%%% Description :
%%% Created :
%%% -------------------------------------------------------------------
-module(robot_gateway).
-behaviour(gen_server).
-include("robot.hrl").
-compile(export_all).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%%%
%%% API
start() ->
start(20000, 10000),
ok.
%%StartId AccountID
%%Num int
%%Mod 1 ,2
start(StartId, Num) ->
sleep(100),
F = fun(N) ->
io:format("start robot-~p~n", [N]),
sleep(200),
start_link(StartId + N)
end,
for(0, Num, F),
ok.
%% ROBOT
start_link(N) ->
case gen_server:start(?MODULE, [N], []) of
{ok, _Pid} ->
io:format("--robot~p start finish!-~n", [N]);
%gen_server:cast(Pid, {start_action});
_ ->
fail
end.
%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% --------------------------------------------------------------------
%%
init([N]) ->
process_flag(trap_exit, true),
Pid = self(),
Robot = #robot{login = 0,
acid = N,
id = 0,
pid = Pid
},
erlang:send_after(10, self(), {'action'}),
%%
{ok, Robot}.
%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call({get_state}, _From, State) ->
{reply, State, State};
%%
handle_call({Mod, Msg}, _From, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_call(State, Msg) of
{reply, Reply, NewState} when is_record(NewState, robot) ->
{reply, Reply, NewState};
_ ->
{reply, noreply, State}
end;
false ->
io:format("Error cast call: Mod:~p Msg: ~p~n", [Mod, Msg]),
{reply, error, State}
end;
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast({gateway_fallback}, State) ->
io:format("====gateway_fallback: ~p~n", [State#robot.pid]),
gen_tcp:close(State#robot.socket),
exit(State#robot.rpid, nomal),
erlang:send_after(1000, self(), {'action'}),
{noreply, State#robot{socket = []}};
handle_cast(login_failed, State) ->
io:format("login failed~n"),
{stop, normal, State};
handle_cast({playerid, Id}, State) ->
NewState = State#robot{id = Id},
{noreply, NewState};
handle_cast(enter_ok, State) ->
NewState = State#robot{act = run, status = standing},
gen_server:cast(self(), {start_action}),
{noreply, NewState};
handle_cast({after_fight, Len, TargetBin}, State) ->
DataList = get_robot_status(Len, TargetBin, []),
case lists:keyfind(State#robot.id, 1, DataList) of
{_, CurHp} ->
case CurHp > 0 of
true ->
NewState = State;
false ->
NewState = State#robot{status = dead}
end;
_ ->
NewState = State
end,
{noreply, NewState};
handle_cast({upgrade_state, NewState}, _State) ->
{noreply, NewState};
handle_cast({get_state_13001}, State) ->
handle(get_self_info, a, State#robot.socket),
{noreply, State};
handle_cast({upgrade_state_13001, [Scene, X, Y]}, State) ->
NewState = State#robot{x = X, y = Y, scene = Scene},
handle(enter_scene, [Scene], State#robot.socket),
{noreply, NewState};
handle_cast({upgrade_state_revive, []}, State) ->
NewState = State#robot{status = standing},
{noreply, NewState};
handle_cast({upgrade_state_13099, [IdLists]}, State) ->
IdLists1 = [[State#robot.id] | IdLists],
NewState = State#robot{frda = IdLists1},
{noreply, NewState};
handle_cast({run}, State) ->
State2 = State#robot{act = run},
{noreply, State2};
handle_cast({stop}, State) ->
State2 = State#robot{act = undefined},
{noreply, State2};
handle_cast({stop, _Reason}, State) ->
io:format("~s_quit_2: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
{stop, normal, State};
%%
handle_cast({Mod, Msg}, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_cast(Msg, State) of
{noreply, NewState} when is_record(NewState, robot) ->
NewState;
_ ->
State
end;
false ->
io:format("Error cast call: Mod:~p Msg: ~p~n", [Mod, Msg]),
State
end,
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info({'action'}, State) ->
case connect_server(?GATEWAY_ADD, ?GATEWAY_PORT) of
{ok, Socket} ->
Accid = State#robot.acid,
AccName = "ROBOT" ++ integer_to_list(Accid),
handle(login_gateway, {Accid, AccName}, Socket),
RPid = spawn_link(fun() -> do_parse_packet(Socket, State#robot.pid) end),
NewState = State#robot{socket = Socket, rpid = RPid},
{ok, Socket};
_Reason2 ->
NewState = State,
io:format("Connect to server failed: ~p~n", [_Reason2]),
error
end,
{noreply, NewState};
handle_info({random}, State) ->
NewState = handle_action_random(State),
erlang:send_after(?RANDOM_INTERVAL, self(), {random}),
{noreply, NewState};
handle_info({stop, _Reason}, State) ->
io:format("~s ------ robot stop: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
{stop, normal, State};
handle_info(close, State) ->
gen_tcp:close(State#robot.socket),
{noreply, State};
%%
handle_info({Mod, Msg}, State) ->
case lists:member(Mod, ?RANDOM_MODULE) of
true ->
Module = list_to_atom(lists:concat(["robot_", Mod])),
case catch Module:handle_info(Msg, State) of
{noreply, NewState} when is_record(NewState, robot) ->
NewState;
_ ->
State
end;
false ->
io:format("Error msg call: Mod:~p Msg: ~p~n", [Mod, Msg]),
State
end,
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(_Reason, State) ->
io:format(" ----------terminate-----------~s_quit_4: /~p/~p/~p/,~n", [misc:time_format(now()), State#robot.acid, State#robot.id, _Reason]),
if is_port(State#robot.socket) ->
gen_tcp:close(State#robot.socket);
true -> no_socket
end,
ok.
%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%=========================================================================
%%
%%=========================================================================
%%
login(N, Pid) ->
case connect_server(?GATEWAY_ADD, ?GATEWAY_PORT) of
{ok, Socket} ->
Accid = N,
AccName = "ROBOT" ++ integer_to_list(Accid),
handle(login_gateway, {Accid, AccName}, Socket),
spawn_link(fun() -> do_parse_packet(Socket, Pid) end),
{ok, Socket};
_Reason2 ->
io:format("Connect to server failed: ~p~n", [_Reason2]),
error
end.
%%
connect_server(Ip, Port) ->
gen_tcp:connect(Ip, Port, ?TCP_OPTS, 10000).
%%
async_recv(Sock, Length, Timeout) when is_port(Sock) ->
case prim_inet:async_recv(Sock, Length, Timeout) of
{error, Reason} -> throw({Reason});
{ok, Res} -> Res;
Res -> Res
end.
%% -
%%Socketsocket id
%%Client: client记录
do_parse_packet(Socket, Pid) ->
Ref = async_recv(Socket, ?HEADER_LENGTH, ?HEART_TIMEOUT),
receive
{inet_async, Socket, Ref, {ok, <<Len:16, Cmd:16>>}} ->
BodyLen = Len - ?HEADER_LENGTH,
RecvData =
case BodyLen > 0 of
true ->
Ref1 = async_recv(Socket, BodyLen, ?TCP_TIMEOUT),
receive
{inet_async, Socket, Ref1, {ok, Binary}} ->
{ok, Binary};
Other ->
io:format("Data recv Error: ~p~n", [Other]),
{fail, Other}
end;
false ->
{ok, <<>>}
end,
case RecvData of
{ok, _BinData} ->
case Cmd of
60000 ->
gen_server:cast(Pid, {gateway_fallback});
_ ->
io:format("do_parse_packet recv data failed:/~p/~p/~n~p~n", [Socket, Pid, RecvData])
end;
{fail, _} ->
io:format("do_parse_packet recv data failed:/~p/~p/~n~p~n", [Socket, Pid, RecvData]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_1})
end;
%%
{inet_async, Socket, Ref, {error, timeout}} ->
io:format("do_parse_packet timeout:/~p/~p/~n", [Socket, Pid]),
do_parse_packet(Socket, Pid);
%%
Reason ->
io:format("do_parse_packet: Error Reason:/~p/~p/~n", [Socket, Reason]),
gen_tcp:close(Socket),
gen_server:cast(Pid, {stop, socket_error_3})
end.
%%
handle_action_random(State) ->
Actions = ?RANDOM_MODULE,
if Actions =/= [] ->
Action = lists:nth(random:uniform(length(Actions)), Actions),
Module = list_to_atom(lists:concat(["robot_", Action])),
case catch Module:handle(State) of
NewState when is_record(NewState, robot) ->
NewState;
_Error ->
io:format("ERROR: ~p~n", [_Error]),
State
end;
true ->
State
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
handle(heart, _, Socket) ->
case gen_tcp:send(Socket, pack(10006, <<>>)) of
ok ->
sleep(24 * 1000),
handle(heart, a, Socket);
_ ->
error
end;
%%
handle(login_gateway, {Accid, AccName}, Socket) ->
io:format("======sending login_gateway : ~p ~p~n", [Accid, Socket]),
StrBin = tool:to_binary(AccName),
Len = byte_size(StrBin),
Data = <<Accid:32, 123456789:32, Len:16, StrBin/binary>>,
gen_tcp:send(Socket, pack(60000, Data)),
ok;
%%
handle(select_role, Accid, Socket) ->
NickName = "GUEST" ++ integer_to_list(Accid),
NameBin = list_to_binary(NickName),
TLen = byte_size(NameBin),
Gender = random:uniform(2),
Career = random:uniform(3),
gen_tcp:send(Socket, pack(10003, <<9999:16, Career:8, Gender:8, TLen:16, NameBin/binary>>)),
ok;
%%
handle(enter_player, {PlayerId}, Socket) ->
%% Posx = random:uniform(30) ,
%% Posy = random:uniform(20) ,
gen_tcp:send(Socket, pack(10004, <<9999:16, PlayerId:64, 30:8, 20:8>>)),
ok;
%%
handle(run, {DestX, DestY}, Socket) ->
gen_tcp:send(Socket, pack(12011, <<DestX:8, DestY:8>>));
%%
handle(broad_path, {DestX, DestY, Path}, Socket) ->
Len = length(Path),
Fun = fun({X, Y}) ->
<<X:8, Y:8>>
end,
MoveBin = tool:to_binary([Fun(M) || M <- Path]),
gen_tcp:send(Socket, pack(12010, <<DestX:8, DestY:8, Len:16, MoveBin/binary>>));
%%ai模式跑步
handle(run, {X, Y, SX, SY}, Socket) ->
io:format("----running:[~p][~p]~n", [X, Y]),
gen_tcp:send(Socket, pack(12001, <<X:8, Y:8, SX:8, SY:8>>));
%%
handle(enter_scene, [SceneId], Socket) ->
Posx = random:uniform(30),
Posy = random:uniform(20),
gen_tcp:send(Socket, pack(12001, <<SceneId:16, Posx:8, Posy:8>>));
%%
handle(undefined, a, _Socket) ->
ok;
%%
handle(get_player_info, Id, Socket) ->
gen_tcp:send(Socket, pack(13004, <<Id:16>>));
%%
handle(get_self_info, _, Socket) ->
io:format("get_self_info: sending 13001~n"),
gen_tcp:send(Socket, pack(13001, <<>>));
%%
handle(revive, _, Socket) ->
%% gen_tcp:send(Socket, pack(20004, <<3:8>>)),
%% Action = tool:to_binary("-加血 100000"),
%% ActionLen= byte_size(Action),
%% Data = <<ActionLen:16, Action/binary>>,
%% Packet = pack(11020, Data),
%% gen_tcp:send(Socket, Packet);
gen_tcp:send(Socket, pack(12020, <<>>));
handle(_Handle, _Data, Socket) ->
io:format("handle error: /~p/~p/~n", [_Handle, _Data]),
{reply, handle_no_match, Socket}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%
read_string(Bin) ->
case Bin of
<<Len:16, Bin1/binary>> ->
case Bin1 of
<<Str:Len/binary-unit:8, Rest/binary>> ->
{binary_to_list(Str), Rest};
_R1 ->
{[], <<>>}
end;
_R1 ->
{[], <<>>}
end.
random_sleep(T) ->
N = random:uniform(T),
timer:sleep(N * 100).
sleep(T) ->
receive
after T -> ok
end.
for(Max, Max, _F) ->
[];
for(Min, Max, F) ->
[F(Min) | for(Min + 1, Max, F)].
for(Max, Max, _F, X) ->
X;
for(Min, Max, F, X) ->
F(X),
for(Min + 1, Max, F, X).
sleep_send({T, S}) ->
receive
after T -> handle(run, a, S)
end.
get_pid(Name) ->
case whereis(Name) of
undefined ->
err;
Pid -> Pid
end.
ping(Node) ->
case net_adm:ping(Node) of
pang ->
io:format("ping ~p error.~n", [Node]);
pong ->
io:format("ping ~p success.~n", [Node]);
_Error ->
io:format("error: ~p ~n", [_Error])
end.
get_robot_status(0, _TargetBin, DataList) ->
DataList;
get_robot_status(Len, TargetBin, DataList) ->
<<_:8, UId:64, CurHp:32, _:32, _:32, _:32, _:8, OtherBin/binary>> = TargetBin,
NewDataList = DataList ++ [{UId, CurHp}],
get_robot_status(Len - 1, OtherBin, NewDataList).
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.
rand(Same, Same) -> Same;
rand(Min, Max) ->
M = Min - 1,
if
Max - M =< 0 ->
0;
true ->
random:uniform(Max - M) + M
end.
%%@spec
make_move_path(StartX, StartY, EndX, EndY, Path) ->
if
StartX =:= EndX andalso StartY =:= EndY ->
Path;
StartX =:= EndX ->
NextX = StartX,
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
StartY =:= EndY ->
NextX = make_next_step(StartX, EndX),
NextY = EndY,
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
true ->
NextX = make_next_step(StartX, EndX),
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath)
end.
make_next_step(Current, Target) ->
if Current > Target ->
if Current - Target > 1 ->
Current - 1;
true ->
Target
end;
true ->
if Target - Current > 1 ->
Current + 1;
true ->
Target
end
end.
rand(Min) when Min =< 0 ->
0;
rand(Max) ->
case get("rand_seed") of
undefined ->
RandSeed = now(),
random:seed(RandSeed),
put("rand_seed", RandSeed);
_ -> skip
end,
random:uniform(Max).

+ 39
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_gm.erl Dosyayı Görüntüle

@ -0,0 +1,39 @@
-module(robot_gm).
-compile(export_all).
-include("robot.hrl").
%%
%% -undefine行
%%-define(gm_debug, 1).
%-undefine(gm_debug).
-ifdef(gm_debug).
-define(MYTRACE(Str), io:format(Str)).
-define(MYTRACE(Str, Args), io:format(Str, Args)).
-else.
-define(MYTRACE(Str), void).
-define(MYTRACE(Str, Args), void).
-endif.
%%---------------------- ----------------------
-define(AUTO_CHAT_LIST, [
<<"-level 10">>,
%% <<"-coin 1000000">>,
%% <<"-bcoin 1000000">>,
%% <<"-gold 100000">>,
%% <<"-bgold 100000">>,
<<"-exp 10000000">>
]).
handle(State) ->
F = fun(Msg) ->
{ok, BinData} = ptr_11:write(11005, [1, Msg]),
mysend(State#robot.socket, BinData)
end,
lists:foreach(F, ?AUTO_CHAT_LIST),
State.
mysend(Socket, BinData) ->
<<_:16, _Cmd:16, _/binary>> = BinData,
?MYTRACE("sending: cmd: ~p~n", [_Cmd]),
gen_tcp:send(Socket, BinData).

+ 62
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_goods.erl Dosyayı Görüntüle

@ -0,0 +1,62 @@
%% Author: Administrator
%% Created: 2013-9-16
%% Description: TODO: Add description to robot_goods
-module(robot_goods).
-behaviour(gen_server).
%%
%% Include files
%%
-include("robot.hrl").
%%
%% Exported Functions
%%
-compile(export_all).
%% -export([]).
%%
%% API Functions
%%
%% RS = RobotStatus #robot
start_robot_test(RS) ->
io:format("**********20130916 robot_goods start_robot_test~n"),
handle(15000, RS),
handle(15002, RS#robot.socket),
handle(15003, RS#robot.socket),
handle(15004, RS),
ok.
%%
handle(15000, RS) ->
?TRACE("**********20130916 robot_goods 15000 handle~n"),
Id = RS#robot.id,
gen_tcp:send(RS#robot.socket, pack(15000, <<Id:64>>)),
ok;
%%
handle(15002, Socket) ->
?TRACE("**********20130916 robot_goods 15002 handle~n"),
gen_tcp:send(Socket, pack(15002, <<0:8>>)),
ok;
%%
handle(15003, Socket) ->
?TRACE("**********20130916 robot_goods 15003 handle~n"),
gen_tcp:send(Socket, pack(15003, <<0:8, 1:8>>)),
ok;
%%
handle(15004, RS) ->
?TRACE("**********20130916 robot_goods 15004 handle~n"),
gen_tcp:send(RS#robot.socket, pack(15004, <<123:64, 1:16, 2:16>>)),
ok.
%%
%% Local Functions
%%
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 232
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_guild.erl Dosyayı Görüntüle

@ -0,0 +1,232 @@
%%%---------------------------------------------
%%% @Module : robot_guild
%%% @Author : smxx
%%% @Created : 2013.03.01
%%% @Description:
%%%---------------------------------------------
-module(robot_guild).
-include("robot.hrl").
-compile(export_all).
%%
%% -undefine行
-define(guild_debug, 1).
%-undefine(guild_debug).
-ifdef(guild_debug).
-define(MYTRACE(Str), io:format(Str)).
-define(MYTRACE(Str, Args), io:format(Str, Args)).
-else.
-define(MYTRACE(Str), void).
-define(MYTRACE(Str, Args), void).
-endif.
%%Robot进程调用 ()
handle(State) ->
?TRACE("guild handle : begin"),
if State#robot.guild =:= 0 -> %%
case robot:rand(100) of
Int when Int =< 90 -> %%,
Cmd = 40001;
_ ->
Cmd = 40002
end,
case Cmd of
40001 -> % ->
IsNotFull = robot:rand(100) rem 2,
IsSameGroup = robot:rand(100) rem 2,
{ok, BinData} = ptr_40:write(Cmd, [1, IsNotFull, IsSameGroup]);
40002 -> %
%%
GoodsId = 390004205,
Content = string:concat("-addgoods ", util:term_to_string(GoodsId)),
Content2 = string:concat(Content, " 1"),
ContentLen = length(Content2),
NewContent = list_to_binary(Content2),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)),
%%
Level = 45,
LevelContent = string:concat("-level ", util:term_to_string(Level)),
LevelContentLen = length(LevelContent),
NewLevelContent = list_to_binary(LevelContent),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<LevelContentLen:16, NewLevelContent:LevelContentLen/binary-unit:8>>/binary>>)),
GName = "Guild" ++ integer_to_list(State#robot.acid),
{ok, BinData} = ptr_40:write(Cmd, [GName, <<" ">>])
end,
mysend(State#robot.socket, BinData),
State;
true ->
if State#robot.guild_post =:= 1 -> %
%%{ok, Bin} = ptr_40:write(40031, [0]), %%
%% mysend(State#robot.socket, Bin),
ActionCmds = [40005, 40010, 40031, 40034],
Cmd = lists:nth(robot:rand(length(ActionCmds)), ActionCmds);
true ->
%ActionCmds = [40004, 40005, 40006],
case robot:rand(100) < 20 of
true ->
Cmd = 40004;
false ->
ActionCmds = [40005],
Cmd = lists:nth(robot:rand(length(ActionCmds)), ActionCmds)
end
end,
case Cmd of
40004 -> %退
{ok, BinData} = ptr_40:write(Cmd, [0]);
40005 -> %
{ok, BinData} = ptr_40:write(Cmd, [0, 0]);
%% 40006 -> %
%% {ok, BinData} = ptr_40:write(Cmd, [0]);
40010 ->%
{ok, BinData} = ptr_40:write(Cmd, [0, 0]);
%% 40011 -> %
%%
%% skip;
40031 -> %
{ok, BinData} = ptr_40:write(Cmd, [0])
%% 40034 -> %
%% {ok, BinData} = ptr_40:write(Cmd, [0])
%% _ ->
%% skip
end,
mysend(State#robot.socket, BinData),
State
end.
%%Robot进程
handle_cast({guild_create_ok}, State) ->
NewState = State#robot{guild = 1, guild_post = 1},
{noreply, NewState};
%%便
handle_cast({request_join, GuildId}, State) ->
if State#robot.guild =:= 0 ->
{ok, BinData} = ptr_40:write(40003, [GuildId]),
mysend(State#robot.socket, BinData);
true -> skip end,
{noreply, State};
handle_cast({join_guild_approve}, State) ->
NewState = State#robot{guild = 1, guild_post = 0},
{noreply, NewState};
handle_cast({refresh_robot_guild_state, [GuildId, Position]}, State) ->
?TRACE("refresh_robot_guild_state:GuildId=~p,Position=~p ", [GuildId, Position]),
NewState = State#robot{guild = GuildId, guild_post = Position},
{noreply, NewState};
handle_cast({quit_guild}, State) ->
NewState = State#robot{guild = 0, guild_post = 0},
{noreply, NewState};
%%
handle_cast({member, Uid}, State) ->
if State#robot.guild =:= 1 andalso State#robot.guild_post =:= 1 -> %
ActionCmds = [40033, 40035, 40037],
Cmd = lists:nth(robot:rand(length(ActionCmds)), ActionCmds),
case Cmd of
40033 -> %()
Position = robot:rand(2) + 1, %2 3
{ok, BinData} = ptr_40:write(Cmd, [Uid, Position]);
40035 -> %(/)
{ok, BinData} = ptr_40:write(Cmd, [Uid]);
40037 -> %
{ok, BinData} = ptr_40:write(Cmd, [Uid])
end,
mysend(State#robot.socket, BinData);
true -> skip end,
{noreply, State};
%%
handle_cast({new_guild_chief, Uid}, State) ->
if State#robot.guild =:= 1 andalso State#robot.id =:= Uid -> %
{noreply, State#robot{guild_post = 1}};
true -> {noreply, State}
end;
handle_cast(_, State) ->
{noreply, State}.
%%
do_parse_packet(Socket, Pid, Cmd, BinData) ->%%
%%?MYTRACE("do_parse_packet begin: Cmd: ~p, BinData: ~p~n", [Cmd, BinData]),
{ok, DecodeMsg} = ptr_40:read(Cmd, BinData),
%%?MYTRACE("Cmd: ~p, Result: ~p~n", [Cmd, DecodeMsg]),
case Cmd of
40001 -> %%
[_, _, GuildList] = DecodeMsg,
if GuildList =/= [] ->
[[GuildId | _T1] | _T2] = GuildList,
gen_server:cast(Pid, {guild, {request_join, GuildId}});
true -> skip end;
40002 -> %%
[Result] = DecodeMsg,
if Result =:= 1 -> gen_server:cast(Pid, {guild, {guild_create_ok}});
true -> skip end;
40003 -> %%
skip;
40004 -> %%退
[Result] = DecodeMsg,
if Result =:= 1 -> gen_server:cast(Pid, {guild, {quit_guild}});
true -> skip end;
40005 -> %
[StCode | T] = DecodeMsg,
if StCode =:= 1 andalso length(T) >= 1 ->
[Uid | _] = lists:nth(robot:rand(length(T)), T),
gen_server:cast(Pid, {guild, {member, Uid}});
true -> skip end;
40006 -> %%
skip;
40007 -> %
skip;
40008 -> %
skip;
40031 -> %%
F = fun(Apply) ->
[Uid | _T] = Apply,
Ops = robot:rand(2),
{ok, BinData} = ptr_40:write(40032, [Uid, Ops]),
mysend(Socket, BinData)
end,
lists:foreach(F, DecodeMsg);
40034 -> %%()
[Result] = DecodeMsg,
if Result =:= 1 -> gen_server:cast(Pid, {guild, {quit_guild}});
true -> skip end;
40070 -> %
[Uid | _] = DecodeMsg,
gen_server:cast(Pid, {guild, {member, Uid}});
40071 -> %
gen_server:cast(Pid, {guild, {quit_guild}});
40074 -> %
[_, _, Uid, _] = DecodeMsg,
gen_server:cast(Pid, {guild, {new_guild_chief, Uid}});
40078 -> %
gen_server:cast(Pid, {guild, {join_guild_approve}});
_ -> skip
end.
mysend(Socket, BinData) ->
<<_:16, _Cmd:16, _/binary>> = BinData,
?MYTRACE("sending: cmd: ~p~n", [_Cmd]),
gen_tcp:send(Socket, BinData).%%
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 23
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_mail.erl Dosyayı Görüntüle

@ -0,0 +1,23 @@
%%---------------------------------------------
%% @Module : robot_mail
%% @Author : smxx
%% @Created : 2013.09.13
%% @Description:
%%---------------------------------------------
-module(robot_mail).
-include("robot.hrl").
-compile(export_all).
handle(Status) ->
%% gm指令来压
Cmd = 11005,
Type = 0,
Content = "-mail 1",
{ok, BinData} = ptr_11:write(Cmd, [0, Content]),
gen_tcp:send(Status#robot.socket, BinData),
Status.

+ 158
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_market.erl Dosyayı Görüntüle

@ -0,0 +1,158 @@
-module(robot_market).
-compile(export_all).
%-include("common.hrl").
-include("robot.hrl").
-record(bag_list, {
id,
tid,
cell,
num,
stren,
strenPer,
bind
}).
-record(sale_list, {
saleId,
goodsUid,
goodsId,
leftTime,
num,
price
}).
-define(ADD_GOODS, 1).
-define(DO_SALE, 2).
-define(DO_BUY, 3).
-define(GOODS, [262035204]).
-define(ACTIONS, [?ADD_GOODS, ?DO_SALE, ?DO_BUY]).
handle(State) ->
Cmds = [41001],
%%Chat_List = ?AUTO_CHAT_LIST,
%%Msg = tool:to_list(lists:nth(random:uniform(length(Chat_List)), Chat_List)),
Rand = random:uniform(100),
case Rand > 50 of
true ->
Act = ?DO_SALE;
false ->
case Rand > 20 of
true ->
Act = ?ADD_GOODS;
false ->
Act = ?ADD_GOODS
end
end,
%%Act = lists:nth(random:uniform(length(?ACTIONS)), ?ACTIONS),
do_action(State, Act),
State.
do_action(State, Act) ->
case Act of
?ADD_GOODS ->
io:format("do_action:add_goods~n"),
become_vip(State),
sale_add_goods(State);
?DO_SALE ->
io:format("do_action:query_bag~n"),
query_bag(State);
?DO_BUY ->
io:format("do_action:do_query~n"),
do_buy(State);
_ ->
skip
end.
do_parse_packet(_Socket, _Pid, Cmd, BinData) ->
{ok, _Result} = ptr_41:read(Cmd, BinData),
case Cmd of
41001 ->
case _Result of
<<Len:8, SellingBin/binary>> ->
case parse_sale_list(SellingBin, []) of
SaleList when length(SaleList) > 0 ->
Sale = lists:nth(random:uniform(length(SaleList)), SaleList),
io:format("SaleList~p~n", [Sale#sale_list.saleId]),
{ok, BinData2} = ptr_41:write(41002, [Sale#sale_list.saleId]),
gen_tcp:send(_Socket, BinData2);
_ ->
skip
end;
_ ->
skip
end;
_ ->
skip
end,
io:format("Cmd: ~p, Result: ~p~n", [Cmd, _Result]).
do_buy(State) ->
sale_add_gold(State),
do_query(State).
do_query(State) ->
{ok, BinData} = ptr_41:write(41001, [0]),
gen_tcp:send(State#robot.socket, BinData).
do_sale(State, BagList) ->
lists:map(fun(Data) ->
case lists:member(Data#bag_list.tid, ?GOODS) of
true ->
io:format("do_sale::~p~n", [Data#bag_list.id]),
{ok, BinData} = ptr_41:write(41003, [Data#bag_list.id, 1, 10]),
gen_tcp:send(State#robot.socket, BinData);
false ->
skip
end
end, BagList).
refresh_bag(State, BinData) ->
<<Location:8, CellNum:16, ListNum:16, ListBin/binary>> = BinData,
BagList = parse_bag_data(ListBin, []),
do_sale(State, BagList).
parse_sale_list(BinData, Result) ->
case BinData of
<<SaleId:64, GoodsUId:64, GoodsId:64, LeftTime:32, Num:32, Price:32, LeftData/binary>> ->
Result2 = Result ++ [#sale_list{saleId = SaleId, goodsUid = GoodsUId, goodsId = GoodsId, leftTime = LeftTime, num = Num, price = Price}],
parse_sale_list(LeftData, Result2);
_ ->
Result
end.
parse_bag_data(BinData, Result) ->
case BinData of
<<GoodsId:64, TypeId:32, Cell:16, GoodsNum:16, Stren:8, StrenPer:8, Bind:8, LeftData/binary>> ->
Result2 = Result ++ [#bag_list{id = GoodsId, tid = TypeId, cell = Cell, num = GoodsNum, stren = Stren, strenPer = StrenPer, bind = Bind}],
parse_bag_data(LeftData, Result2);
_ ->
io:format("market:parse_bag_data::~p~n", [Result]),
Result
end.
become_vip(State) ->
Content = "-gold 1000010",
ContentLen = length(Content),
NewContent = list_to_binary(Content),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)).
sale_add_goods(State) ->
GoodsId = lists:nth(random:uniform(length(?GOODS)), ?GOODS),
Content = string:concat("-addgoods ", util:term_to_string(GoodsId)),
Content2 = string:concat(Content, " 1"),
ContentLen = length(Content2),
NewContent = list_to_binary(Content2),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)).
sale_add_gold(State) ->
GoodsId = lists:nth(random:uniform(length(?GOODS)), ?GOODS),
Content = "-addgold 11",
ContentLen = length(Content),
NewContent = list_to_binary(Content),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)).
query_bag(State) ->
gen_tcp:send(State#robot.socket, pack(15002, <<0:8>>)).
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 44
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_mount.erl Dosyayı Görüntüle

@ -0,0 +1,44 @@
%%%------------------------------------
%%% @Author :
%%% @Created : 2010.09.27
%%% @Description:
%%%------------------------------------
-module(robot_mount).
-include("robot.hrl").
-compile(export_all).
handle(Status) ->
RandNum = util:rand(1, 3),
if
RandNum == 1 ->
upgrade_mount_star(Status);
RandNum == 2 ->
upgrade_mount_level(Status);
RandNum == 3 ->
upgrade_mount_skill(Status);
true ->
skip
end,
Status.
upgrade_mount_star(Status) ->
Cmd = 44006,
AutoBuy = 1,
BatchUpgrade = 1,
{ok, BinData} = ptr_44:write(Cmd, [AutoBuy, BatchUpgrade]),
gen_tcp:send(Status#robot.socket, BinData),
Status.
upgrade_mount_level(Status) ->
Cmd = 44007,
AutoBuy = 1,
{ok, BinData} = ptr_44:write(Cmd, [AutoBuy]),
gen_tcp:send(Status#robot.socket, BinData),
Status.
upgrade_mount_skill(Status) ->
Cmd = 44001,
UpgradeType = 1,
{ok, BinData} = ptr_44:write(Cmd, [UpgradeType]),
gen_tcp:send(Status#robot.socket, BinData),
Status.

+ 18
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_newbie.erl Dosyayı Görüntüle

@ -0,0 +1,18 @@
%%---------------------------------------------
%% @Module : robot_newbie
%% @Author : smxx
%% @Created : 2013.09.13
%% @Description:
%%---------------------------------------------
-module(robot_newbie).
-include("robot.hrl").
-compile(export_all).
get_newbie_list(Status) ->
Status.

+ 23
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_openfunc.erl Dosyayı Görüntüle

@ -0,0 +1,23 @@
%%---------------------------------------------
%% @Module : robot_openfunc
%% @Author : smxx
%% @Created : 2013.03.01
%% @Description:
%%---------------------------------------------
-module(robot_openfunc).
-include("robot.hrl").
-compile(export_all).
handle(Status) ->
%%-openfunc XX XX的gm指令来压
Cmd = 11005,
Type = 0,
Content = "-openfunc 1 20",
{ok, BinData} = ptr_11:write(Cmd, [0, Content]),
gen_tcp:send(Status#robot.socket, BinData),
Status.

+ 9
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_pet.erl Dosyayı Görüntüle

@ -0,0 +1,9 @@
%%%---------------------------------------------
%%% @Module : robot_pet
%%% @Author : smxx
%%% @Created : 2013.03.xx
%%% @Description:
%%%---------------------------------------------
-module(robot_pet).
%% -include("robot.hrl").
%% -compile(export_all).

+ 51
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_shop.erl Dosyayı Görüntüle

@ -0,0 +1,51 @@
-module(robot_shop).
-compile(export_all).
%-include("common.hrl").
-include("robot.hrl").
-define(SHOP_REFRESH, 1).
-define(SHOP_BUY, 2).
-define(ADD_GOLD, 3).
-define(ACTIONS, [?SHOP_REFRESH, ?SHOP_BUY]).
handle(State) ->
Rand = random:uniform(100),
case Rand > 50 of
true ->
Act = ?SHOP_REFRESH;
false ->
Act = ?SHOP_BUY
end,
add_gold(State),
do_action(State, Act),
State.
do_action(State, Act) ->
case Act of
?SHOP_REFRESH ->
io:format("do_action:shop_refresh~n"),
do_shop_refresh(State);
?SHOP_BUY ->
io:format("do_action:shop_buy~n"),
do_shop_buy(State);
_ ->
skip
end.
do_shop_refresh(State) ->
BinData = pt:pack(15042, <<>>),
gen_tcp:send(State#robot.socket, BinData).
do_shop_buy(State) ->
BinData = pt:pack(15043, <<>>),
gen_tcp:send(State#robot.socket, BinData).
add_gold(State) ->
Content = "-addgold 111",
ContentLen = length(Content),
NewContent = list_to_binary(Content),
gen_tcp:send(State#robot.socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)).
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.

+ 140
- 0
src/srvNodeMgr/tools/gameWorld/test/robot/robot_task.erl Dosyayı Görüntüle

@ -0,0 +1,140 @@
%%--------------------------------------------
%%--------------------------
%%-----------------by CXF---------------------
%%--------------------------------------------
-module(robot_task).
-include("robot.hrl").
%% gen_server callbacks
-compile(export_all).
accept_task(Socket, TaskProcessId) ->
io:format("accept_task.....................~n"),
gen_tcp:send(Socket, pack(30002, <<TaskProcessId:32>>)).
finish_task(Socket, TaskId) ->
io:format("finish_task.....................~n"),
Content = string:concat("-taskgoto ", util:term_to_string(TaskId)),
ContentLen = length(Content),
NewContent = list_to_binary(Content),
gen_tcp:send(Socket, pack(11005, <<0:8, <<ContentLen:16, NewContent:ContentLen/binary-unit:8>>/binary>>)).
submit_task(Socket, TaskProcessId) ->
io:format("submit_task.....................~n"),
gen_tcp:send(Socket, pack(30004, <<TaskProcessId:32>>)).
parse_task_data(BinData, Result) ->
case BinData of
<<Id:32, TaskId:16, State:8, Mark:32, Grade:8, LeftData/binary>> ->
Result2 = Result ++ [#task_list{id = Id, taskId = TaskId, state = State, mark = Mark, grade = Grade}],
parse_task_data(LeftData, Result2);
_ ->
Result
end.
%%
get_rand_taskPid(TaskList) ->
io:format("VVVVVVVVVVVVVVVVVVVVV333::::::::~p~n", [length(TaskList)]),
if
is_list(TaskList) ->
io:format("VVVVVVVVVVVVVVVVVVVVV666::::::::~p~n", [length(TaskList)]),
RandNum = rand(length(TaskList)),
io:format("VVVVVVVVVVVVVVVVVVVVV444::::::::~p~n", [RandNum]),
TargetTask = lists:nth(RandNum, TaskList);
true ->
skip
end.
handle(get_task, {}, Socket) ->
TotalNum = ?MAX_TASK_NUM,
gen_tcp:send(Socket, pack(30006, <<TotalNum:8>>)).
pack(Cmd, Data) ->
L = byte_size(Data) + ?HEADER_LENGTH,
<<L:16, Cmd:16, Data/binary>>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%
read_string(Bin) ->
case Bin of
<<Len:16, Bin1/binary>> ->
case Bin1 of
<<Str:Len/binary-unit:8, Rest/binary>> ->
{binary_to_list(Str), Rest};
_R1 ->
{[], <<>>}
end;
_R1 ->
{[], <<>>}
end.
random_sleep(T) ->
N = random:uniform(T),
timer:sleep(N * 100).
sleep(T) ->
receive
after T -> ok
end.
for(Max, Max, _F) ->
[];
for(Min, Max, F) ->
[F(Min) | for(Min + 1, Max, F)].
for(Max, Max, _F, X) ->
X;
for(Min, Max, F, X) ->
F(X),
for(Min + 1, Max, F, X).
%%@spec
make_move_path(StartX, StartY, EndX, EndY, Path) ->
if
StartX =:= EndX andalso StartY =:= EndY ->
Path;
StartX =:= EndX ->
NextX = StartX,
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
StartY =:= EndY ->
NextX = make_next_step(StartX, EndX),
NextY = EndY,
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath);
true ->
NextX = make_next_step(StartX, EndX),
NextY = make_next_step(StartY, EndY),
NewPath = Path ++ [{NextX, NextY}],
make_move_path(NextX, NextY, EndX, EndY, NewPath)
end.
make_next_step(Current, Target) ->
if Current > Target ->
if Current - Target > 1 ->
Current - 1;
true ->
Target
end;
true ->
if Target - Current > 1 ->
Current + 1;
true ->
Target
end
end.
rand(Min) when Min =< 0 ->
0;
rand(Max) ->
case get("rand_seed") of
undefined ->
RandSeed = now(),
random:seed(RandSeed),
put("rand_seed", RandSeed);
_ -> skip
end,
random:uniform(Max).

+ 350
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/mmake.erl Dosyayı Görüntüle

@ -0,0 +1,350 @@
%% ,otp/lib/tools/src/make.erl
%% Emakefile,{mods, options},
%% ()
%% mods也可以包含多个模块,1,
%% process进行编译,.
-module(mmake).
-export([all/1, all/2, files/2, files/3]).
-include_lib("kernel/include/file.hrl").
-define(MakeOpts, [noexec, load, netload, noload]).
all(Worker) when is_integer(Worker) ->
all(Worker, []).
all(Worker, Options) when is_integer(Worker) ->
{MakeOpts, CompileOpts} = sort_options(Options, [], []),
case read_emakefile('Emakefile', CompileOpts) of
Files when is_list(Files) ->
do_make_files(Worker, Files, MakeOpts);
error ->
error
end.
files(Worker, Fs) ->
files(Worker, Fs, []).
files(Worker, Fs0, Options) ->
Fs = [filename:rootname(F, ".erl") || F <- Fs0],
{MakeOpts, CompileOpts} = sort_options(Options, [], []),
case get_opts_from_emakefile(Fs, 'Emakefile', CompileOpts) of
Files when is_list(Files) ->
do_make_files(Worker, Files, MakeOpts);
error -> error
end.
do_make_files(Worker, Fs, Opts) ->
%io:format("worker:~p~nfs:~p~nopts:~p~n", [Worker, Fs, Opts]),
process(Fs, Worker, lists:member(noexec, Opts), load_opt(Opts)).
sort_options([H | T], Make, Comp) ->
case lists:member(H, ?MakeOpts) of
true ->
sort_options(T, [H | Make], Comp);
false ->
sort_options(T, Make, [H | Comp])
end;
sort_options([], Make, Comp) ->
{Make, lists:reverse(Comp)}.
%%% Reads the given Emakefile and returns a list of tuples: {Mods,Opts}
%%% Mods is a list of module names (strings)
%%% Opts is a list of options to be used when compiling Mods
%%%
%%% Emakefile can contain elements like this:
%%% Mod.
%%% {Mod,Opts}.
%%% Mod is a module name which might include '*' as wildcard
%%% or a list of such module names
%%%
%%% These elements are converted to [{ModList,OptList},...]
%%% ModList is a list of modulenames (strings)
read_emakefile(Emakefile, Opts) ->
case file:consult(Emakefile) of
{ok, Emake} ->
transform(Emake, Opts, [], []);
{error, enoent} ->
%% No Emakefile found - return all modules in current
%% directory and the options given at command line
Mods = [filename:rootname(F) || F <- filelib:wildcard("*.erl")],
[{Mods, Opts}];
{error, Other} ->
io:format("make: Trouble reading 'Emakefile':~n~p~n", [Other]),
error
end.
transform([{Mod, ModOpts} | Emake], Opts, Files, Already) ->
case expand(Mod, Already) of
[] ->
transform(Emake, Opts, Files, Already);
Mods ->
transform(Emake, Opts, [{Mods, ModOpts ++ Opts} | Files], Mods ++ Already)
end;
transform([Mod | Emake], Opts, Files, Already) ->
case expand(Mod, Already) of
[] ->
transform(Emake, Opts, Files, Already);
Mods ->
transform(Emake, Opts, [{Mods, Opts} | Files], Mods ++ Already)
end;
transform([], _Opts, Files, _Already) ->
lists:reverse(Files).
expand(Mod, Already) when is_atom(Mod) ->
expand(atom_to_list(Mod), Already);
expand(Mods, Already) when is_list(Mods), not is_integer(hd(Mods)) ->
lists:concat([expand(Mod, Already) || Mod <- Mods]);
expand(Mod, Already) ->
case lists:member($*, Mod) of
true ->
Fun = fun(F, Acc) ->
M = filename:rootname(F),
case lists:member(M, Already) of
true -> Acc;
false -> [M | Acc]
end
end,
lists:foldl(Fun, [], filelib:wildcard(Mod ++ ".erl"));
false ->
Mod2 = filename:rootname(Mod, ".erl"),
case lists:member(Mod2, Already) of
true -> [];
false -> [Mod2]
end
end.
%%% Reads the given Emakefile to see if there are any specific compile
%%% options given for the modules.
get_opts_from_emakefile(Mods, Emakefile, Opts) ->
case file:consult(Emakefile) of
{ok, Emake} ->
Modsandopts = transform(Emake, Opts, [], []),
ModStrings = [coerce_2_list(M) || M <- Mods],
get_opts_from_emakefile2(Modsandopts, ModStrings, Opts, []);
{error, enoent} ->
[{Mods, Opts}];
{error, Other} ->
io:format("make: Trouble reading 'Emakefile':~n~p~n", [Other]),
error
end.
get_opts_from_emakefile2([{MakefileMods, O} | Rest], Mods, Opts, Result) ->
case members(Mods, MakefileMods, [], Mods) of
{[], _} ->
get_opts_from_emakefile2(Rest, Mods, Opts, Result);
{I, RestOfMods} ->
get_opts_from_emakefile2(Rest, RestOfMods, Opts, [{I, O} | Result])
end;
get_opts_from_emakefile2([], [], _Opts, Result) ->
Result;
get_opts_from_emakefile2([], RestOfMods, Opts, Result) ->
[{RestOfMods, Opts} | Result].
members([H | T], MakefileMods, I, Rest) ->
case lists:member(H, MakefileMods) of
true ->
members(T, MakefileMods, [H | I], lists:delete(H, Rest));
false ->
members(T, MakefileMods, I, Rest)
end;
members([], _MakefileMods, I, Rest) ->
{I, Rest}.
%% Any flags that are not recognixed as make flags are passed directly
%% to the compiler.
%% So for example make:all([load,debug_info]) will make everything
%% with the debug_info flag and load it.
load_opt(Opts) ->
case lists:member(netload, Opts) of
true ->
netload;
false ->
case lists:member(load, Opts) of
true ->
load;
_ ->
noload
end
end.
%%
process([{[], _Opts} | Rest], Worker, NoExec, Load) ->
process(Rest, Worker, NoExec, Load);
process([{L, Opts} | Rest], Worker, NoExec, Load) ->
Len = length(L),
Worker2 = erlang:min(Len, Worker),
case catch do_worker(L, Opts, NoExec, Load, Worker2) of
error ->
error;
ok ->
process(Rest, Worker, NoExec, Load)
end;
process([], _Worker, _NoExec, _Load) ->
up_to_date.
%% worker进行编译
do_worker(L, Opts, NoExec, Load, Worker) ->
WorkerList = do_split_list(L, Worker),
%io:format("worker:~p worker list(~p)~n", [Worker, length(WorkerList)]),
%
Ref = make_ref(),
Pids =
[begin
start_worker(E, Opts, NoExec, Load, self(), Ref)
end || E <- WorkerList],
do_wait_worker(length(Pids), Ref).
%%
do_wait_worker(0, _Ref) ->
ok;
do_wait_worker(N, Ref) ->
receive
{ack, Ref} ->
do_wait_worker(N - 1, Ref);
{error, Ref} ->
throw(error);
{'EXIT', _P, _Reason} ->
do_wait_worker(N, Ref);
_Other ->
io:format("receive unknown msg:~p~n", [_Other]),
do_wait_worker(N, Ref)
end.
%% L分割成最多包含N个子列表的列表
do_split_list(L, N) ->
Len = length(L),
%
LLen = (Len + N - 1) div N,
do_split_list(L, LLen, []).
do_split_list([], _N, Acc) ->
lists:reverse(Acc);
do_split_list(L, N, Acc) ->
{L2, L3} = lists:split(erlang:min(length(L), N), L),
do_split_list(L3, N, [L2 | Acc]).
%% worker进程
start_worker(L, Opts, NoExec, Load, Parent, Ref) ->
Fun =
fun() ->
[begin
case recompilep(coerce_2_list(F), NoExec, Load, Opts) of
error ->
Parent ! {error, Ref},
exit(error);
_ ->
ok
end
end || F <- L],
Parent ! {ack, Ref}
end,
spawn_link(Fun).
recompilep(File, NoExec, Load, Opts) ->
ObjName = lists:append(filename:basename(File),
code:objfile_extension()),
ObjFile = case lists:keysearch(outdir, 1, Opts) of
{value, {outdir, OutDir}} ->
filename:join(coerce_2_list(OutDir), ObjName);
false ->
ObjName
end,
case exists(ObjFile) of
true ->
recompilep1(File, NoExec, Load, Opts, ObjFile);
false ->
recompile(File, NoExec, Load, Opts)
end.
recompilep1(File, NoExec, Load, Opts, ObjFile) ->
{ok, Erl} = file:read_file_info(lists:append(File, ".erl")),
{ok, Obj} = file:read_file_info(ObjFile),
recompilep1(Erl, Obj, File, NoExec, Load, Opts).
recompilep1(#file_info{mtime = Te},
#file_info{mtime = To}, File, NoExec, Load, Opts) when Te > To ->
recompile(File, NoExec, Load, Opts);
recompilep1(_Erl, #file_info{mtime = To}, File, NoExec, Load, Opts) ->
recompile2(To, File, NoExec, Load, Opts).
%% recompile2(ObjMTime, File, NoExec, Load, Opts)
%% Check if file is of a later date than include files.
recompile2(ObjMTime, File, NoExec, Load, Opts) ->
IncludePath = include_opt(Opts),
case check_includes(lists:append(File, ".erl"), IncludePath, ObjMTime) of
true ->
recompile(File, NoExec, Load, Opts);
false ->
false
end.
include_opt([{i, Path} | Rest]) ->
[Path | include_opt(Rest)];
include_opt([_First | Rest]) ->
include_opt(Rest);
include_opt([]) ->
[].
%% recompile(File, NoExec, Load, Opts)
%% Actually recompile and load the file, depending on the flags.
%% Where load can be netload | load | noload
recompile(File, true, _Load, _Opts) ->
io:format("Out of date: ~s\n", [File]);
recompile(File, false, noload, Opts) ->
io:format("Recompile: ~s\n", [File]),
compile:file(File, [report_errors, report_warnings, error_summary | Opts]);
recompile(File, false, load, Opts) ->
io:format("Recompile: ~s\n", [File]),
c:c(File, Opts);
recompile(File, false, netload, Opts) ->
io:format("Recompile: ~s\n", [File]),
c:nc(File, Opts).
exists(File) ->
case file:read_file_info(File) of
{ok, _} ->
true;
_ ->
false
end.
coerce_2_list(X) when is_atom(X) ->
atom_to_list(X);
coerce_2_list(X) ->
X.
%%% If you an include file is found with a modification
%%% time larger than the modification time of the object
%%% file, return true. Otherwise return false.
check_includes(File, IncludePath, ObjMTime) ->
Path = [filename:dirname(File) | IncludePath],
case epp:open(File, Path, []) of
{ok, Epp} ->
check_includes2(Epp, File, ObjMTime);
_Error ->
false
end.
check_includes2(Epp, File, ObjMTime) ->
case epp:parse_erl_form(Epp) of
{ok, {attribute, 1, file, {File, 1}}} ->
check_includes2(Epp, File, ObjMTime);
{ok, {attribute, 1, file, {IncFile, 1}}} ->
case file:read_file_info(IncFile) of
{ok, #file_info{mtime = MTime}} when MTime > ObjMTime ->
epp:close(Epp),
true;
_ ->
check_includes2(Epp, File, ObjMTime)
end;
{ok, _} ->
check_includes2(Epp, File, ObjMTime);
{eof, _} ->
epp:close(Epp),
false;
{error, _Error} ->
check_includes2(Epp, File, ObjMTime)
end.

+ 298
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/mtop.erl Dosyayı Görüntüle

@ -0,0 +1,298 @@
%% minitop, etop的简化版
%% 使etop类似 lines sort
%% all etop的内容以外 erlang:process_info
%% top etop一样
%% stack: etop的信息和堆栈信息
%% messages: etop的信息和进程消息队列的信息
%% option: etop的信息和指定的erlang:process_info信息
-module(mtop).
-export([all/0, all/1]).
-export([top/0, top/1]).
-export([stack/0, stack/1]).
-export([option/1, option/2]).
-export([messages/0, messages/1]).
-define(SYSFORM,
" ~-72w~10s~n"
" Load: cpu ~8w Memory: total ~8w binary ~8w~n"
" procs~8w processes~8w code ~8w~n"
" runq ~8w atom ~8w ets ~8w~n").
-define(PROCFORM, "~-15w~-20s~8w~8w~8w~8w ~-20s~n").
-record(mtop_info,
{now = {0, 0, 0},
n_procs = 0,
wall_clock = {0, 0},
runtime = {0, 0},
run_queue = 0,
alloc_areas = [],
memi = [{total, 0},
{processes, 0},
{ets, 0},
{atom, 0},
{code, 0},
{binary, 0}],
procinfo = []
}).
-record(mtop_proc_info,
{pid,
mem = 0,
reds = 0,
name,
runtime = 0,
cf,
mq = 0}).
-record(opts, {lines = 10, sort = msg_q}).
make_info(ProcInfo) ->
#mtop_info{now = now(),
n_procs = length(ProcInfo),
run_queue = erlang:statistics(run_queue),
wall_clock = erlang:statistics(wall_clock),
runtime = erlang:statistics(runtime),
memi = mtop_memi(),
procinfo = ProcInfo
}.
all() ->
all([{lines, 10}, {sort, msg_q}]).
all(Opts) ->
Config = handle_args(init:get_arguments() ++ Opts, #opts{}),
ProcInfo = get_infos(Config),
Info = make_info(ProcInfo),
print_infos_all(standard_io, Info).
top() ->
top([{lines, 10}, {sort, msg_q}]).
top(Opts) ->
Config = handle_args(init:get_arguments() ++ Opts, #opts{}),
ProcInfo = get_infos(Config),
Info = make_info(ProcInfo),
print_infos_top(standard_io, Info).
stack() ->
stack([{lines, 10}, {sort, msg_q}]).
stack(Opts) ->
Config = handle_args(init:get_arguments() ++ Opts, #opts{}),
ProcInfo = get_infos(Config),
Info = make_info(ProcInfo),
print_infos_stack(standard_io, Info).
option(OptionList) ->
option([{lines, 10}, {sort, msg_q}], OptionList).
option(Opts, OptionList) ->
Config = handle_args(init:get_arguments() ++ Opts, #opts{}),
ProcInfo = get_infos(Config),
Info = make_info(ProcInfo),
print_infos_option(standard_io, Info, OptionList).
messages() ->
messages([{lines, 10}, {sort, msg_q}]).
messages(Opts) ->
option(Opts, [messages]).
mtop_memi() ->
try
[{total, c:memory(total)},
{processes, c:memory(processes)},
{ets, c:memory(ets)},
{atom, c:memory(atom)},
{code, c:memory(code)},
{binary, c:memory(binary)}]
catch
error:notsup ->
undefined
end.
get_infos(Opts) ->
ProcInfo = mtop_collect(),
ProcInfo1 = lists:map(fun(PI) -> PI#mtop_proc_info{runtime = '-'} end, ProcInfo),
sort(Opts, ProcInfo1).
mtop_collect() ->
mtop_collect(processes(), []).
mtop_collect([P | Ps], Acc) when P =:= self() ->
mtop_collect(Ps, Acc);
mtop_collect([P | Ps], Acc) ->
Fs = [registered_name, initial_call, memory, reductions, current_function, message_queue_len],
case process_info(P, Fs) of
undefined ->
mtop_collect(Ps, Acc);
[{registered_name, Reg}, {initial_call, Initial}, {memory, Mem},
{reductions, Reds}, {current_function, Current}, {message_queue_len, Qlen}] ->
Name = case Reg of
[] -> Initial;
_ -> Reg
end,
Info = #mtop_proc_info{pid = P, mem = Mem, reds = Reds, name = Name,
cf = Current, mq = Qlen},
mtop_collect(Ps, [Info | Acc])
end;
mtop_collect([], Acc) -> Acc.
sort(Opts, PI) ->
Tag = get_tag(Opts#opts.sort),
PI1 = lists:reverse(lists:keysort(Tag, PI)),
lists:sublist(PI1, Opts#opts.lines).
get_tag(runtime) -> #mtop_proc_info.runtime;
get_tag(memory) -> #mtop_proc_info.mem;
get_tag(reductions) -> #mtop_proc_info.reds;
get_tag(msg_q) -> #mtop_proc_info.mq.
print_infos_top(Fd, Info) ->
{Cpu, NProcs, RQ, Clock} = loadinfo(Info),
io:nl(Fd),
writedoubleline(Fd),
case Info#mtop_info.memi of
undefined ->
io:fwrite(Fd, " ~-72w~10s~n"
" Load: cpu ~8w~n"
" procs~8w~n"
" runq ~8w~n",
[node(), Clock,
Cpu, NProcs, RQ]);
Memi ->
[Tot, Procs, Atom, Bin, Code, Ets] =
meminfo(Memi, [total, processes, atom, binary, code, ets]),
io:fwrite(Fd, ?SYSFORM,
[node(), Clock,
Cpu, Tot, Bin,
NProcs, Procs, Code,
RQ, Atom, Ets])
end,
io:nl(Fd),
writepinfo_header(Fd),
writesingleline(Fd),
writepinfo(Fd, Info#mtop_info.procinfo),
writedoubleline(Fd),
io:nl(Fd).
writepinfo_header(Fd) ->
io:fwrite(Fd, "Pid Name or Initial Func Time Reds Memory MsgQ Current Function~n", []).
writesingleline(Fd) ->
io:fwrite(Fd, "----------------------------------------------------------------------------------------~n", []).
writedoubleline(Fd) ->
io:fwrite(Fd, "========================================================================================~n", []).
formatmfa({M, F, A}) ->
io_lib:format("~w:~w/~w", [M, F, A]).
to_list(Name) when is_atom(Name) -> atom_to_list(Name);
to_list({_M, _F, _A} = MFA) -> formatmfa(MFA).
writepinfo(Fd, [#mtop_proc_info{pid = Pid,
mem = Mem,
reds = Reds,
name = Name,
runtime = Time,
cf = MFA,
mq = MQ}
| T]) ->
io:fwrite(Fd, ?PROCFORM, [Pid, to_list(Name), Time, Reds, Mem, MQ, formatmfa(MFA)]),
writepinfo(Fd, T);
writepinfo(_Fd, []) ->
ok.
loadinfo(SysI) ->
#mtop_info{n_procs = Procs,
run_queue = RQ,
now = Now,
wall_clock = {_, WC},
runtime = {_, RT}} = SysI,
Cpu = round(100 * RT / WC),
Clock = io_lib:format("~2.2.0w:~2.2.0w:~2.2.0w",
tuple_to_list(element(2, calendar:now_to_datetime(Now)))),
{Cpu, Procs, RQ, Clock}.
meminfo(MemI, [Tag | Tags]) ->
[round(get_mem(Tag, MemI) / 1024) | meminfo(MemI, Tags)];
meminfo(_MemI, []) -> [].
get_mem(Tag, MemI) ->
case lists:keysearch(Tag, 1, MemI) of
{value, {Tag, I}} -> I; %these are in bytes
_ -> 0
end.
handle_args([{lines, Lines} | R], Config) when is_integer(Lines) ->
NewC = Config#opts{lines = Lines},
handle_args(R, NewC);
handle_args([{lines, [Lines]} | R], Config) when is_list(Lines) ->
NewC = Config#opts{lines = list_to_integer(Lines)},
handle_args(R, NewC);
handle_args([{sort, Sort} | R], Config) when is_atom(Sort) ->
NewC = Config#opts{sort = Sort},
handle_args(R, NewC);
handle_args([{sort, [Sort]} | R], Config) when is_list(Sort) ->
NewC = Config#opts{sort = list_to_atom(Sort)},
handle_args(R, NewC);
handle_args([_ | R], C) ->
handle_args(R, C);
handle_args([], C) ->
C.
print_infos_all(Fd, Info) ->
print_infos_top(Fd, Info),
writeprocessinfo(Fd, Info#mtop_info.procinfo).
writebt(Fd, Pid) ->
{_, P} = erlang:process_info(Pid, backtrace),
io:fwrite(Fd, "~s~n", [erlang:binary_to_list(P)]).
writeprocessinfo(Fd, [#mtop_proc_info{pid = Pid}
| T]) ->
writedoubleline(Fd),
io:fwrite(Fd, "~p~n", [erlang:process_info(Pid)]),
writesingleline(Fd),
writebt(Fd, Pid),
writeprocessinfo(Fd, T);
writeprocessinfo(_Fd, []) ->
ok.
print_infos_stack(Fd, Info) ->
print_infos_top(Fd, Info),
writebtinfo(Fd, Info#mtop_info.procinfo).
writebtinfo(Fd, [#mtop_proc_info{pid = Pid}
| T]) ->
writedoubleline(Fd),
writebt(Fd, Pid),
writebtinfo(Fd, T);
writebtinfo(_Fd, []) ->
ok.
print_infos_option(Fd, Info, OptionList) ->
print_infos_top(Fd, Info),
writeprocessinfo_option(Fd, OptionList, Info#mtop_info.procinfo).
writeprocessinfo_option(Fd, OptionList, [#mtop_proc_info{pid = Pid}
| T]) ->
writedoubleline(Fd),
io:fwrite(Fd, "~p~n", [erlang:process_info(Pid, OptionList)]),
writesingleline(Fd),
writebt(Fd, Pid),
writeprocessinfo_option(Fd, OptionList, T);
writeprocessinfo_option(_Fd, _OptionList, []) ->
ok.

+ 480
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/record_to_code.erl Dosyayı Görüntüle

@ -0,0 +1,480 @@
%%%--------------------------------------
%%% @Module : game_gateway
%%% @Author : csj
%%% @Created : 2010.10.27
%%% @Description: record erl code
%%% player, 便便player字段值
%%% "../src/lib/lib_player_rw.erl"
%%%--------------------------------------
-module(record_to_code).
%%
%% Include files
%%
-include("common.hrl").
-include("record.hrl").
%%
%% Exported Functions
%%
-compile(export_all).
-define(CONFIG_FILE, "../config/gateway.config").
%%
%% API Functions
%%
start() ->
convert_player(),
case get_db_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB, Encode] ->
start_erlydb(Host, Port, User, Password, DB),
mysql:start_link(?DB_SERVER, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?DB_SERVER, Host, Port, User, Password, DB, Encode, true),
table_fields_all(DB),
get_all_tables(DB),
ok;
_ -> mysql_config_fail
end,
halt(),
ok.
get_db_config(Config_file) ->
try
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(mysql_config, 1, C),
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode]
catch
_:_ -> no_config
end.
%%
%% Local Functions
%%
start_erlydb(IP, Port, User, Password, Db) ->
erlydb:start(mysql, [{pool_id, erlydb_mysql},
{hostname, IP},
{port, Port},
{username, User},
{password, Password},
{database, Db},
{logfun, fun(_, _, _, _) -> ok end},
{encoding, utf8},
{pool_size, 10}]).
convert_player() ->
io:format("~n~n~n~n~n~nBegin create ../src/lib/lib_player_rw.erl!~n~n"),
P_list = record_info(fields, player),
O_list = record_info(fields, player_other),
B_list = record_info(fields, battle_attr),
File = "../src/lib/lib_player_rw.erl",
file:write_file(File, ""),
file:write_file(File, ""),
file:write_file(File, "%%%------------------------------------------------\t\n", [append]),
file:write_file(File, "%%% File : lib_player_rw.erl\t\n", [append]),
file:write_file(File, "%%% Author : csj\t\n", [append]),
Bytes0 = list_to_binary(io_lib:format("%%% Created : ~s\t\n", [time_format(now())])),
file:write_file(File, Bytes0, [append]),
file:write_file(File, "%%% Description: 从record生成的代码\t\n", [append]),
file:write_file(File, "%%% Warning: 由程序自动生成,请不要随意修改!\t\n", [append]),
file:write_file(File, "%%%------------------------------------------------ \t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "-module(lib_player_rw).\t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "%% \t\n", [append]),
file:write_file(File, "%% Include files \t\n", [append]),
file:write_file(File, "-include(\"common.hrl\"). \t\n", [append]),
file:write_file(File, "-include(\"record.hrl\"). \t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "%% \t\n", [append]),
file:write_file(File, "%% Exported Functions \t\n", [append]),
file:write_file(File, "%% \t\n", [append]),
file:write_file(File, "-compile(export_all). \t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "%%获取用户信息(按[字段1,字段2,...])\t\n", [append]),
file:write_file(File, "%% handle_call({'PLAYER', [x ,y]}, _from, Status)\t\n", [append]),
file:write_file(File, "get_player_info_fields(Player, List) ->\t\n", [append]),
file:write_file(File, " lists:map(fun(T) ->\t\n", [append]),
file:write_file(File, " case T of\t\n", [append]),
lists:foreach(fun(Field_name) ->
case lists:member(Field_name, B_list) of
false ->
Bytes00 = lists:concat([" ", Field_name, " -> Player#player.", Field_name, ";\t\n"]),
file:write_file(File, Bytes00, [append]);
true ->
no_action
end
end,
P_list),
lists:foreach(fun(Field_name) ->
Bytes00 = lists:concat([" ", Field_name, " -> Player#player.battle_attr#battle_attr.", Field_name, ";\t\n"]),
file:write_file(File, Bytes00, [append])
end,
B_list),
lists:foreach(fun(Field_name) ->
Bytes00 = lists:concat([" ", Field_name, " -> Player#player.other#player_other.", Field_name, ";\t\n"]),
file:write_file(File, Bytes00, [append])
end,
O_list),
file:write_file(File, " _ -> undefined\t\n", [append]),
file:write_file(File, " end\t\n", [append]),
file:write_file(File, " end, List).\t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "%%设置用户信息(按[{字段1,值1},{字段2,值2, add},{字段3,值3, sub}...])\t\n", [append]),
file:write_file(File, "%% handle_cast({'SET_PLAYER',[{x, 10} ,{y, 20, add}, ,{hp, 20, sub}]}, Status)\t\n", [append]),
file:write_file(File, "set_player_info_fields(Player, []) ->\t\n", [append]),
file:write_file(File, " Player;\t\n", [append]),
file:write_file(File, "set_player_info_fields(Player, [H|T]) ->\t\n", [append]),
file:write_file(File, " NewPlayer =\t\n", [append]),
file:write_file(File, " case H of\t\n", [append]),
lists:foreach(fun(Field_name) ->
case Field_name =:= other orelse Field_name =:= battle_attr orelse lists:member(Field_name, B_list) of
false ->
Bytes1 = lists:concat([" {", Field_name, ", Val, add} -> Player#player{", Field_name, "=Player#player.", Field_name, " + Val};\t\n"]),
file:write_file(File, Bytes1, [append]),
Bytes2 = lists:concat([" {", Field_name, ", Val, sub} -> Player#player{", Field_name, "=Player#player.", Field_name, " - Val};\t\n"]),
file:write_file(File, Bytes2, [append]),
Bytes3 = lists:concat([" {", Field_name, ", Val, _} -> Player#player{", Field_name, "= Val};\t\n"]),
file:write_file(File, Bytes3, [append]),
Bytes4 = lists:concat([" {", Field_name, ", Val} -> Player#player{", Field_name, "= Val};\t\n"]),
file:write_file(File, Bytes4, [append]);
true -> no_action
end
end,
P_list),
lists:foreach(fun(Field_name) ->
Bytes1 = lists:concat([" {", Field_name,
", Val, add} -> Player#player{other=Player#player.other#player_other{", Field_name,
" = Player#player.other#player_other.", Field_name, " + Val}};\t\n"]),
file:write_file(File, Bytes1, [append]),
Bytes2 = lists:concat([" {", Field_name,
", Val, sub} -> Player#player{other=Player#player.other#player_other{", Field_name,
" = Player#player.other#player_other.", Field_name, " - Val}};\t\n"]),
file:write_file(File, Bytes2, [append]),
Bytes3 = lists:concat([" {", Field_name,
", Val, _} -> Player#player{other=Player#player.other#player_other{", Field_name,
" = Val}};\t\n"]),
file:write_file(File, Bytes3, [append]),
Bytes4 = lists:concat([" {", Field_name,
", Val} -> Player#player{other=Player#player.other#player_other{", Field_name,
" = Val}};\t\n"]),
file:write_file(File, Bytes4, [append])
end,
O_list),
lists:foreach(fun(Field_name) ->
case lists:member(Field_name, P_list) of
true -> %%player顶层成员,
Bytes11 = lists:concat([" {", Field_name,
", Val, add} -> Player1 = Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Player#player.battle_attr#battle_attr.", Field_name, " + Val}},\t\n"]),
file:write_file(File, Bytes11, [append]),
Bytes12 = lists:concat([" Player1#player{", Field_name, "=Player1#player.", Field_name, " + Val};\t\n"]),
file:write_file(File, Bytes12, [append]),
Bytes21 = lists:concat([" {", Field_name,
", Val, sub} -> Player1 = Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Player#player.battle_attr#battle_attr.", Field_name, " - Val}},\t\n"]),
file:write_file(File, Bytes21, [append]),
Bytes22 = lists:concat([" Player1#player{", Field_name, "=Player1#player.", Field_name, " - Val};\t\n"]),
file:write_file(File, Bytes22, [append]),
Bytes31 = lists:concat([" {", Field_name,
", Val, _} -> Player1 = Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Val}},\t\n"]),
file:write_file(File, Bytes31, [append]),
Bytes32 = lists:concat([" Player1#player{", Field_name, "= Val};\t\n"]),
file:write_file(File, Bytes32, [append]),
Bytes41 = lists:concat([" {", Field_name,
", Val} -> Player1 = Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Val}},\t\n"]),
file:write_file(File, Bytes41, [append]),
Bytes42 = lists:concat([" Player1#player{", Field_name, "= Val};\t\n"]),
file:write_file(File, Bytes42, [append]);
false ->
Bytes1 = lists:concat([" {", Field_name,
", Val, add} -> Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Player#player.battle_attr#battle_attr.", Field_name, " + Val}};\t\n"]),
file:write_file(File, Bytes1, [append]),
Bytes2 = lists:concat([" {", Field_name,
", Val, sub} -> Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Player#player.battle_attr#battle_attr.", Field_name, " - Val}};\t\n"]),
file:write_file(File, Bytes2, [append]),
Bytes3 = lists:concat([" {", Field_name,
", Val, _} -> Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Val}};\t\n"]),
file:write_file(File, Bytes3, [append]),
Bytes4 = lists:concat([" {", Field_name,
", Val} -> Player#player{battle_attr=Player#player.battle_attr#battle_attr{", Field_name,
" = Val}};\t\n"]),
file:write_file(File, Bytes4, [append])
end
end,
B_list),
file:write_file(File, " _ -> Player\t\n", [append]),
file:write_file(File, " end,\t\n", [append]),
file:write_file(File, " set_player_info_fields(NewPlayer, T).\t\n", [append]),
file:write_file(File, " \t\n", [append]),
file:write_file(File, "%%设置宠物信息(按[{字段1,值1},{字段2,值2, add},{字段3,值3, sub}...])\t\n", [append]),
file:write_file(File, "%% handle_cast({'SET_PET',[{x, 10} ,{y, 20, add}, ,{hp, 20, sub}]}, Status)\t\n", [append]),
io:format("Create ../src/lib/lib_player_rw.erl finished!~n~n"),
ok.
%%
table_fields_all(DB_name) ->
Filename = "../src/lib/lib_player_rw.erl",
Sql = lists:concat(["SELECT table_name FROM information_schema.tables WHERE table_schema='", tool:to_list(DB_name), "' and table_type ='BASE TABLE'"]),
try
case db_esql:get_all(list_to_binary(Sql)) of
[] -> error1;
A ->
file:write_file(Filename,
list_to_binary(io_lib:format("\t\n\t\n%% 根据表名获取其完全字段\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format("get_table_fields(Table_name) ->\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(" Table_fileds = [ \t\n", [])),
[append]),
L = lists:flatten(A),
F = fun(T) ->
%% io:format("~p~n",[T]),
Sql1 = lists:concat(["SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema= '", tool:to_list(DB_name), "' AND table_name= '", tool:to_list(T), "'"]),
case db_esql:get_all(list_to_binary(Sql1)) of
[] -> error2;
B ->
%% D = lists:flatten(B),
{DL, _} =
lists:mapfoldl(fun([Field, Data_type0, Default0], Sum) ->
Data_type = tool:to_atom(Data_type0),
Default =
case Default0 of
undefined ->
case erlydb_field:get_erl_type(Data_type) of
binary ->
"";
integer ->
0;
_ -> 0
end;
<<>> ->
case erlydb_field:get_erl_type(Data_type) of
binary ->
"";
integer ->
0;
_ -> ""
end;
<<"[]">> ->
[];
Val ->
case erlydb_field:get_erl_type(Data_type) of
binary ->
lists:concat(["", binary_to_list(Val), ""]);
integer ->
tool:to_integer(binary_to_list(Val));
decimal ->
tool:to_float(binary_to_list(Val));
_ ->
lists:concat([binary_to_list(Val)])
end
end,
S = if Sum == length(B) ->
io_lib:format("{~s, ~p}", [tool:to_atom(Field), Default]);
true ->
io_lib:format("{~s, ~p},", [tool:to_atom(Field), Default])
end,
{S, Sum + 1}
end,
1, B),
E = io_lib:format('{~s,[~s]}', [tool:to_atom(T), lists:flatten(DL)]),
file:write_file(Filename,
list_to_binary(io_lib:format(" ~s,\t\n", [E])),
[append]),
ok
end
end,
[F(T) || T <- L],
file:write_file(Filename,
list_to_binary(io_lib:format(' {null,""}], \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' case lists:keysearch(Table_name,1, Table_fileds) of \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' {value,{_, Val}} -> Val; \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' _ -> undefined \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' end. \t\n', [])),
[append]),
ok
end
catch
_:_ -> fail
end.
%%
get_all_tables(DB_name) ->
Filename = "../src/lib/lib_player_rw.erl",
Sql = lists:concat(["SELECT table_name FROM information_schema.tables WHERE table_schema='", tool:to_list(DB_name), "' and table_type ='BASE TABLE'"]),
try
case db_esql:get_all(list_to_binary(Sql)) of
[] -> error1;
A ->
file:write_file(Filename,
list_to_binary(io_lib:format("\t\n\t\n%% 获取所有表名\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format("get_all_tables() ->\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(" [ \t\n", [])),
[append]),
L = lists:flatten(A),
F = fun(T) ->
file:write_file(Filename,
list_to_binary(io_lib:format(" ~s,\t\n", [tool:to_atom(T)])),
[append])
end,
[F(T) || T <- L],
file:write_file(Filename,
list_to_binary(io_lib:format(' null \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(" ]. \t\n", [])),
[append]),
ok
end
catch
_:_ -> fail
end.
%% ()
table_fields_all_bak(DB_name) ->
Filename = "../src/lib/lib_player_rw.erl",
Sql = lists:concat(["SELECT table_name FROM information_schema.tables WHERE table_schema='", tool:to_list(DB_name), "' and table_type ='BASE TABLE'"]),
try
case db_esql:get_all(list_to_binary(Sql)) of
[] -> error1;
A ->
file:write_file(Filename,
list_to_binary(io_lib:format("\t\n\t\n%% 根据表名获取其完全字段\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format("get_table_fields(Table_name) ->\t\n", [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(" Table_fileds = [ \t\n", [])),
[append]),
L = lists:flatten(A),
F = fun(T) ->
%% io:format("~p~n",[T]),
Sql1 = lists:concat(["SELECT column_name FROM information_schema.columns WHERE table_schema= '", tool:to_list(DB_name), "' AND table_name= '", tool:to_list(T), "'"]),
case db_esql:get_all(list_to_binary(Sql1)) of
[] -> error2;
B ->
D = lists:flatten(B),
{DL, _} =
lists:mapfoldl(fun(F, Sum) ->
S = if Sum == length(D) ->
io_lib:format("~s", [tool:to_atom(F)]);
true ->
io_lib:format("~s,", [tool:to_atom(F)])
end,
{S, Sum + 1}
end,
1, D),
E = io_lib:format('{~s,"~s"}', [tool:to_atom(T), lists:flatten(DL)]),
file:write_file(Filename,
list_to_binary(io_lib:format(" ~s,\t\n", [E])),
[append]),
ok
end
end,
[F(T) || T <- L],
file:write_file(Filename,
list_to_binary(io_lib:format(' {null,""}], \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' case lists:keysearch(Table_name,1, Table_fileds) of \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' {value,{_, Val}} -> Val; \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' _ -> undefined \t\n', [])),
[append]),
file:write_file(Filename,
list_to_binary(io_lib:format(' end. \t\n', [])),
[append]),
ok
end
catch
_:_ -> fail
end.
%% --------------------------------------------------
%% time format
one_to_two(One) -> io_lib:format("~2..0B", [One]).
%% @doc get the time's seconds for integer type
%% @spec get_seconds(Time) -> integer()
get_seconds(Time) ->
{_MegaSecs, Secs, _MicroSecs} = Time,
Secs.
time_format(Now) ->
{{Y, M, D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ",
one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
date_format(Now) ->
{{Y, M, D}, {_H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D)]).
date_hour_format(Now) ->
{{Y, M, D}, {H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H)]).
date_hour_minute_format(Now) ->
{{Y, M, D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H), "-", one_to_two(MM)]).
%% split by -
minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), "-", one_to_two(MM)]).
hour_minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).

+ 492
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/table_to_erlang.erl Dosyayı Görüntüle

@ -0,0 +1,492 @@
%%%--------------------------------------
%%% @Module : game_gateway
%%% @Author :
%%% @Created : 2010.10.27
%%% @Description: mysql数据表 erl record
%%% "../include/table_to_record.hrl"
-module(table_to_erlang).
-compile(export_all).
%%
%% Include files
%%
-include("common.hrl").
-include("table_to_record.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
-define(TMP_TABLE_PATH, "./tmptable/").
-define(SRC_TABLE_PATH, "../src/table/").
-define(BEAM_PATH, "./").
-define(TABLES_TPLS, [
% Record名 %erlang文件名 %
{temp_combat_attr, temp_combat_attr, tpl_combat_attr, [1, 2]},
{temp_goods, temp_goods, tpl_goods, [1]},
{temp_goods_contain, temp_goods_contain, tpl_goods_contain, [1]},
{temp_goods_equipment, temp_goods_equipment, tpl_goods_equipment, [1]},
{temp_goods_gem, temp_goods_gem, tpl_goods_gem, [1]},
{temp_goods_suit, temp_goods_suit, tpl_goods_suit, [1, 2]},
%%{temp_mon_layout, temp_mon_layout, data_scene_mon, [1]} ,
%{temp_notice,temp_notice, []} ,
%{temp_npc,temp_npc, []} ,
{temp_npc_layout, temp_npc_layout, tpl_npc_layout, [2, 3]},
{temp_skill, temp_skill, tpl_skill, [1]},
{temp_skill_attr, temp_skill_attr, tpl_skill_attr, [2, 3]},
{temp_task, tpl_task, tpl_task, [1]},
%{temp_talk,temp_talk, temp_talk,[1]},
{temp_buff, temp_buff, tpl_buff, [1]},
{temp_drop_main, temp_drop_main, tpl_drop_main, [1]},
{temp_drop_sub, temp_drop_sub, tpl_drop_sub, [1]},
{temp_stren, temp_stren, tpl_stren, [1]},
{temp_polish, temp_polish, tpl_polish, [1]},
{temp_upgrade, temp_upgrade, tpl_upgrade, [1]},
{temp_task_detail, temp_task_detail, tpl_task_detail, [1]},
{temp_all_stren_reward, temp_all_stren_reward, tpl_all_stren_reward, [1]},
{temp_polish_goods, temp_polish_goods, tpl_polish_goods, [1]},
{temp_suit_reward, temp_suit_reward, tpl_suit_reward, [1, 2]},
{temp_all_gem_reward, temp_all_gem_reward, tpl_all_gem_reward, [1]},
{temp_gilding, temp_gilding, tpl_gilding, [1, 2]},
{temp_gold_bag, temp_gold_bag, tpl_gold_bag, [1]},
{temp_vip_bag, temp_vip_bag, tpl_vip_bag, [1]},
{temp_god_tried, temp_god_tried, tpl_god_tried, [1]},
{temp_compose, temp_compose, tpl_compose, [1]},
{temp_npc_shop, temp_npc_shop, tpl_npc_shop, [1, 2]},
{temp_meridian, tpl_meridian, tpl_meridian, [2, 3, 4]},
{temp_bones, tpl_bones, tpl_bones, [1]},
{temp_shop, temp_shop, tpl_shop, [1, 2]},
{temp_activity, temp_activity, tpl_activity, [1]},
{temp_activity_reward, temp_activity_reward, tpl_activity_reward, [1]},
{temp_mount_attr, temp_mount_attr, tpl_mount_attr, [2, 3]},
{temp_mount_medicine, temp_mount_medicine, tpl_mount_medicine, [1]},
{temp_mount_quality, temp_mount_quality, tpl_mount_quality, [1]},
{temp_mount_skill, temp_mount_skill, tpl_mount_skill, [2, 3]},
{temp_label, temp_label, tpl_label, [1]},
{temp_goods_buff, temp_goods_buff, tpl_goods_buff, [1]},
{temp_cultivation, tpl_cultivation, tpl_cultivation, [1]},
{temp_pet, temp_pet, tpl_pet, [1]},
{temp_pet_quality, temp_pet_quality, tpl_pet_quality, [1]},
{temp_pet_growth, temp_pet_growth, tpl_pet_growth, [1]},
{temp_pet_aptitude, temp_pet_aptitude, tpl_pet_aptitude, [1]},
{temp_pet_medicine, temp_pet_medicine, tpl_pet_medicine, [1]},
{temp_dungeon_group, temp_dungeon_group, tpl_dungeon_group, [1]},
{temp_dungeon, temp_dungeon, tpl_dungeon, [1]},
{temp_dungeon_trigger, temp_dungeon_trigger, tpl_dungeon_trigger, [2, 3]},
{temp_dungeon_obj, temp_dungeon_obj, tpl_dungeon_obj, [2, 3, 4]},
{temp_rand_shop, temp_rand_shop, tpl_rand_shop, [1]},
{temp_rand_shop_goods, temp_rand_shop_goods, tpl_rand_shop_goods, [1]},
{temp_goods_facade, temp_goods_facade, tpl_goods_facade_ex, [1, 2]},
{temp_goods_facade, temp_goods_facade, tpl_goods_facade, [1]},
{temp_pet_skill_book, temp_pet_skill_book, tpl_pet_skill_book, [4]},
{temp_mon_ai, temp_mon_ai, tpl_mon_ai, [1]},
{temp_tips, temp_tips, tpl_tips, [1]},
{temp_task_factor, temp_task_factor, tpl_task_factor, [1, 2]},
{temp_level_bag, temp_level_bag, tpl_level_bag, [1]},
{temp_energy, temp_energy, tpl_energy, [2, 3]},
{temp_download_gift, temp_download_gift, tpl_download_gift, [1]},
{temp_vip, temp_vip, tpl_vip, [1]},
{temp_vip, temp_vip, tpl_vip2, [9]},
{temp_guild_level, temp_guild_level, tpl_guild_level, [1]},
{temp_charge, temp_charge, tpl_charge, [1]},
{temp_guild_contribution, temp_guild_contribution, tpl_guild_contribution, [1]},
{temp_pet_skill_list, temp_pet_skill_list, tpl_pet_skill_list, [1]},
{temp_all_polish_reward, temp_all_polish_reward, tpl_all_polish_reward, [1]},
{temp_skill_point, temp_skill_point, tpl_skill_point, [1]},
{temp_task_daily, tpl_task_daily, tpl_task_daily, [2]},
{temp_cdkey_awards, temp_cdkey_awards, tpl_cdkey_awards, [1]}
]).
%%
-define(TABLES_LIST, [
% %erlang文件名 % %Id名
{temp_task, tpl_task, [type], [tid]},
{temp_task, tpl_task, [type, level], [tid]},
{temp_dungeon, tpl_dungeon, [grp], [sid]},
{temp_dungeon_trigger, tpl_dungeon_trigger, [sid], [sid, action]},
{temp_mount_skill, tpl_mount_skill, [mount_level], [sid, level]},
{temp_label, tpl_label, [type, condition_id], [leader_id]},
{temp_activity, tpl_activity, [btype, stype], [id]},
{temp_dungeon_obj, tpl_dungeon_obj, [dun_id], [dun_id, obj_id, action]},
{temp_rand_shop_goods, tpl_rand_shop_goods, [goods_lv], [goods_id]},
{temp_goods_facade, tpl_goods_facade_ex, [facade], [gtid, facade]},
{temp_goods_facade, tpl_goods_facade, [facade], [gtid]},
{temp_pet_skill_list, tpl_pet_skill_list, [type, condition_id], [list_id]},
{temp_pet_skill_book, tpl_pet_skill_book, [sid, skill_level], [skill_book_id]}
%% {temp_task, tpl_task,[type,tid,ongoing_dialog],tid},
%% {temp_task, tpl_task,[type],tid} ,
%% {temp_skill_buff,tpl_skill_buff,[name],buff_id},
%% {temp_task, tpl_task,[start_npc],tid}
]).
%%
%% Exported Functions
%%
%%
%% API Functions
%%
start() ->
case get_db_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB, Encode, _Conns] ->
start_erlydb(Host, Port, User, Password, DB),
mysql:start_link(?DB_SERVER, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?DB_SERVER, Host, Port, User, Password, DB, Encode, true),
tables_to_erlang(),
tables_to_erlang_list(),
ok;
_ -> mysql_config_fail
end,
halt(),
ok.
get_db_config(Config_file) ->
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(mysql_config, 1, C),
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
{_, Conns} = lists:keyfind(conns, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode, Conns].
%%
%% Local Functions
%%
start_erlydb(IP, Port, User, Password, Db) ->
erlydb:start(mysql, [{pool_id, erlydb_mysql},
{hostname, IP},
{port, Port},
{username, User},
{password, Password},
{database, Db},
{logfun, fun(_, _, _, _) -> ok end},
{encoding, utf8},
{pool_size, 10}]).
%% @doc beam文件
%% @spec code_gen/0
%% unilog_mysql_pool:code_gen()
code_gen() ->
code_gen(?TABLES_TPLS).
code_gen(TableName) ->
TableList = writeTempFile(TableName),
erlydb:code_gen(TableList, {mysql,
[{allow_unsafe_statements, true},
{skip_fk_checks, true}]},
[debug_info, {skip_fk_checks, true},
{outdir, "../ebin/"}]),
clearTempFile(),
ok.
%% @doc beam生成erl文件便
%% code_gen()beam文件
%% @spec code_gen_src/0
code_gen_src() ->
lists:foreach(fun(TableName) ->
Beam = lists:concat([?BEAM_PATH, TableName, ".beam"]),
case beam_lib:chunks(Beam, [abstract_code]) of
{ok, {_, [{abstract_code, {_, AC}}]}} ->
Code = erl_prettypr:format(erl_syntax:form_list(AC)),
file:write_file(lists:concat([?SRC_TABLE_PATH, TableName, ".erl"]), list_to_binary(Code)),
io:format("build beam:~p to erl:~p success.~n", [TableName, TableName]);
{error, beam_lib, Reason} ->
io:format("code_gen_erl_file error, reason:~p~n", [Reason])
end
end, ?TABLES_TPLS).
%% @doc module文件code_gen/0 使
%% @spec writeTempFile/0 ->[TableFilePath]
%% eg: TableFilePath -> "./tmptable/tuser_friend_log.erl"
writeTempFile(TableName) ->
clearTempFile(),
ok = file:make_dir(?TMP_TABLE_PATH),
lists:map(fun(F) ->
Filename =
?TMP_TABLE_PATH ++ atom_to_list(F) ++ ".erl",
Bytes = list_to_binary(io_lib:format("-module(~w).", [F])),
file:write_file(Filename, Bytes),
Filename
end, TableName).
clearTempFile() ->
case file:list_dir(?TMP_TABLE_PATH) of
{ok, Filenames} ->
lists:foreach(fun(F) ->
file:delete(?TMP_TABLE_PATH ++ F) end, Filenames);
{error, _} -> ignore
end,
file:del_dir(?TMP_TABLE_PATH).
%% time format
one_to_two(One) -> io_lib:format("~2..0B", [One]).
%% @doc get the time's seconds for integer type
%% @spec get_seconds(Time) -> integer()
get_seconds(Time) ->
{_MegaSecs, Secs, _MicroSecs} = Time,
Secs.
time_format(Now) ->
{{Y, M, D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ",
one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
date_format(Now) ->
{{Y, M, D}, {_H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D)]).
date_hour_format(Now) ->
{{Y, M, D}, {H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H)]).
date_hour_minute_format(Now) ->
{{Y, M, D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H), "-", one_to_two(MM)]).
%% split by -
minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), "-", one_to_two(MM)]).
hour_minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
tables_to_erlang() ->
io:format("~nstart converting table to erlang data TABLES_TPLS ~n", []),
F = fun({TableName, RecordName, FileName, ParamList}) ->
table_to_erlang(atom_to_list(TableName), atom_to_list(RecordName), atom_to_list(FileName), ParamList)
end,
lists:foreach(F, ?TABLES_TPLS).
table_to_erlang(TableName, RecordName, FileName, ParamList) ->
io:format("~s => ~s.erl, \tTable fields ~p as parametes~n", [TableName, FileName, ParamList]),
DataFileName = lists:concat(["../src/data/", FileName, ".erl"]),
%Bakfile = re:replace(lists:flatten(lists:concat([DataFileName , "_", time_format(now())])),"[ :]","_",[global,{return,list}]),
%file:rename(DataFileName, Bakfile),
file:write_file(DataFileName, ""),
file:write_file(DataFileName, "%%%------------------------------------------------\t\n", [append]),
FileBytes = list_to_binary(io_lib:format("%%% File : ~s.erl\t\n", [FileName])),
file:write_file(DataFileName, FileBytes, [append]),
file:write_file(DataFileName, "%%% Author : table_to_erlang\t\n", [append]),
%Bytes = list_to_binary(io_lib:format("%%% Created : ~s\t\n", [time_format(now())])),
Bytes = list_to_binary("%%% Created : \n"),
file:write_file(DataFileName, Bytes, [append]),
TableNameBytes = list_to_binary(io_lib:format("%%% Description:从数据库表~s生成\n", [TableName])),
file:write_file(DataFileName, TableNameBytes, [append]),
file:write_file(DataFileName, "%%% WARNING:程序生成,请不要增加手工代码!\n", [append]),
file:write_file(DataFileName, "%%%------------------------------------------------ \t\n", [append]),
file:write_file(DataFileName, " \t\n", [append]),
ModuleName = lists:concat(["-module(", FileName, ")."]),
file:write_file(DataFileName, ModuleName, [append]),
file:write_file(DataFileName, " \t\n", [append]),
file:write_file(DataFileName, "-compile(export_all).", [append]),
file:write_file(DataFileName, " \t\n", [append]),
%%MYSQL查表所有内容
Sql = io_lib:format("select * from ~s;", [TableName]),
Lists = db_esql:get_all(Sql),
TableRecordAtom = list_to_atom(RecordName),
F = fun(ValueList) ->
list_to_tuple([TableRecordAtom | ValueList])
end,
RecordList = lists:map(F, Lists),
%[Key1|T] = ParamList,
%SortedRecordList = lists:keysort(Key1+1, RecordList),
SortedRecordList = lists:sort(RecordList),
F2 = fun(Record) ->
record_to_erlang(DataFileName, Record, ParamList)
end,
lists:foreach(F2, SortedRecordList),
record_to_erlang_end(DataFileName, ParamList).
%%Erlang文件, Record为数据库一条记录对应的Record
%%DataFileName为文件名 ParamList为入口参数列表[]
%%get(Level, Career), ParamList应该指定 Level,Career在数据表位置
record_to_erlang(DataFileName, Record, ParamList) ->
[RecordName | ValueList] = tuple_to_list(Record),
F1 = fun(Index) ->
Idx = lists:nth(Index, ParamList),
Value = lists:nth(Idx, ValueList),
if Index =:= length(ParamList) ->
Bytes = lists:concat([integer_to_list(Value), ")->\n\t"]);
true ->
Bytes = lists:concat([integer_to_list(Value), ", "])
end,
file:write_file(DataFileName, list_to_binary(Bytes), [append])
end,
%%get(xxx,xxx) ->
file:write_file(DataFileName, "\t\n", [append]),
file:write_file(DataFileName, "get(", [append]),
lists:foreach(F1, lists:seq(1, length(ParamList))),
%% {record_name,
file:write_file(DataFileName, list_to_binary(io_lib:format("{~s, ", [RecordName])), [append]),
F2 = fun(Index2) ->
Value2 = lists:nth(Index2, ValueList),
if is_integer(Value2) ->
if Index2 =:= length(ValueList) ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~p};", [Value2])), [append]);
true ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~p, ", [Value2])), [append])
end;
%%()
is_list(Value2) orelse is_binary(Value2) ->
Value3 = case is_binary(Value2) of
true -> binary_to_list(Value2);
false -> Value2
end,
if Index2 =:= length(ValueList) ->
%%[(91),{(123),"(34)开头,如果是, 不在前面加引号, 否则输出字符串时加引号
case length(Value3) >= 1 andalso
(lists:nth(1, Value3) =:= 91 orelse lists:nth(1, Value3) =:= 123 orelse lists:nth(1, Value3) =:= 34) of
true ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~s};", [Value3])), [append]);
false ->
file:write_file(DataFileName, list_to_binary(io_lib:format("<<\"~s\">>};", [Value3])), [append])
end;
true ->
%%[(91),{(123),"(34)开头,如果是, 不在前面加引号, 否则输出字符串时加引号
case length(Value3) >= 1 andalso
(lists:nth(1, Value3) =:= 91 orelse lists:nth(1, Value3) =:= 123 orelse lists:nth(1, Value3) =:= 34) of
true ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~s,", [Value3])), [append]);
false ->
file:write_file(DataFileName, list_to_binary(io_lib:format("<<\"~s\">>, ", [Value3])), [append])
end
end;
true ->
if Index2 =:= length(ValueList) ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~p};", [Value2])), [append]);
true ->
file:write_file(DataFileName, list_to_binary(io_lib:format("~p, ", [Value2])), [append])
end
end
end,
lists:foreach(F2, lists:seq(1, length(ValueList))).
%% %%get(_,_, ...) -> [].
record_to_erlang_end(DataFileName, ParamList) ->
F = fun(Index) ->
if Index =:= length(ParamList) ->
Bytes = "_)->\t\n";
true ->
Bytes = "_, "
end,
file:write_file(DataFileName, list_to_binary(Bytes), [append])
end,
file:write_file(DataFileName, "\t\n", [append]),
file:write_file(DataFileName, "get(", [append]),
lists:foreach(F, lists:seq(1, length(ParamList))),
file:write_file(DataFileName, "\t[].\t\n", [append]).
%%============erlang列表=============
tables_to_erlang_list() ->
io:format("~nstart converting table to erlang data list~n", []),
F = fun({TableName, FileName, ParamList, IdList}) ->
conver_start(atom_to_list(TableName), atom_to_list(FileName), ParamList, list_to_string(IdList))
end,
lists:foreach(F, ?TABLES_LIST).
%%
conver_start(TableName, FileName, ParamList, IdList) ->
io:format("~s => ~s.erl, \tTable fields ~p as parametes~n", [TableName, FileName, ParamList]),
DataFileName = lists:concat(["../src/data/", FileName, ".erl"]),
get_filter_data(DataFileName, TableName, ParamList, IdList, FileName).
get_filter_data(DataFileName, TableName, ParamList, IdList, FileName) ->
F = fun(Param, Result) ->
case Result of
0 -> lists:concat([Param]);
_ -> lists:concat([Result, ",", Param]) end end,
Res = lists:foldl(F, 0, ParamList),
Sql = io_lib:format("select distinct ~s from ~s;", [Res, TableName]),
Lists = db_esql:get_all(Sql),
lists:foreach(fun(Obj) ->
construts_data(DataFileName, TableName, ParamList, Obj, IdList, FileName) end, Lists),
EndRes = lists:foldl(fun(_Item, Sum) ->
case Sum of
0 -> ["_"];
_ -> Sum ++ ["_"] end end, 0, ParamList),
make_fun_head(DataFileName, ParamList, EndRes),
file:write_file(DataFileName, " [].\t\n", [append]).
%%erlang函数
construts_data(DataFileName, TableName, ParamList, Res, IdList, FileName) ->
Filter = for(ParamList, Res, 0, length(ParamList), []),
Sql = io_lib:format("select ~s from ~s ~s;", [IdList, TableName, Filter]),
Lists = db_esql:get_all(Sql),
%%get(xxx,xxx) ->
make_fun_head(DataFileName, ParamList, Res),
file:write_file(DataFileName, " lists:map(fun([", [append]),
file:write_file(DataFileName, string:to_upper(IdList), [append]),
file:write_file(DataFileName, "])->", [append]),
file:write_file(DataFileName, FileName, [append]),
file:write_file(DataFileName, ":get(", [append]),
file:write_file(DataFileName, string:to_upper(IdList), [append]),
file:write_file(DataFileName, ") end,\n\t", [append]),
file:write_file(DataFileName, term_to_string(Lists), [append]),
file:write_file(DataFileName, ");\t\n", [append]).
%%
make_fun_head(DataFileName, ParamList, Res) ->
file:write_file(DataFileName, "\t\n", [append]),
file:write_file(DataFileName, "get_by", [append]),
lists:foreach(fun(Item) ->
file:write_file(DataFileName, lists:concat(["_", Item]), [append]) end, ParamList),
file:write_file(DataFileName, "(", [append]),
lists:foldl(fun(Index, Sum) ->
Value = lists:nth(Index, Res),
R = case is_binary(Value) of
true ->
lists:concat(["\"", binary_to_list(Value), "\""]);
false ->
Value end,
case Sum of
0 ->
file:write_file(DataFileName, lists:concat([R]), [append]);
_ ->
file:write_file(DataFileName, lists:concat([",", R]), [append]) end
end, 0, lists:seq(1, length(ParamList))),
file:write_file(DataFileName, ")->\t\n", [append]).
%%where语句
for(_ParamList, _ResList, _Index, _Index, Out) ->
Out;
for(ParamList, ResList, I, Index, Out) ->
[Pamram | PRest] = ParamList,
[TempRes | RRest] = ResList,
Res = convert_bin_4(TempRes),
Sql = case I of
0 ->
lists:concat([" where ", Pamram, "=", Res]);
_ ->
lists:concat([Out, " and ", Pamram, "=", Res]) end,
for(PRest, RRest, I + 1, Index, Sql).
convert_bin_4(In) ->
case is_binary(In) of
true ->
lists:concat(["'", binary_to_list(In), "'"]);
false ->
In end.
%%string [a,b,c] -> "a,b,c"
list_to_string(List) ->
case List == [] orelse List == "" of
true -> "";
false ->
F = fun(E) ->
atom_to_list(E) ++ ","
end,
L1 = [F(E) || E <- List],
L2 = lists:concat(L1),
string:substr(L2, 1, length(L2) - 1)
end.
%% term序列化term转换为string格式e.g., [{a},1] => "[{a},1]"
term_to_string(Term) ->
binary_to_list(list_to_binary(io_lib:format("~w", [Term]))).

+ 552
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/table_to_record.erl Dosyayı Görüntüle

@ -0,0 +1,552 @@
%%%--------------------------------------
%%% @Module : game_gateway
%%% @Author : csj
%%% @Created : 2010.10.27
%%% @Description: mysql数据表 erl record
%%% "../include/table_to_record.hrl"
%%%--------------------------------------
-module(table_to_record).
%%
%% Include files
%%
-include("common.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
-define(TMP_TABLE_PATH, "./tmptable/").
-define(SRC_TABLE_PATH, "../src/table/").
-define(RECORD_FILENAME, "../include/table_to_record.hrl").
-define(BEAM_PATH, "./").
-define(TABLES,
[
{server, server},
{config_server, config_server},
{server_player, server_player},
{player, player},
{goods, goods},
{goods_attribute, goods_attribute},
{skill, skill},
{system_config, system_config},
{feedback, feedback},
{temp_combat_attr, temp_combat_attr},
{temp_goods, temp_goods},
{temp_goods_contain, temp_goods_contain},
{temp_goods_equipment, temp_goods_equipment},
{temp_goods_gem, temp_goods_gem},
{temp_goods_suit, temp_goods_suit},
{temp_mon_layout, temp_mon_layout},
{temp_notice, temp_notice},
{temp_npc, temp_npc},
{temp_npc_layout, temp_npc_layout},
{temp_scene, temp_scene},
{temp_skill, temp_skill},
{temp_buff, temp_buff},
{temp_skill_attr, temp_skill_attr},
{mount, mount},
{leader, leader},
{activity, activity},
{bubble_msg, bubble_msg},
{business_announce, business_announce},
{contact, contact},
{relation, relation},
{temp_drop_main, temp_drop_main},
{temp_drop_sub, temp_drop_sub},
{temp_task, tpl_task}, %
{temp_task_detail, temp_task_detail},%
{task_finish, task_finish}, %
{task_process, task_process},%
{temp_stren, temp_stren},
{temp_compose, temp_compose},
{temp_polish, temp_polish},
{temp_upgrade, temp_upgrade},
{temp_all_stren_reward, temp_all_stren_reward},
{casting_polish, casting_polish},
{temp_polish_goods, temp_polish_goods},
{temp_suit_reward, temp_suit_reward},
{temp_all_gem_reward, temp_all_gem_reward},
{temp_gilding, temp_gilding},
{temp_gold_bag, temp_gold_bag},
{temp_level_bag, temp_level_bag},
{temp_vip_bag, temp_vip_bag},
{temp_god_tried, temp_god_tried},
{guild, guild},
{guild_member, guild_member},
{guild_apply, guild_apply},
{buy_npc_shop_log, buy_npc_shop_log},
{temp_npc_shop, temp_npc_shop},
{goods_cd, goods_cd},
{temp_meridian, tpl_meridian},
{temp_bones, tpl_bones},
{meridian, meridian},
{bones, bones},
{temp_shop, temp_shop},
{buy_shop_log, buy_shop_log},
{pet, pet},
{temp_mount_attr, temp_mount_attr},
{temp_mount_skill, temp_mount_skill},
{temp_label, temp_label},
{temp_activity, temp_activity},
{temp_activity_reward, temp_activity_reward},
{buff, buff},
{temp_cultivation, tpl_cultivation},
{cultivation, cultivation},
{temp_goods_buff, temp_goods_buff},
{temp_pet, temp_pet},
{temp_pet_quality, temp_pet_quality},
{temp_pet_growth, temp_pet_growth},
{temp_pet_aptitude, temp_pet_aptitude},
{temp_pet_medicine, temp_pet_medicine},
{temp_goods_facade, temp_goods_facade},
{temp_dungeon_group, temp_dungeon_group},
{temp_dungeon, temp_dungeon},
{temp_dungeon_trigger, temp_dungeon_trigger},
{temp_dungeon_obj, temp_dungeon_obj},
{dungeon_daily, dungeon_daily},
{dungeon_finish, dungeon_finish},
{dungeon_master, dungeon_master},
{temp_pet_skill_book, temp_pet_skill_book},
{temp_mon_ai, temp_mon_ai},
{ban_account_list, ban_account_list},
{ban_ip_list, ban_ip_list},
{sys_announce, sys_announce},
{temp_tips, temp_tips},
{task_master, task_master},
{heaven, heaven},
{task_heaven, task_heaven},
{temp_task_factor, temp_task_factor},
{task_daily, task_daily},
{temp_energy, temp_energy},
{opera, opera},
{scene_gift, scene_gift},
{temp_download_gift, temp_download_gift},
{temp_vip, temp_vip},
{temp_rand_shop, temp_rand_shop},
{temp_rand_shop_goods, temp_rand_shop_goods},
{rand_shop, rand_shop},
{market_selling, market_selling},
{market_request, market_request},
{temp_guild_level, temp_guild_level},
{temp_charge, temp_charge},
{temp_guild_contribution, temp_guild_contribution},
{temp_pet_skill_list, temp_pet_skill_list},
{temp_all_polish_reward, temp_all_polish_reward},
{temp_skill_point, temp_skill_point},
{temp_task_daily, tpl_task_daily},
{temp_cdkey_awards, temp_cdkey_awards}
]).
-record(erlydb_field,
{name, name_str, name_bin, type, modifier, erl_type,
html_input_type,
null, key,
default, extra, attributes}).
%%
%% Exported Functions
%%
-compile(export_all).
%%
%% API Functions
%%
start() ->
case get_db_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB, Encode, _Conns] ->
start_erlydb(Host, Port, User, Password, DB),
mysql:start_link(?DB_SERVER, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?DB_SERVER, Host, Port, User, Password, DB, Encode, true),
tables_to_record(),
%% get_date_box(),
%% make_data_box:get_data_box(),
ok;
_ ->
mysql_config_fail
end,
halt(),
ok.
get_db_config(Config_file) ->
{ok, [L]} = file:consult(Config_file),
{_, C} = lists:keyfind(gateway, 1, L),
{_, Mysql_config} = lists:keyfind(mysql_config, 1, C),
{_, Host} = lists:keyfind(host, 1, Mysql_config),
{_, Port} = lists:keyfind(port, 1, Mysql_config),
{_, User} = lists:keyfind(user, 1, Mysql_config),
{_, Password} = lists:keyfind(password, 1, Mysql_config),
{_, DB} = lists:keyfind(db, 1, Mysql_config),
{_, Encode} = lists:keyfind(encode, 1, Mysql_config),
{_, Conns} = lists:keyfind(conns, 1, Mysql_config),
[Host, Port, User, Password, DB, Encode, Conns].
%%
%% Local Functions
%%
start_erlydb(IP, Port, User, Password, Db) ->
erlydb:start(mysql, [{pool_id, erlydb_mysql},
{hostname, IP},
{port, Port},
{username, User},
{password, Password},
{database, Db},
{logfun, fun(_, _, _, _) -> ok end},
{encoding, utf8},
{pool_size, 10}]).
%% @doc beam文件
%% @spec code_gen/0
%% unilog_mysql_pool:code_gen()
code_gen() ->
code_gen(?TABLES).
code_gen(TableName) ->
TableList = writeTempFile(TableName),
%% io:format("TableList=~p~n~n",[TableList]),
erlydb:code_gen(TableList, {mysql,
[{allow_unsafe_statements, true},
{skip_fk_checks, true}]},
[debug_info, {skip_fk_checks, true},
{outdir, "../ebin/"}]),
clearTempFile(),
ok.
%% @doc beam生成erl文件便
%% code_gen()beam文件
%% @spec code_gen_src/0
code_gen_src() ->
lists:foreach(fun(TableName) ->
Beam = lists:concat([?BEAM_PATH, TableName, ".beam"]),
case beam_lib:chunks(Beam, [abstract_code]) of
{ok, {_, [{abstract_code, {_, AC}}]}} ->
Code = erl_prettypr:format(erl_syntax:form_list(AC)),
file:write_file(lists:concat([?SRC_TABLE_PATH, TableName, ".erl"]), list_to_binary(Code)),
io:format("build beam:~p to erl:~p success.~n", [TableName, TableName]);
{error, beam_lib, Reason} ->
io:format("code_gen_erl_file error, reason:~p~n", [Reason])
end
end, ?TABLES).
%% @doc module文件code_gen/0 使
%% @spec writeTempFile/0 ->[TableFilePath]
%% eg: TableFilePath -> "./tmptable/tuser_friend_log.erl"
writeTempFile(TableName) ->
clearTempFile(),
ok = file:make_dir(?TMP_TABLE_PATH),
lists:map(fun(F) ->
Filename =
?TMP_TABLE_PATH ++ atom_to_list(F) ++ ".erl",
Bytes = list_to_binary(io_lib:format("-module(~w).", [F])),
file:write_file(Filename, Bytes),
Filename
end, TableName).
clearTempFile() ->
case file:list_dir(?TMP_TABLE_PATH) of
{ok, Filenames} ->
lists:foreach(fun(F) ->
file:delete(?TMP_TABLE_PATH ++ F) end, Filenames);
{error, _} -> ignore
end,
file:del_dir(?TMP_TABLE_PATH).
tables_to_record() ->
io:format("starting table to record ...~n"),
Bakfile = re:replace(
lists:flatten(lists:concat([?RECORD_FILENAME, "_", time_format(now())])),
"[ :]", "_", [global, {return, list}]),
lists:flatten(lists:concat([?RECORD_FILENAME, "_", time_format(now())])),
file:rename(?RECORD_FILENAME, Bakfile),
file:write_file(?RECORD_FILENAME, ""),
file:write_file(?RECORD_FILENAME, "%%%------------------------------------------------\t\n", [append]),
file:write_file(?RECORD_FILENAME, "%%% File : table_to_record.erl\t\n", [append]),
file:write_file(?RECORD_FILENAME, "%%% Author : smxx\t\n", [append]),
Bytes = list_to_binary(io_lib:format("%%% Created : ~s\t\n", [time_format(now())])),
file:write_file(?RECORD_FILENAME, Bytes, [append]),
file:write_file(?RECORD_FILENAME, "%%% Description: 从mysql表生成的record\t\n", [append]),
file:write_file(?RECORD_FILENAME, "%%% Warning: 由程序自动生成,请不要随意修改!\t\n", [append]),
file:write_file(?RECORD_FILENAME, "%%%------------------------------------------------ \t\n", [append]),
file:write_file(?RECORD_FILENAME, " \t\n", [append]),
io:format("~n~n"),
lists:foreach(fun(Table) ->
case Table of
{Table_name, Record_name} -> table_to_record(Table_name, Record_name, "");
{Table_name, Record_name, TableComment} -> table_to_record(Table_name, Record_name, TableComment);
_ -> no_action
end
end,
?TABLES),
io:format("finished!~n~n"),
ok.
%% table_to_record:table_to_record(user, 1).
%% [A,B]=db_esql:get_row("show create table user;")
%% db_esql:get_row("select * from base_goods_type;")
table_to_record(Table_name, Record_name, TableComment) ->
file:write_file(?RECORD_FILENAME, "\t\n", [append]),
Sql = lists:concat(["show create table ", Table_name]),
try
case db_esql:get_row(Sql) of
{db_error, _} ->
error;
[_, A | _] ->
Create_table_list = re:split(A, "[\n]", [{return, binary}]),
Table_comment =
case TableComment of
"" -> get_table_comment(Create_table_list, Table_name);
_ -> TableComment
end,
file:write_file(?RECORD_FILENAME,
list_to_binary(io_lib:format("%% ~s\t\n", [Table_comment])),
[append]),
file:write_file(?RECORD_FILENAME,
list_to_binary(io_lib:format("%% ~s ==> ~s \t\n", [Table_name, Record_name])),
[append]),
file:write_file(?RECORD_FILENAME,
list_to_binary(io_lib:format("-record(~s, {\t\n", [Record_name])),
[append]),
code_gen([Table_name]),
Table_fields = erlang:apply(Table_name, db_fields, []),
lists:mapfoldl(fun(Field, Sum) ->
Field_comment = get_field_comment(Create_table_list, Sum),
Default =
case Field#erlydb_field.default of
undefined -> '';
<<>> ->
case erlydb_field:get_erl_type(Field#erlydb_field.type) of
binary ->
lists:concat([" = \"\""]);
integer ->
lists:concat([" = 0"]);
_ -> ''
end;
<<"[]">> ->
lists:concat([" = ", binary_to_list(Field#erlydb_field.default)]);
Val ->
case erlydb_field:get_erl_type(Field#erlydb_field.type) of
binary ->
lists:concat([" = <<\"", binary_to_list(Val), "\">>"]);
_ ->
lists:concat([" = ", binary_to_list(Val)])
end
end,
T1 =
if Sum == length(Table_fields) ->
'';
true -> ','
end,
T2 = io_lib:format("~s~s~s",
[Field#erlydb_field.name,
Default,
T1]),
T3 = lists:duplicate(40 - length(lists:flatten(T2)), " "),
Bytes = list_to_binary(io_lib:format(" ~s~s%% ~s\t\n",
[T2,
T3,
Field_comment])),
file:write_file(?RECORD_FILENAME,
Bytes,
[append]),
{
[],
Sum + 1
}
end,
1, Table_fields),
file:write_file(?RECORD_FILENAME,
list_to_binary(io_lib:format(" }).\t\n", [])),
[append]),
io:format(" ~s ==> ~s ~n", [Table_name, Record_name]),
ok
end
catch
_:_ ->
io:format("error when getting ~s ==> ~s ~n", [Table_name, Record_name]),
error
end.
get_field_comment(Create_table_list, Loc) ->
try
%% L1 = re:split(lists:nth(Loc+1, Create_table_list),"[ ]",[{return, list}]),
L1 = binary_to_list(lists:nth(Loc + 1, Create_table_list)),
%% io:format("L1 = ~p ~n", [L1]),
Loc1 = string:rstr(L1, "COMMENT "),
%% io:format("Loc = ~p ~n", [Loc1]),
case Loc1 > 0 of
true ->
L2 = string:substr(L1, Loc1 + 8),
L3 = lists:subtract(L2, [39, 44]),
lists:subtract(L3, [39]);
_ -> ""
end
catch
_:_ -> ""
end.
get_table_comment(Create_table_list, Table_name) ->
try
%% L1 = re:split(lists:nth(Loc+1, Create_table_list),"[ ]",[{return, list}]),
Len = length(Create_table_list),
L1 = binary_to_list(lists:nth(Len, Create_table_list)),
%% io:format("L1 = ~p ~n", [L1]),
Loc1 = string:rstr(L1, "COMMENT="),
%% io:format("Loc = ~p ~n", [Loc1]),
case Loc1 > 0 of
true ->
L2 = string:substr(L1, Loc1 + 8),
L3 = lists:subtract(L2, [39, 44]),
lists:subtract(L3, [39]);
_ -> Table_name
end
catch
_:_ -> Table_name
end.
%% time format
one_to_two(One) -> io_lib:format("~2..0B", [One]).
%% @doc get the time's seconds for integer type
%% @spec get_seconds(Time) -> integer()
get_seconds(Time) ->
{_MegaSecs, Secs, _MicroSecs} = Time,
Secs.
time_format(Now) ->
{{Y, M, D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ",
one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
date_format(Now) ->
{{Y, M, D}, {_H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D)]).
date_hour_format(Now) ->
{{Y, M, D}, {H, _MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H)]).
date_hour_minute_format(Now) ->
{{Y, M, D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([Y, "-", one_to_two(M), "-", one_to_two(D), " ", one_to_two(H), "-", one_to_two(MM)]).
%% split by -
minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, _S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), "-", one_to_two(MM)]).
hour_minute_second_format(Now) ->
{{_Y, _M, _D}, {H, MM, S}} = calendar:now_to_local_time(Now),
lists:concat([one_to_two(H), ":", one_to_two(MM), ":", one_to_two(S)]).
%% ------------------------------------------------------------------------------------------------------
%% *********************************mysql表生成的诛邪系统物品概率碰撞表 start ****************************
%% ------------------------------------------------------------------------------------------------------
get_date_box() ->
Careers = lists:seq(1, 5),
lists:map(fun get_data_box_career/1, Careers).
get_data_box_career(Career) ->
%% DataFileName = lists:concat(["../src/data/data_box_", Career, ".erl"]),
%% Bakfile = re:replace(
%% lists:flatten(lists:concat([DataFileName , "_", time_format(now())])),
%% "[ :]","_",[global,{return,list}]),
%%
%% file:rename(DataFileName, Bakfile),
%%
%% file:write_file(DataFileName, ""),
%% file:write_file(DataFileName, "%%%------------------------------------------------\t\n",[append]),
%% file:write_file(DataFileName, "%%% File : data_box_X.erl\t\n",[append]),
%% file:write_file(DataFileName, "%%% Author : xiaomai\t\n",[append]),
%% Bytes = list_to_binary(io_lib:format("%%% Created : ~s\t\n", [time_format(now())])),
%% file:write_file(DataFileName, Bytes,[append]),
%% file:write_file(DataFileName, "%%% Description: 从mysql表生成的诛邪系统物品概率碰撞表\t\n",[append]),
%% file:write_file(DataFileName, "%%% Warning: 由程序自动生成,请不要随意修改!\t\n",[append]),
%% file:write_file(DataFileName, "%%%------------------------------------------------ \t\n",[append]),
%% file:write_file(DataFileName, " \t\n",[append]),
%% ModuleName = lists:concat(["-module(data_box_",Career,")."]),
%% file:write_file(DataFileName, ModuleName,[append]),
%% file:write_file(DataFileName, " \t\n\n",[append]),
%% file:write_file(DataFileName, "-export([get_goods_one/3]).",[append]),
%% file:write_file(DataFileName, " \t\n",[append]),
%% file:write_file(DataFileName, " \t\n",[append]),
%% file:write_file(DataFileName, "get_goods_one(HoleType, Career, RandomCount) ->\n\t",[append]),
Counts = lists:seq(1, 3),
lists:map(fun(Elem) -> handle_data_box_each(Career, Elem) end, Counts),
%% ErCodeend = "GoodsInfo = lists:concat([\"Goods_info_\", HoleType, Elem, \"00\"]),
%% %%
%% {BaseGoodsId} = lists:nth(RandomCount, GoodsInfo),
%% BaseGoodsId.",
%% file:write_file(DataFileName, ErCodeend,[append]),
io:format("~n~n").
%% handle_data_box_each(Elem, Career) ->
%% Sum = lists:seq(1,5),
%% lists:foldl(fun handle_data_box_each_one/2,{Elem}, Sum).
handle_data_box_each(Career, Elem) ->
DataFileName = lists:concat(["../src/data/data_box_", Career, Elem, ".erl"]),
Bakfile = re:replace(
lists:flatten(lists:concat([DataFileName, "_", time_format(now())])),
"[ :]", "_", [global, {return, list}]),
file:rename(DataFileName, Bakfile),
file:write_file(DataFileName, ""),
file:write_file(DataFileName, "%%%------------------------------------------------\t\n", [append]),
file:write_file(DataFileName, "%%% File : data_box_XX.erl\t\n", [append]),
file:write_file(DataFileName, "%%% Author : xiaomai\t\n", [append]),
Bytes = list_to_binary(io_lib:format("%%% Created : ~s\t\n", [time_format(now())])),
file:write_file(DataFileName, Bytes, [append]),
file:write_file(DataFileName, "%%% Description: 从mysql表生成的诛邪系统物品概率碰撞表\t\n", [append]),
file:write_file(DataFileName, "%%% Warning: 由程序自动生成,请不要随意修改!\t\n", [append]),
file:write_file(DataFileName, "%%%------------------------------------------------ \t\n", [append]),
file:write_file(DataFileName, " \t\n", [append]),
ModuleName = lists:concat(["-module(data_box_", Career, Elem, ")."]),
file:write_file(DataFileName, ModuleName, [append]),
file:write_file(DataFileName, " \t\n\n", [append]),
file:write_file(DataFileName, "-export([get_goods_one/3]).", [append]),
file:write_file(DataFileName, " \t\n", [append]),
file:write_file(DataFileName, " \t\n", [append]),
file:write_file(DataFileName, "get_goods_one(HoleType, Career, RandomCount) ->\n\t", [append]),
Sql =
io_lib:format("select a.pro, a.goods_id from `base_box_goods` a, `base_goods` b where hole_type = ~p and b.goods_id = a.goods_id and b.career in (0,~p) order by a.goods_id desc",
[Elem, Career]),
Lists = db_mysqlutil:get_all(Sql),
ElemName = lists:concat(["Goods_info_", Career, Elem, "00 = ["]),
file:write_file(DataFileName, ElemName, [append]),
{_NewCount, _FileName} = lists:foldl(fun make_content_goods/2, {1, DataFileName}, Lists),
%% io:format("the [~p]count is[~p]\n\n\n", [Career, NewCount]),
%% String = lists:concat(Result),
%% file:write_file(?FILENAME, string:substr(String,1, string:len(String)),[append]),
file:write_file(DataFileName, "],\n\t", [append]),
ErCodeEndOne = "
%%
{BaseGoodsId} = lists:nth(RandomCount, ",
ErCodeEndTwo = "),
BaseGoodsId.",
EndString = lists:concat([ErCodeEndOne, "Goods_info_", Career, Elem, "00", ErCodeEndTwo]),
file:write_file(DataFileName, EndString, [append]).
make_content_goods(List, AccIn) ->
[Pro, GoodsId] = List,
{Count, DataFileName} = AccIn,
NewPro = Pro * 100000,
NewProInt = tool:to_integer(NewPro),
Sum = lists:seq(1, NewProInt),
{NewCount, _GodosId, Result} = lists:foldl(fun get_content_array/2, {Count, GoodsId, []}, Sum),
String = lists:concat(lists:reverse(Result)),
file:write_file(DataFileName, String, [append]),
%% file:write_file(DataFileName, "\n\t\t\t\t\t\t",[append]),
%% io:format("the elem is {~p,~p,~p,~p}\t\t", [Pro,NewProInt,NewCount,length(Result)]),
{NewCount, DataFileName}.
get_content_array(_Elem, AccIn) ->
{Count, GoodsId, ResultList} = AccIn,
case tool:to_integer(Count) =:= 100000 of
true ->
ResultElem = lists:concat(["{", GoodsId, "}"]);
false ->
ResultElem = lists:concat(["{", GoodsId, "},"])
end,
{Count + 1, GoodsId, [ResultElem | ResultList]}.
%% ------------------------------------------------------------------------------------------------------
%% *********************************mysql表生成的诛邪系统物品概率碰撞表 end ****************************
%% ------------------------------------------------------------------------------------------------------

+ 247
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/task_data_checker.erl Dosyayı Görüntüle

@ -0,0 +1,247 @@
%% @author Administrator
%% @doc @todo Add description to task_data_checker.
-module(task_data_checker).
%% ====================================================================
%% API functions
%% ====================================================================
-export([]).
-compile(export_all).
-include("common.hrl").
-include("table_to_record.hrl").
-include("task.hrl").
-define(CONFIG_FILE, "../config/gateway.config").
-define(TMP_TABLE_PATH, "./tmptable/").
-define(SRC_TABLE_PATH, "../src/table/").
-define(BEAM_PATH, "./").
-define(IOFILE(Str, Args), (fun() ->
Command = io_lib:format(Str, Args),
file:write_file("../logs/data/task_data.log", Command, [append])
end)()).
-define(IOFILE(Str), (fun() ->
file:write_file("../logs/data/task_data.log", Str, [append])
end)()).
%% ====================================================================
%% Internal functions
%% ====================================================================
start() ->
case table_to_erlang:get_db_config(?CONFIG_FILE) of
[Host, Port, User, Password, DB, Encode, _Conns] ->
table_to_erlang:start_erlydb(Host, Port, User, Password, DB),
mysql:start_link(?DB_SERVER, Host, Port, User, Password, DB, fun(_, _, _, _) -> ok end, Encode),
mysql:connect(?DB_SERVER, Host, Port, User, Password, DB, Encode, true),
start_check(),
ok;
_ -> mysql_config_fail
end,
halt(),
ok.
start_check() ->
?IOFILE("\n[信息]******************任务数据有效性检测开始********************** \n"),
?IOFILE("[信息]***************日期:~p 时间:~p******************* ~n", [date(), time()]),
F = fun(Task) ->
D = list_to_tuple([tpl_task | Task]),
TaskInfo = D#tpl_task{
goods_list = util:bitstring_to_term(D#tpl_task.goods_list),
target_property = util:bitstring_to_term(D#tpl_task.target_property),
guild_goods_list = util:bitstring_to_term(D#tpl_task.guild_goods_list)
},
check_interface(TaskInfo)
end,
Lists = db_esql:get_all("select * from temp_task;"),
lists:foreach(F, Lists),
?IOFILE("[信息]***************任务数据有效性检测结束******************* \n \n").
check_interface(TaskInfo) ->
check_start_npc_scene(TaskInfo#tpl_task.start_npc, TaskInfo#tpl_task.start_scene, TaskInfo#tpl_task.tid),
check_end_npc_scene(TaskInfo#tpl_task.end_npc, TaskInfo#tpl_task.end_scene, TaskInfo#tpl_task.tid),
check_next_task(TaskInfo#tpl_task.next_tid, TaskInfo#tpl_task.tid),
check_pid_task(TaskInfo#tpl_task.pre_tid, TaskInfo#tpl_task.tid),
check_goods_list(TaskInfo#tpl_task.goods_list, TaskInfo#tpl_task.tid, "goods_list"),
check_goods_list(TaskInfo#tpl_task.goods_list, TaskInfo#tpl_task.tid, "guild_goods_list"),
check_target_pro(TaskInfo#tpl_task.target_type, TaskInfo#tpl_task.target_property, TaskInfo#tpl_task.pre_tid).
check_npc(NpcId, Type, Tid) ->
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中, ~p npc数据 npc id -> ~p 无效 ~n", [Tid, Type, NpcId]);
_ ->
skip
end.
check_scene(SceneId, Type, Tid) ->
Sql = io_lib:format("select count(*) from temp_scene where sid = ~p;", [SceneId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中, ~p场景数据 id -> ~p 无效 ~n", [Tid, Type, SceneId]);
_ ->
skip
end.
check_start_npc_scene(NpcId, SceneId, Tid) ->
if NpcId =:= 0 ->
skip;
true ->
check_npc(NpcId, "开始", Tid),
check_scene(SceneId, "开始", Tid),
Sql = io_lib:format("select count(*) from temp_npc_layout where scene_id = ~p and npcid = ~p;", [SceneId, NpcId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[警告]任务 task id -> ~p 中,任务开始场景id -> ~p 与 任务开始npc id -> ~p 不匹配(可能是跨地图任务,同事们自己留意下)~n", [Tid, SceneId, NpcId]);
_ -> skip
end
end.
check_end_npc_scene(NpcId, SceneId, Tid) ->
if NpcId =:= 0 ->
skip;
true ->
check_npc(NpcId, "结束", Tid),
check_scene(SceneId, "结束", Tid),
Sql = io_lib:format("select count(*) from temp_npc_layout where scene_id = ~p and npcid = ~p;", [SceneId, NpcId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中,任务结束场景id -> ~p 与 任务结束npc id -> ~p 不匹配 ~n", [Tid, SceneId, NpcId]);
_ -> skip
end
end.
check_next_task(NextTid, Tid) ->
if NextTid =:= -1 ->
skip;
true ->
case NextTid =< Tid of
true ->
?IOFILE("[错误]任务 task id -> ~p 中,后置任务 id -> ~p 必须比本任务id大 ~n", [Tid, NextTid]);
false ->
Sql = io_lib:format("select count(*) from temp_task where tid = ~p;", [NextTid]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中,后置任务 id -> ~p 无效~n", [Tid, NextTid]);
_ -> skip
end
end
end.
check_pid_task(PerTid, Tid) ->
if PerTid =:= -1 ->
skip;
true ->
case PerTid >= Tid of
true ->
?IOFILE("[错误]任务 task id -> ~p 中, 前置任务 id -> ~p 必须比本任务id小 ~n", [Tid, PerTid]);
false ->
Sql = io_lib:format("select count(*) from temp_task where tid = ~p;", [PerTid]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中,前置任务 id -> ~p 无效 ~n", [Tid, PerTid]);
_ -> skip
end
end
end.
check_goods_list(GoodsList, Tid, Type) ->
F = fun({_, _, Gid, _}) ->
Sql = io_lib:format("select count(*) from temp_goods where gtid = ~p;", [Gid]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]任务 task id -> ~p 中,任务奖励物品 id -> ~p 无效 ,具体见字段: ~p ~n", [Tid, Gid, Type]);
_ -> skip
end
end,
lists:foreach(F, GoodsList).
check_target_pro(?NPC_TALK_EVENT, TaskPro, Tid) ->
case TaskPro of
[{NpcId}] ->
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]对话任务 task id -> ~p 中,目标npc -> ~p 无效,具体见字段 target_property ~n", [Tid, NpcId]);
_ -> skip
end;
_ ->
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid])
end;
check_target_pro(?KILL_EVENT, TaskPro, Tid) ->
case TaskPro of
[{MonId, _, 0}] ->
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [MonId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]杀怪任务 task id -> ~p 中,怪物数据 monster id -> ~p 无效,具体见字段 target_property ~n", [Tid, MonId]);
_ -> skip
end;
_ ->
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid])
end;
check_target_pro(?COLLECT_EVENT, TaskPro, Tid) ->
case TaskPro of
[{ItemId, _, 0}] ->
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [ItemId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]采集任务 task id -> ~p 中, 采集物数据 item id -> ~p 无效,具体见字段 target_property ~n", [Tid, ItemId]);
_ ->
skip
end;
_ ->
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid])
end;
check_target_pro(?NPC_GOODS_EVENT, TaskPro, Tid) ->
case TaskPro of
[{NpcId, ItemId, _, 0}] ->
do_check_npc_shop_item(ItemId, Tid),
do_check_npc_shop_npc(NpcId, Tid),
do_check_npc_shop_data(NpcId, ItemId, Tid);
_ ->
?IOFILE("[错误]任务 task id -> ~p 中,字段 target_property 格式有误 ~n", [Tid])
end;
check_target_pro(ERR1, Err2, Err3) ->
io:format("[ERROR]param of check_target_pro err ~p ~n", [{ERR1, Err2, Err3}]).
do_check_npc_shop_item(ItemId, Tid) ->
Sql = io_lib:format("select count(*) from temp_goods where gtid = ~p;", [ItemId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]npc购物任务 task id -> ~p 中, 商品数据 item id -> ~p 无效,具体见字段 target_property ~n", [Tid, ItemId]);
_ ->
skip
end.
do_check_npc_shop_npc(NpcId, Tid) ->
Sql = io_lib:format("select count(*) from temp_npc where nid = ~p;", [NpcId]),
case db_esql:get_all(Sql) of
[[0]] ->
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 无效,具体见字段 target_property ~n", [Tid, NpcId]);
_ ->
skip
end.
do_check_npc_shop_data(NpcId, ItemId, Tid) ->
Sql = io_lib:format("select shop_goods from temp_npc_shop where shop_id = ~p;", [NpcId]),
case db_esql:get_all(Sql) of
[] ->
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 没有商品,具体见 temp_npc_shop表 ~n", [Tid, NpcId]);
Data ->
ResultList = lists:map(fun(ShopGoos) ->
do_check_npc_shop_npc_item(ItemId, ShopGoos)
end, Data),
case lists:member(true, ResultList) of
true -> skip;
false ->
?IOFILE("[错误]npc购物任务 task id -> ~p 中, npc数据 npc id -> ~p 没有商品 item id -> ~p,具体见 temp_npc_shop表 ~n", [Tid, NpcId, ItemId])
end
end.
do_check_npc_shop_npc_item(ItemId, ShopGoos) ->
NewShopGoods = util:bitstring_to_term(ShopGoos),
case lists:keyfind(ItemId, 1, NewShopGoods) of
false -> false;
_ -> true
end.

+ 152
- 0
src/srvNodeMgr/tools/gameWorld/test/tools/u.erl Dosyayı Görüntüle

@ -0,0 +1,152 @@
%%----------------------------------------------------
%% Erlang模块热更新到所有线路server的回调函数state有影响时慎用
%%
%% u:c() %% 5
%% u:c(N) %% N分钟内编译过的文件
%%
%% u:u() %% 5
%% u:u(N) %% N分钟内编译过的文件
%% u:u([mod_xx, ...]) %%
%% u:u(m) %%
%%
%% Tips: u - update, c - check
%%
%% @author rolong@vip.qq.com
%%----------------------------------------------------
-module(u).
-compile(export_all).
-include_lib("kernel/include/file.hrl").
-include("common.hrl").
-include("record.hrl").
c() ->
c(5).
c(S) when is_integer(S) ->
c:cd("../ebin"),
case file:list_dir(".") of
{ok, FileList} ->
Files = get_new_file(FileList, S * 60),
info("---------check modules---------~n~w~n=========check modules=========", [Files]);
Any -> info("Error Dir: ~w", [Any])
end;
c([S]) when is_atom(S) ->
S1 = tool:to_integer(tool:to_list(S)),
case is_integer(S1) of
true ->
c:cd("../ebin"),
case file:list_dir(".") of
{ok, FileList} ->
Files = get_new_file(FileList, S * 60),
info("---------check modules---------~n~w~n=========check modules=========", [Files]);
Any -> info("Error Dir: ~w", [Any])
end;
_ ->
info("ERROR======> Badarg ~p/~p ~n", [S, S1])
end;
c(S) -> info("ERROR======> Badarg ~p ~n", [S]).
admin() ->
spawn(fun() -> u(m) end),
ok.
u() ->
u(5).
u(m) ->
StartTime = util:unixtime(),
info("----------makes----------", []),
c:cd("../"),
make:all(),
c:cd("ebin"),
EndTime = util:unixtime(),
Time = EndTime - StartTime,
info("Make Time : ~w s", [Time]),
u(Time / 60);
u(S) when is_number(S) ->
case file:list_dir(".") of
{ok, FileList} ->
Files = get_new_file(FileList, util:ceil(S * 60) + 3),
load(Files),
try
AllZone = mod_disperse:server_list(),
info("---------modules---------~n~w~n----------nodes----------", [Files]),
loads(AllZone, Files)
catch
_:_ -> ok
end;
Any -> info("Error Dir: ~w", [Any])
end;
u(Files) when is_list(Files) ->
AllZone = mod_disperse:server_list(),
info("---------modules---------~n~w~n----------nodes----------", [Files]),
load(Files),
loads(AllZone, Files);
u(_) -> info("ERROR======> Badarg", []).
%% m(['src/data/*','src/lib/lib_goods.erl'])
m(Files) when is_list(Files) ->
StartTime = util:unixtime(),
info("----------makes----------~n~w~n", [Files]),
c:cd("../"),
Res = make:files(Files, [debug_info, {i, "include"}, {outdir, "ebin"}]),
c:cd("ebin"),
EndTime = util:unixtime(),
Time = EndTime - StartTime,
info("Make Time : ~w s", [Time]),
Res.
info(V) ->
info(V, []).
info(V, P) ->
io:format(V ++ "~n", P).
%% 线
loads([], _Files) -> ok;
loads([H | T], Files) ->
info("[~w]", [H#server.node]),
rpc:cast(H#server.node, u, load, [Files]),
loads(T, Files).
get_new_file(Files, S) ->
get_new_file(Files, S, []).
get_new_file([], _S, Result) -> Result;
get_new_file([H | T], S, Result) ->
NewResult = case string:tokens(H, ".") of
[Left, Right] when Right =:= "beam" ->
case file:read_file_info(H) of
{ok, FileInfo} ->
Now = calendar:local_time(),
case calendar:time_difference(FileInfo#file_info.mtime, Now) of
{Days, Times} ->
Seconds = calendar:time_to_seconds(Times),
case Days =:= 0 andalso Seconds < S of
true ->
FileName = list_to_atom(Left),
[FileName | Result];
false -> Result
end;
_ -> Result
end;
_ -> Result
end;
_ -> Result
end,
get_new_file(T, S, NewResult).
load([]) -> ok;
load([FileName | T]) ->
c:l(FileName),
info("loaded: ~w", [FileName]),
load(T).
% case code:soft_purge(FileName) of
% true ->
% case code:load_file(FileName) of
% {module, _} ->
% info("loaded: ~w", [FileName]),
% ok;
% %% info("loaded: ~w", [FileName]);
% {error, What} -> info("ERROR======> loading: ~w (~w)", [FileName, What])
% end;
% false -> info("ERROR======> Processes lingering : ~w [zone ~w] ", [FileName, srv_kernel:zone_id()])
% end,
% load(T).

+ 869
- 0
src/srvNodeMgr/tools/gameWorld/test/union_to_emongo.erl Dosyayı Görüntüle

@ -0,0 +1,869 @@
%%%--------------------------------------
%%% @Module : mysql_to_emongo
%%% @Author : csj
%%% @Created : 2011.03.03
%%% @Description: emongo数据库合服处理模块
%%%--------------------------------------
-module(union_to_emongo).
-compile([export_all]).
-include("common.hrl").
%%
-define(SN, config:get_server_number(gateway)).
%%id数字
-define(Max_id, config:get_max_id(gateway)).
%%
-define(SN_List, [user, player, infant_ctrl_byuser]).
%%
-define(DelLevel, 10).
%%
-define(PageSize, 100).
%% monogo数据库连接初始化
init_mongo(App) ->
try
[PoolId, Host, Port, DB, EmongoSize] = config:get_mongo_config(App),
emongo_sup:start_link(),
emongo_app:initialize_pools([PoolId, Host, Port, DB, EmongoSize]),
misc:write_system_info({self(), mongo}, mongo, {PoolId, Host, Port, DB, EmongoSize}),
{ok, master_mongo}
catch
_:_ -> mongo_config_error
end.
%% monogo数据库连接初始化
init_slave_mongo(App) ->
try
[PoolId, Host, Port, DB, EmongoSize] = config:get_slave_mongo_config(App),
emongo_sup:start_link(),
emongo_app:initialize_pools([PoolId, Host, Port, DB, EmongoSize]),
misc:write_system_info({self(), mongo_slave}, mongo_slave, {PoolId, Host, Port, DB, EmongoSize}),
{ok, slave_mongo}
catch
_:_ -> slave_config_error %%
end.
%%
%% 1.sn 2.() 3.=+nickname 4.id,id唯一 5. 6.audo_ids的对应的id 7.
%%player,user,infant_ctrl_byuser表中添加服号
start(1) ->
io:format("?SN is ~p~n", [?SN]),
case ?SN > 0 of
false ->
skip;
true ->
F = fun(Table_name) ->
io:format("db.~p.update start...~n", [Table_name]),
db_mongo:update(tool:to_list(Table_name), [{sn, ?SN}], []),
io:format("db.~p.update ok...~n", [Table_name])
end,
lists:foreach(F, ?SN_List)
end,
io:format("add server number finished!");
%%
start(2) ->
IdList = lists:flatten(db_mongo:select_all("player", "id", [{lv, "<=", ?DelLevel}])),
case IdList of
[] ->
io:format("no data!"),
skip;
_ ->
TableList = lib_player_rw:get_all_tables(),
F = fun(Tablename) ->
case Tablename of
arena -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
arena_week -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
box_scene -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
cards -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
carry -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
consign_player -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
consign_task -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
daily_bless -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
exc -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
feedback -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
fst_god -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
goods -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
goods_attribute -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
goods_buff -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
goods_cd -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
%%
%%guild -> db_mongo:delete(Tablename, [{player_id,"in",IdList}]);
guild_apply -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
guild_invite -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
guild_manor_cd -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
guild_member -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
log_backout -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_box_open -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_box_player -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_box_throw -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_compose -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_consume -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
log_dungeon -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_employ -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
log_exc -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_exc_exp -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_free_pet -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
log_fst -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
log_fst_mail -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
log_hole -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_icompose -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_idecompose -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_identify -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_inlay -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_linggen -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
log_mail -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
log_merge -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_meridian -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_pay -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_practise -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_quality_out -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_quality_up -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_refine -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_sale -> db_mongo:delete(Tablename, [{buyer_id, "in", IdList}]),
db_mongo:delete(Tablename, [{sale_id, "in", IdList}]);
log_sale_dir -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_shop -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_stren -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_suitmerge -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_throw -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_trade -> db_mongo:delete(Tablename, [{donor_id, "in", IdList}]),
db_mongo:delete(Tablename, [{gainer_id, "in", IdList}]);
log_uplevel -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_use -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_warehouse_flowdir -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
log_wash -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
mail -> db_mongo:delete(Tablename, [{uid, "in", IdList}]);
master_apprentice -> db_mongo:delete(Tablename, [{apprentenice_id, "in", IdList}]),
db_mongo:delete(Tablename, [{master_id, "in", IdList}]);
master_charts -> db_mongo:delete(Tablename, [{master_id, "in", IdList}]);
meridian -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
mon_drop_analytics -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
offline_award -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
online_award -> db_mongo:delete(Tablename, [{pid, "in", IdList}]);
online_gift -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
pet -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
player -> db_mongo:delete(Tablename, [{id, "in", IdList}]);
player_buff -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
player_donttalk -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
player_hook_setting -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
player_sys_setting -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
relationship -> db_mongo:delete(Tablename, [{idA, "in", IdList}]),
db_mongo:delete(Tablename, [{idB, "in", IdList}]);
sale_goods -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
skill -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
target_gift -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
task_bag -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
task_consign -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
task_log -> db_mongo:delete(Tablename, [{player_id, "in", IdList}]);
_ -> skip
end
end,
[F(Tablename) || Tablename <- TableList],
io:format("delete data finished!")
end;
%%
start(3) ->
TableList = lib_player_rw:get_all_tables(),
F = fun(Tablename) ->
case Tablename of
arena -> update_name(Tablename, nickname, id);
arena_week -> update_name(Tablename, nickname, id);
feedback -> update_name(Tablename, player_name, id);
fst_god -> update_name(Tablename, g_name, id), update_name(Tablename, nick, id);
guild -> update_name(Tablename, name, id), update_name(Tablename, chief_name, id),
update_name(Tablename, deputy_chief1_name, id), update_name(Tablename, deputy_chief2_name, id);
guild_invite -> update_name(Tablename, recommander_name, id);
guild_member -> update_name(Tablename, guild_name, id), update_name(Tablename, player_name, id);
log_backout -> update_name(Tablename, nickname, id);
log_box_open -> update_name(Tablename, player_name, id);
log_compose -> update_name(Tablename, nickname, id);
log_guild -> update_name(Tablename, guild_name, id);
log_hole -> update_name(Tablename, nickname, id);
log_icompose -> update_name(Tablename, nickname, id);
log_idecompose -> update_name(Tablename, nickname, id);
log_identify -> update_name(Tablename, nickname, id);
log_inlay -> update_name(Tablename, nickname, id);
log_mail -> update_name(Tablename, sname, id);
log_merge -> update_name(Tablename, nickname, id);
log_pay -> update_name(Tablename, nickname, id);
log_practise -> update_name(Tablename, nickname, id);
log_quality_out -> update_name(Tablename, nickname, id);
log_quality_up -> update_name(Tablename, nickname, id);
log_refine -> update_name(Tablename, nickname, id);
log_sale -> update_name(Tablename, buyer_name, id), update_name(Tablename, saler_name, id);
log_shop -> update_name(Tablename, nickname, id);
log_stren -> update_name(Tablename, nickname, id);
log_suitmerge -> update_name(Tablename, nickname, id);
log_throw -> update_name(Tablename, nickname, id);
log_trade -> update_name(Tablename, donor_name, id), update_name(Tablename, gainer_name, id);
log_use -> update_name(Tablename, nickname, id);
log_wash -> update_name(Tablename, nickname, id);
mail -> update_name(Tablename, sname, id);
master_apprentice -> update_name(Tablename, apprentenice_name, id);
master_charts -> update_name(Tablename, master_name, id);
mon_drop_analytics -> update_name(Tablename, player_name, id);
player -> update_name(Tablename, nickname, id), update_name(Tablename, guild_name, id);
sale_goods -> update_name(Tablename, player_name, id);
_ -> skip
end
end,
[F(Tablename) || Tablename <- TableList],
io:format("change name finished!");
%%id,id唯一
start(4) ->
%%ID最大值
%%
L = search_another_max_id(),
TableList = lib_player_rw:get_all_tables(),
F1 = fun(Tablename) ->
case Tablename of
arena -> update_id(Tablename, [{arena, id}, {player, player_id}], 0, L);
arena_week -> update_id(Tablename, [{arena_week, id}, {player, player_id}], 0, L);
box_scene -> update_id(Tablename, [{box_scene, id}, {player, player_id}], 0, L);
cards -> update_id(Tablename, [{cards, id}, {player, player_id}], 0, L);
carry -> update_id(Tablename, [{carry, id}, {player, pid}], 0, L);
consign_player -> update_id(Tablename, [{consign_player, id}, {player, pid}], 0, L);
consign_task -> update_id(Tablename, [{consign_task, id}, {player, pid}], 0, L);
daily_bless -> update_id(Tablename, [{daily_bless, id}, {player, player_id}], 0, L);
exc -> update_id(Tablename, [{exc, id}, {player, player_id}], 0, L);
feedback -> update_id(Tablename, [{feedback, id}, {player, player_id}], 0, L);
fst_god -> update_id(Tablename, [{fst_god, id}, {player, uid}], 0, L);
goods -> update_id(Tablename, [{goods, id}, {player, player_id}], 0, L);
goods_attribute -> update_id(Tablename, [{goods_attribute, id}, {player, player_id}, {goods, gid}], 0, L);
goods_buff -> update_id(Tablename, [{goods_buff, id}, {player, player_id}], 0, L);
goods_cd -> update_id(Tablename, [{goods_cd, id}, {player, player_id}], 0, L);
guild ->
update_id(Tablename, [{guild, id}, {player, chief_id}, {player, deputy_chief1_id}, {player, deputy_chief2_id}], 1, L);
guild_apply -> update_id(Tablename, [{guild_apply, id}, {guild, guild_id}, {player, player_id}], 0, L);
guild_invite ->
update_id(Tablename, [{guild_invite, id}, {guild, guild_id}, {player, player_id}, {player, recommander_id}], 1, L);
guild_manor_cd -> update_id(Tablename, [{guild_manor_cd, id}, {player, player_id}], 0, L);
guild_member -> update_id(Tablename, [{guild_member, id}, {guild, guild_id}, {player, player_id}], 0, L);
guild_skills_attribute -> update_id(Tablename, [{guild_skills_attribute, id}, {guild, guild_id}], 0, L);
infant_ctrl_byuser -> update_id(Tablename, [{infant_ctrl_byuser, id}], 0, L);
log_backout -> update_id(Tablename, [{log_backout, id}, {player, player_id}, {goods, gid}], 0, L);
log_box_open -> update_id(Tablename, [{log_box_open, id}, {player, player_id}, {goods, gid}], 1, L);
log_box_player -> update_id(Tablename, [{log_box_player, id}, {player, player_id}], 0, L);
log_box_throw -> update_id(Tablename, [{log_box_throw, id}, {player, player_id}, {goods, gid}], 0, L);
log_compose -> update_id(Tablename, [{log_compose, id}, {player, player_id}], 0, L);
log_consume -> update_id(Tablename, [{log_consume, id}, {player, pid}], 0, L);
log_dungeon -> update_id(Tablename, [{log_dungeon, id}, {player, player_id}], 0, L);
log_employ -> update_id(Tablename, [{log_employ, id}, {player, pid}], 0, L);
log_exc -> update_id(Tablename, [{log_exc, id}, {player, player_id}], 0, L);
log_exc_exp -> update_id(Tablename, [{log_exc_exp, id}, {player, player_id}], 0, L);
log_free_pet -> update_id(Tablename, [{log_free_pet, id}, {player, uid}], 0, L);
log_fst -> update_id(Tablename, [{log_fst, id}, {player, uid}], 0, L);
log_fst_mail -> update_id(Tablename, [{log_fst_mail, id}, {player, uid}], 0, L);
log_guild -> update_id(Tablename, [{log_guild, id}, {guild, guild_id}], 0, L);
log_hole -> update_id(Tablename, [{log_hole, id}, {player, player_id}, {goods, gid}], 0, L);
log_icompose -> update_id(Tablename, [{log_icompose, id}, {player, player_id}], 0, L);
log_idecompose -> update_id(Tablename, [{log_idecompose, id}, {player, player_id}, {goods, gid}], 0, L);
log_identify -> update_id(Tablename, [{log_identify, id}, {player, player_id}, {goods, gid}], 0, L);
log_inlay -> update_id(Tablename, [{log_inlay, id}, {player, player_id}, {goods, gid}], 0, L);
log_linggen -> update_id(Tablename, [{log_linggen, id}, {player, pid}], 0, L);
log_mail -> update_id(Tablename, [{log_mail, id}, {player, uid}, {goods, gid}], 1, L);
log_merge ->
update_id(Tablename, [{log_merge, id}, {player, player_id}, {goods, gid_1}, {goods, gid_2}], 0, L);
log_meridian -> update_id(Tablename, [{log_meridian, id}, {player, player_id}], 0, L);
log_pay -> update_id(Tablename, [{log_pay, id}, {player, player_id}], 0, L);
log_practise -> update_id(Tablename, [{log_practise, id}, {player, player_id}, {goods, gid}], 0, L);
log_quality_out -> update_id(Tablename, [{log_quality_out, id}, {player, player_id}, {goods, gid}], 0, L);
log_quality_up -> update_id(Tablename, [{log_quality_up, id}, {player, player_id}, {goods, gid}], 0, L);
log_refine -> update_id(Tablename, [{log_refine, id}, {player, player_id}, {goods, gid}], 0, L);
log_sale ->
update_id(Tablename, [{log_sale, id}, {sale_goods, sale_id}, {player, player_id}, {goods, gid}], 1, L);
log_sale_dir ->
update_id(Tablename, [{log_sale_dir, id}, {sale_goods, sale_id}, {player, player_id}, {goods, gid}], 1, L);
log_shop -> update_id(Tablename, [{log_shop, id}, {player, player_id}], 0, L);
log_stren -> update_id(Tablename, [{log_stren, id}, {player, player_id}, {goods, gid}], 0, L);
log_suitmerge ->
update_id(Tablename, [{log_suitmerge, id}, {player, player_id}, {goods, gid1}, {goods, gid2}, {goods, gid3}], 0, L);
log_throw -> update_id(Tablename, [{log_throw, id}, {player, player_id}, {goods, gid}], 0, L);
log_trade ->
update_id(Tablename, [{log_trade, id}, {player, donor_id}, {player, gainer_id}, {goods, gid}], 1, L);
log_uplevel -> update_id(Tablename, [{log_uplevel, id}, {player, player_id}], 0, L);
log_use -> update_id(Tablename, [{log_use, id}, {player, player_id}, {goods, gid}], 0, L);
log_warehouse_flowdir ->
update_id(Tablename, [{log_warehouse_flowdir, id}, {player, player_id}, {goods, gid}], 0, L);
log_wash -> update_id(Tablename, [{log_wash, id}, {player, player_id}, {goods, gid}], 0, L);
login_prize -> update_id(Tablename, [{login_prize, id}], 0, L);
mail -> update_id(Tablename, [{mail, id}, {player, uid}, {goods, gid}], 1, L);
master_apprentice ->
update_id(Tablename, [{master_apprentice, id}, {player, apprentenice_id}, {player, master_id}], 1, L);
master_charts -> update_id(Tablename, [{master_charts, id}, {player, master_id}], 0, L);
meridian -> update_id(Tablename, [{meridian, id}, {player, player_id}], 0, L);
mon_drop_analytics -> update_id(Tablename, [{mon_drop_analytics, id}, {player, player_id}], 0, L);
offline_award -> update_id(Tablename, [{offline_award, id}, {player, pid}], 0, L);
online_award -> update_id(Tablename, [{online_award, id}, {player, pid}], 0, L);
online_gift -> update_id(Tablename, [{online_gift, id}, {player, player_id}], 0, L);
pet -> update_id(Tablename, [{pet, id}, {player, player_id}], 0, L);
player -> update_id(Tablename, [{player, id}, {guild, guild_id}], 1, L);
player_buff -> update_id(Tablename, [{player_buff, id}, {player, player_id}], 0, L);
player_donttalk -> update_id(Tablename, [{player, player_id}], 0, L);
player_hook_setting -> update_id(Tablename, [{player_hook_setting, id}, {player, player_id}], 0, L);
player_sys_setting -> update_id(Tablename, [{player_sys_setting, id}, {player, player_id}], 0, L);
relationship -> update_id(Tablename, [{relationship, id}, {player, idA}, {player, idB}], 0, L);
sale_goods -> update_id(Tablename, [{sale_goods, id}, {goods, gid}, {player, player_id}], 0, L);
skill -> update_id(Tablename, [{skill, id}, {player, player_id}], 0, L);
target_gift -> update_id(Tablename, [{target_gift, id}, {player, player_id}], 0, L);
task_bag -> update_id(Tablename, [{task_bag, id}, {player, player_id}], 0, L);
task_consign -> update_id(Tablename, [{task_consign, id}, {player, player_id}], 0, L);
task_log -> update_id(Tablename, [{task_log, id}, {player, player_id}], 0, L);
user -> update_id(Tablename, [{user, id}], 0, L);
_ -> skip
end
end,
[F1(Tablename) || Tablename <- TableList],
io:format("change id finished!");
%%
start(5) ->
Master_mongo1 =
case init_mongo(gateway) of
{ok, Master_mongo} -> Master_mongo;
_ -> []
end,
Slave_mongo1 =
case init_slave_mongo(gateway) of
{ok, Slave_mongo} -> Slave_mongo;
_ -> []
end,
if (Master_mongo1 =/= [] andalso Slave_mongo1 =/= []) ->
%% TableList = lib_player_rw:get_all_tables(),
TableList =
[
arena,
arena_week,
box_scene,
cards,
carry,
consign_player,
consign_task,
daily_bless,
exc,
feedback,
fst_god,
goods,
goods_attribute,
goods_buff,
goods_cd,
guild,
guild_apply,
guild_invite,
guild_manor_cd,
guild_member,
guild_skills_attribute,
infant_ctrl_byuser,
log_backout,
log_box_open,
log_box_player,
log_box_throw,
log_compose,
log_consume,
log_dungeon,
log_employ,
log_exc,
log_exc_exp,
log_free_pet,
log_fst,
log_fst_mail,
log_guild,
log_hole,
log_icompose,
log_idecompose,
log_identify,
log_inlay,
log_linggen,
log_mail,
log_merge,
log_meridian,
log_pay,
log_practise,
log_quality_out,
log_quality_up,
log_refine,
log_sale,
log_sale_dir,
log_shop,
log_stren,
log_suitmerge,
log_throw,
log_trade,
log_uplevel,
log_use,
log_warehouse_flowdir,
log_wash,
login_prize,
mail,
master_apprentice,
master_charts,
meridian,
mon_drop_analytics,
offline_award,
online_award,
online_gift,
pet,
player,
player_buff,
player_donttalk,
player_hook_setting,
player_sys_setting,
relationship,
sale_goods,
skill,
target_gift,
task_bag,
task_consign,
task_log,
user
],
F = fun(Tablename) ->
ResultList = emongo:find_all(tool:to_list(Slave_mongo1), tool:to_list(Tablename), [], []),
F = fun(R) ->
R1 = [({Key, Value}) || {Key, Value} <- R, Key =/= <<"_id">>],
Opertion = db_mongoutil:make_insert_opertion(R1),
emongo:insert(tool:to_list(Master_mongo1), tool:to_list(Tablename), Opertion)
end,
io:format("Tablename is ~p union data finish ~n", [Tablename]),
[F(R) || R <- ResultList]
end,
[F(Tablename) || Tablename <- lists:reverse(TableList)],
io:format("mongo and slave config ok");
true ->
io:format("mongo and slave config error")
end;
%%audo_ids的对应的id
start(6) ->
update_ids(),
io:format("change auto_ids finished!");
%%
start(7) ->
ok.
update_name(Tablename, Field, WhereField) ->
io:format("start update_name ~p~n ", [Tablename]),
[Size] = db_mongo:select_count(Tablename, []),
TotalPage =
if (Size div ?PageSize == 0) ->
Size div ?PageSize;
true ->
Size div ?PageSize + 1
end,
io:format("Size is ~p~n", [Size]),
if (TotalPage =< 1) ->
NameList = db_mongo:select_all(Tablename, tool:to_list(WhereField) ++ "," ++ tool:to_list(Field)),
F = fun(Name) ->
Name1 = tool:to_list(lists:nth(2, Name)),
case length(Name1) > 0 andalso Name1 =/= "[]" of
false -> skip;
true ->
Id1 = lists:nth(1, Name),
NewName = "" ++ integer_to_list(?SN) ++ "" ++ Name1,
db_mongo:update(Tablename, [{Field, NewName}], [{WhereField, Id1}])
end
end,
io:format("end update_name ~p ", [Tablename]),
[F(Name) || Name <- NameList];
true ->
F = fun(Page) ->
io:format("Page is ~p~n", [Page]),
Result = db_mongo:select_all(Tablename, tool:to_list(WhereField) ++ "," ++ tool:to_list(Field), [], [{tool:to_list(WhereField), asc}, {tool:to_list(Field), asc}], [?PageSize, (Page - 1) * ?PageSize]),
io:format("Result size is ~p~n", [length(Result)]),
F = fun(Name) ->
Name1 = tool:to_list(lists:nth(2, Name)),
case length(Name1) > 0 andalso Name1 =/= "[]" of
false -> skip;
true ->
Id1 = lists:nth(1, Name),
NewName = "" ++ integer_to_list(?SN) ++ "" ++ Name1,
db_mongo:update(Tablename, [{Field, NewName}], [{WhereField, Id1}])
end
end,
io:format("end update_name ~p ", [Tablename]),
[F(Name) || Name <- Result]
end,
lists:foreach(F, lists:seq(1, TotalPage))
end.
search_another_max_id() ->
%%ID最大值
TableList = lib_player_rw:get_all_tables(),
F = fun(Tablename) ->
case Tablename of
arena -> search_id(Tablename, [id]);
arena_week -> search_id(Tablename, [id]);
box_scene -> search_id(Tablename, [id]);
cards -> search_id(Tablename, [id]);
carry -> search_id(Tablename, [id]);
consign_player -> search_id(Tablename, [id]);
consign_task -> search_id(Tablename, [id]);
daily_bless -> search_id(Tablename, [id]);
exc -> search_id(Tablename, [id]);
feedback -> search_id(Tablename, [id]);
fst_god -> search_id(Tablename, [id]);
goods -> search_id(Tablename, [id]);
goods_attribute -> search_id(Tablename, [id]);
goods_buff -> search_id(Tablename, [id]);
goods_cd -> search_id(Tablename, [id]);
guild -> search_id(Tablename, [id]);
guild_apply -> search_id(Tablename, [id]);
guild_invite -> search_id(Tablename, [id]);
guild_manor_cd -> search_id(Tablename, [id]);
guild_member -> search_id(Tablename, [id]);
guild_skills_attribute -> search_id(Tablename, [id]);
infant_ctrl_byuser -> search_id(Tablename, [id]);
log_backout -> search_id(Tablename, [id]);
log_box_open -> search_id(Tablename, [id]);
log_box_player -> search_id(Tablename, [id]);
log_box_throw -> search_id(Tablename, [id]);
log_compose -> search_id(Tablename, [id]);
log_consume -> search_id(Tablename, [id]);
log_dungeon -> search_id(Tablename, [id]);
log_employ -> search_id(Tablename, [id]);
log_exc -> search_id(Tablename, [id]);
log_exc_exp -> search_id(Tablename, [id]);
log_free_pet -> search_id(Tablename, [id]);
log_fst -> search_id(Tablename, [id]);
log_fst_mail -> search_id(Tablename, [id]);
log_guild -> search_id(Tablename, [id]);
log_hole -> search_id(Tablename, [id]);
log_icompose -> search_id(Tablename, [id]);
log_idecompose -> search_id(Tablename, [id]);
log_identify -> search_id(Tablename, [id]);
log_inlay -> search_id(Tablename, [id]);
log_linggen -> search_id(Tablename, [id]);
log_mail -> search_id(Tablename, [id]);
log_merge -> search_id(Tablename, [id]);
log_meridian -> search_id(Tablename, [id]);
log_pay -> search_id(Tablename, [id]);
log_practise -> search_id(Tablename, [id]);
log_quality_out -> search_id(Tablename, [id]);
log_quality_up -> search_id(Tablename, [id]);
log_refine -> search_id(Tablename, [id]);
log_sale -> search_id(Tablename, [id]);
log_sale_dir -> search_id(Tablename, [id]);
log_shop -> search_id(Tablename, [id]);
log_stren -> search_id(Tablename, [id]);
log_suitmerge -> search_id(Tablename, [id]);
log_throw -> search_id(Tablename, [id]);
log_trade -> search_id(Tablename, [id]);
log_uplevel -> search_id(Tablename, [id]);
log_use -> search_id(Tablename, [id]);
log_warehouse_flowdir -> search_id(Tablename, [id]);
log_wash -> search_id(Tablename, [id]);
login_prize -> search_id(Tablename, [id]);
mail -> search_id(Tablename, [id]);
master_apprentice -> search_id(Tablename, [id]);
master_charts -> search_id(Tablename, [id]);
meridian -> search_id(Tablename, [id]);
mon_drop_analytics -> search_id(Tablename, [id]);
offline_award -> search_id(Tablename, [id]);
online_award -> search_id(Tablename, [id]);
online_gift -> search_id(Tablename, [id]);
pet -> search_id(Tablename, [id]);
player -> search_id(Tablename, [id]);
player_buff -> search_id(Tablename, [id]);
player_donttalk -> search_id(Tablename, [player_id]);
player_hook_setting -> search_id(Tablename, [id]);
player_sys_setting -> search_id(Tablename, [id]);
relationship -> search_id(Tablename, [id]);
sale_goods -> search_id(Tablename, [id]);
skill -> search_id(Tablename, [id]);
target_gift -> search_id(Tablename, [id]);
task_bag -> search_id(Tablename, [id]);
task_consign -> search_id(Tablename, [id]);
task_log -> search_id(Tablename, [id]);
user -> search_id(Tablename, [id]);
_ -> search_id([], [])
end
end,
L = [F(Tablename) || Tablename <- TableList],
%%
[R || R <- L, R =/= {}].
%%
search_id(Tablename, FieldList) ->
case Tablename =/= [] of
false -> {};
_ ->
io:format("search_id ~p~n", [Tablename]),
FieldString = util:list_to_string(FieldList),
MaxId = db_mongo:select_one_new(tool:to_list(?SLAVE_POOLID), Tablename, FieldString, [], [{FieldString, desc}], [1]),
case MaxId of
undefined -> {};
null -> {};
_ -> {Tablename, MaxId + 1}
end
end.
update_id(Tablename, FieldList, CheckExist, TablesMaxIdList) ->
io:format("update_id ~p~n", [Tablename]),
%% FieldString = util:list_to_string(FieldList),
case CheckExist of
0 ->
F = fun(AnotherTable, Field) ->
case lists:keysearch(AnotherTable, 1, TablesMaxIdList) of
false -> {};
{value, {AnotherTable, MaxId}} ->
{Field, MaxId, add}
end
end,
FieldList1 = [F(AnotherTable, Field) || {AnotherTable, Field} <- FieldList],
FieldList2 = [FieldValue || FieldValue <- FieldList1, FieldValue =/= {}],
%% emongo:update(tool:to_list(?MASTER_POOLID),tool:to_list(Tablename), [], [{"$inc",FieldList1}]);
db_mongo:update(Tablename, FieldList2, []);
1 ->
FieldList1 = [(Field) || {_AnotherTable, Field} <- FieldList],
FieldList2 = util:list_to_string(FieldList1),
ResultList = db_mongo:select_all(Tablename, FieldList2),
F = fun(Record) ->
FieldTh = [N1 || N1 <- lists:seq(1, length(Record)), lists:nth(N1, Record) > 0, lists:nth(N1, Record) =/= undefined],
F1 = fun(N2) ->
OldValue1 = lists:nth(N2, Record),
Field1 = lists:nth(N2, FieldList1),
F2 = fun() ->
[AnotherTableName2] = [AnotherTable2 || {AnotherTable2, Field2} <- FieldList, Field1 == Field2],
case lists:keyfind(AnotherTableName2, 1, TablesMaxIdList) of
false -> 0;
{_, MaxId} -> MaxId
end
end,
AnotherValue = F2,
{Field1, AnotherValue + OldValue1}
end,
FieldString1 = [F1(N2) || N2 <- FieldTh],
Where1 = [{lists:nth(1, FieldList1), lists:nth(1, Record)}],
db_mongo:update(Tablename, FieldString1, Where1)
end,
[F(Record) || Record <- ResultList];
_ -> skip
end.
update_ids() ->
AutoIdsList = emongo:find_all(tool:to_list(?MASTER_POOLID), tool:to_list(auto_ids), [], ["id,name,mid,counter,kid,gid,uid,num,level"]),
io:format("AutoIdsList is ~p~n", [AutoIdsList]),
F = fun(Result) ->
{_E1, Value1} = lists:nth(1, Result),
{_E2, Value2} = lists:nth(2, Result),
case tool:to_atom(tool:to_list(Value1)) of
master_apprentice -> update_ids(master_apprentice, [id]);
mon_drop_analytics -> update_ids(mon_drop_analytics, [id]);
online_gift -> update_ids(online_gift, [id]);
player_buff -> update_ids(player_buff, [id]);
player_hook_setting -> update_ids(player_hook_setting, [id]);
relationship -> update_ids(relationship, [id]);
sale_goods -> update_ids(sale_goods, [id]);
stc_create_page -> update_ids(stc_create_page, [id]);
system_config -> update_ids(system_config, [id]);
target_gift -> update_ids(target_gift, [id]);
user -> update_ids(user, [id]);
task_bag -> update_ids(task_bag, [id]);
task_log -> update_ids(task_log, [id]);
skill -> update_ids(skill, [id]);
player_sys_setting -> update_ids(player_sys_setting, [id]);
realm_1 -> update_realm(player, [1]);
realm_2 -> update_realm(player, [2]);
realm_3 -> update_realm(player, [3]);
log_box_player -> update_ids(log_box_player, [id]);
dungeon_id -> update_dungeon_id(log_dungeon, [dungeon_id]);
log_dungeon -> update_ids(log_dungeon, [id]);
exc -> update_ids(exc, [id]);
daily_bless -> update_ids(daily_bless, [id]);
log_exc_exp -> update_ids(log_exc_exp, [id]);
arena -> update_ids(arena, [id]);
cards -> update_ids(cards, [id]);
feedback -> update_ids(feedback, [id]);
goods -> update_ids(goods, [id]);
goods_attribute -> update_ids(goods_attribute, [id]);
goods_buff -> update_ids(goods_buff, [id]);
goods_cd -> update_ids(goods_cd, [id]);
guild -> update_ids(guild, [id]);
guild_apply -> update_ids(guild_apply, [id]);
guild_invite -> update_ids(guild_invite, [id]);
guild_member -> update_ids(guild_member, [id]);
guild_skills_attribute -> update_ids(guild_skills_attribute, [id]);
log_backout -> update_ids(log_backout, [id]);
log_box_open -> update_ids(log_box_open, [id]);
log_compose -> update_ids(log_compose, [id]);
log_consume -> update_ids(log_consume, [id]);
log_exc -> update_ids(log_exc, [id]);
log_guild -> update_ids(log_guild, [id]);
log_hole -> update_ids(log_hole, [id]);
log_identify -> update_ids(log_identify, [id]);
log_inlay -> update_ids(log_inlay, [id]);
log_merge -> update_ids(log_merge, [id]);
log_meridian -> update_ids(log_meridian, [id]);
log_pay -> update_ids(log_pay, [id]);
log_practise -> update_ids(log_practise, [id]);
log_quality_out -> update_ids(log_quality_out, [id]);
log_quality_up -> update_ids(log_quality_up, [id]);
log_sale -> update_ids(log_sale, [id]);
log_shop -> update_ids(log_shop, [id]);
log_stren -> update_ids(log_stren, [id]);
log_trade -> update_ids(log_trade, [id]);
log_uplevel -> update_ids(log_uplevel, [id]);
log_use -> update_ids(log_use, [id]);
log_wash -> update_ids(log_wash, [id]);
login_prize -> update_ids(login_prize, [id]);
mail -> update_ids(mail, [id]);
master_charts -> update_ids(master_charts, [id]);
meridian -> update_ids(meridian, [id]);
pet -> update_ids(pet, [id]);
player -> update_ids(player, [id]);
stc_min -> update_ids(stc_min, [id]);
sys_acm -> update_ids(sys_acm, [id]);
test -> update_ids(test, [id]);
log_suitmerge -> update_ids(log_suitmerge, [id]);
infant_ctrl_byuser -> update_ids(infant_ctrl_byuser, [id]);
log_mail -> update_ids(log_mail, [id]);
log_throw -> update_ids(log_throw, [id]);
task_consign -> update_ids(task_consign, [id]);
log_free_pet -> update_ids(log_free_pet, [id]);
guild_manor_cd -> update_ids(guild_manor_cd, [id]);
log_sale_dir -> update_ids(log_sale_dir, [id]);
log_warehouse_flowdir -> update_ids(log_warehouse_flowdir, [id]);
arena_week -> update_ids(arena_week, [id]);
carry -> update_ids(carry, [id]);
consign_player -> update_ids(consign_player, [id]);
log_linggen -> update_ids(log_linggen, [id]);
_ -> skip
end,
case tool:to_atom(tool:to_list(Value2)) of
master_apprentice -> update_ids(master_apprentice, [id]);
mon_drop_analytics -> update_ids(mon_drop_analytics, [id]);
online_gift -> update_ids(online_gift, [id]);
player_buff -> update_ids(player_buff, [id]);
player_hook_setting -> update_ids(player_hook_setting, [id]);
relationship -> update_ids(relationship, [id]);
sale_goods -> update_ids(sale_goods, [id]);
stc_create_page -> update_ids(stc_create_page, [id]);
system_config -> update_ids(system_config, [id]);
target_gift -> update_ids(target_gift, [id]);
user -> update_ids(user, [id]);
task_bag -> update_ids(task_bag, [id]);
task_log -> update_ids(task_log, [id]);
skill -> update_ids(skill, [id]);
player_sys_setting -> update_ids(player_sys_setting, [id]);
realm_1 -> update_realm(player, [1]);
realm_2 -> update_realm(player, [2]);
realm_3 -> update_realm(player, [3]);
log_box_player -> update_ids(log_box_player, [id]);
dungeon_id -> update_dungeon_id(log_dungeon, [dungeon_id]);
log_dungeon -> update_ids(log_dungeon, [id]);
exc -> update_ids(exc, [id]);
daily_bless -> update_ids(daily_bless, [id]);
log_exc_exp -> update_ids(log_exc_exp, [id]);
arena -> update_ids(arena, [id]);
cards -> update_ids(cards, [id]);
feedback -> update_ids(feedback, [id]);
goods -> update_ids(goods, [id]);
goods_attribute -> update_ids(goods_attribute, [id]);
goods_buff -> update_ids(goods_buff, [id]);
goods_cd -> update_ids(goods_cd, [id]);
guild -> update_ids(guild, [id]);
guild_apply -> update_ids(guild_apply, [id]);
guild_invite -> update_ids(guild_invite, [id]);
guild_member -> update_ids(guild_member, [id]);
guild_skills_attribute -> update_ids(guild_skills_attribute, [id]);
log_backout -> update_ids(log_backout, [id]);
log_box_open -> update_ids(log_box_open, [id]);
log_compose -> update_ids(log_compose, [id]);
log_consume -> update_ids(log_consume, [id]);
log_exc -> update_ids(log_exc, [id]);
log_guild -> update_ids(log_guild, [id]);
log_hole -> update_ids(log_hole, [id]);
log_identify -> update_ids(log_identify, [id]);
log_inlay -> update_ids(log_inlay, [id]);
log_merge -> update_ids(log_merge, [id]);
log_meridian -> update_ids(log_meridian, [id]);
log_pay -> update_ids(log_pay, [id]);
log_practise -> update_ids(log_practise, [id]);
log_quality_out -> update_ids(log_quality_out, [id]);
log_quality_up -> update_ids(log_quality_up, [id]);
log_sale -> update_ids(log_sale, [id]);
log_shop -> update_ids(log_shop, [id]);
log_stren -> update_ids(log_stren, [id]);
log_trade -> update_ids(log_trade, [id]);
log_uplevel -> update_ids(log_uplevel, [id]);
log_use -> update_ids(log_use, [id]);
log_wash -> update_ids(log_wash, [id]);
login_prize -> update_ids(login_prize, [id]);
mail -> update_ids(mail, [id]);
master_charts -> update_ids(master_charts, [id]);
meridian -> update_ids(meridian, [id]);
pet -> update_ids(pet, [id]);
player -> update_ids(player, [id]);
stc_min -> update_ids(stc_min, [id]);
sys_acm -> update_ids(sys_acm, [id]);
test -> update_ids(test, [id]);
log_suitmerge -> update_ids(log_suitmerge, [id]);
infant_ctrl_byuser -> update_ids(infant_ctrl_byuser, [id]);
log_mail -> update_ids(log_mail, [id]);
log_throw -> update_ids(log_throw, [id]);
task_consign -> update_ids(task_consign, [id]);
log_free_pet -> update_ids(log_free_pet, [id]);
guild_manor_cd -> update_ids(guild_manor_cd, [id]);
log_sale_dir -> update_ids(log_sale_dir, [id]);
log_warehouse_flowdir -> update_ids(log_warehouse_flowdir, [id]);
arena_week -> update_ids(arena_week, [id]);
carry -> update_ids(carry, [id]);
consign_player -> update_ids(consign_player, [id]);
log_linggen -> update_ids(log_linggen, [id]);
_ -> skip
end
end,
[F(lists:nthtail(1, AutoIds)) || AutoIds <- AutoIdsList].
update_ids(Tablename, FieldList) ->
io:format("update_ids ~p~n", [Tablename]),
FieldString = util:list_to_string(FieldList),
MaxId = db_mongo:select_one(Tablename, FieldString, [], [{FieldString, desc}], [1]),
MaxId1 =
case MaxId of
null -> 0;
_ -> MaxId
end,
io:format("MaxId1 is ~p~n", [MaxId1]),
MaxId2 =
case Tablename of
user ->
[UserCount] = db_mongo:select_count(Tablename, []),
if UserCount > MaxId1 ->
UserCount;
true ->
MaxId1
end;
_ ->
MaxId1
end,
io:format("MaxId2 is ~p~n", [MaxId2]),
db_mongo:update("auto_ids", [{FieldString, MaxId2}], [{name, Tablename}]).
update_realm(Tablename, NumList) ->
Realm = lists:nth(1, NumList),
[Total] = db_mongo:select_count(Tablename, [{realm, Realm}]),
Realm_Num = lists:concat(["realm_", Realm]),
db_mongo:update("auto_ids", [{num, Total}], [{name, Realm_Num}]).
update_dungeon_id(Tablename, FieldList) ->
io:format("update_dungeon_id ~p~n", [Tablename]),
FieldString = util:list_to_string(FieldList),
Total = db_agent:sum(log_dungeon, "dungeon_counter", []),
db_mongo:update("auto_ids", [{counter, Total}], [{name, FieldString}]).

+ 97
- 0
src/srvNodeMgr/tools_cq/h.erl Dosyayı Görüntüle

@ -0,0 +1,97 @@
-module(h).
-include_lib("kernel/include/file.hrl").
-export([
h/0, % erl文件
hh/0, % hrl头文件
kf_load_beam_all_server_in_local_node/1,
kf_load_beam_all_server_in_kf_center/1,
nodes_load/1,
load/1
]).
%
% ==== u:h() % erl文件
% u:hh()
h() ->
ErlFileList = filelib:wildcard("../src/**/*.erl"),
F = fun([$., $., $/ | ErlFile__] = ErlFile) ->
case file:read_file_info(ErlFile) of
{ok, #file_info{mtime = ErlTime}} ->
BeamName = lists:concat(["../ebin/", filename:basename(ErlFile, ".erl"), code:objfile_extension()]),
case file:read_file_info(BeamName) of
{ok, #file_info{mtime = BeamTime}} when ErlTime > BeamTime ->
ErlFile__;
{ok, _} ->
skip;
_E ->
ErlFile__
end;
_ ->
skip
end
end,
CompileFiles = [Y || Y <- [F(X) || X <- ErlFileList], Y =/= skip],
StartTime = unixtime(),
io:format("----------makes----------~n~p~n", [CompileFiles]),
c:cd("../"),
Res = make:files(CompileFiles, [netload]),
c:cd("ebin"),
EndTime = unixtime(),
io:format("Make result = ~p~nMake Time : ~p s", [Res, EndTime - StartTime]),
% cast到某条线调用
catch kf_load_beam(CompileFiles),
ok.
hh() ->
StartTime = unixtime(),
c:l(mmake),
io:format("----------makes----------~n", []),
c:cd("../"),
Res = (catch mmake:all(8, [netload])),
c:cd("ebin"),
EndTime = unixtime(),
io:format("MMake result = ~p~nMMake Time : ~p s", [Res, EndTime - StartTime]),
ok.
%% unix时间戳
%%
unixtime() ->
{M, S, _} = os:timestamp(),
M * 1000000 + S.
%%
kf_load_beam([]) -> skip;
kf_load_beam(Files) ->
Modules = [list_to_atom(filename:basename(File, ".erl")) || File <- Files],
case nodes(connected) of
[Node | _] ->
rpc:cast(Node, ?MODULE, kf_load_beam_all_server_in_local_node, [Modules]);
_ ->
skip
end,
ok.
%
kf_load_beam_all_server_in_local_node(Modules) ->
lib_kfclient:apply_cast(?MODULE, kf_load_beam_all_server_in_kf_center, [Modules]).
%
kf_load_beam_all_server_in_kf_center(Modules) ->
%
nodes_load(Modules),
%
lib_kfcenter:apply_to_all_node(?MODULE, nodes_load, [Modules]),
ok.
%
nodes_load(Modules) ->
%
catch load(Modules),
%
ContenctedNodes = nodes(connected),
[rpc:cast(Node, ?MODULE, load, [Modules]) || Node <- ContenctedNodes].
load(Modules) -> [c:nl(M) || M <- Modules].

+ 36
- 0
src/srvNodeMgr/tools_cq/hot_swap.erl Dosyayı Görüntüle

@ -0,0 +1,36 @@
-module(hot_swap).
-export([
load/1,
network_load/1,
network_load/2
]).
%%
%% @param ModList ()
load(ModList) ->
lists:foreach(fun(Module) ->
code:purge(Module),
code:load_file(Module)
end, ModList).
%%
%% @param ModList ()
network_load(ModList) ->
lists:foreach(fun(Module) ->
[begin rpc:call(Node, code, purge, [Module]), rpc:call(Node, code, load_file, [Module]) end || Node <- (nodes() ++ [node()])]
end, ModList).
%%
%% @param NodeList ()
%% @param ModList ()
network_load(NodeList, ModList) ->
lists:foreach(fun(Node) ->
lists:foreach(fun(Module) ->
rpc:call(Node, code, purge, [Module]),
rpc:call(Node, code, load_file, [Module])
end, ModList)
end, NodeList).

+ 67
- 0
src/srvNodeMgr/tools_cq/memory_show.erl Dosyayı Görüntüle

@ -0,0 +1,67 @@
-module(memory_show).
-compile(export_all).
show(N) ->
F = fun(P) ->
case catch process_info(P, [memory, dictionary]) of
[{_, Memory}, {_, Dict}] ->
InitStart = util:prop_get_value('$initial_call', Dict, null),
{InitStart, Memory};
_ -> {null, 0}
end
end,
Infos1 = lists:map(F, processes()),
Infos2 = [{Name, M} || {Name, M} <- Infos1, Name =/= null],
SortFun = fun({_, M1}, {_, M2}) -> M1 > M2 end,
Infos3 = lists:sort(SortFun, Infos2),
Infos4 = lists:sublist(Infos3, N),
[io:format("~p : ~p ~n", [Name, M]) || {Name, M} <- Infos4],
ok.
show(N, SkipNames) ->
F = fun(P) ->
case catch process_info(P, [memory, dictionary]) of
[{_, Memory}, {_, Dict}] ->
InitStart = util:prop_get_value('$initial_call', Dict, null),
case catch tuple_to_list(InitStart) of
[Name | _] ->
case lists:member(Name, SkipNames) of
true -> {null, 0};
false -> {InitStart, Memory}
end;
_ -> {null, 0}
end;
_ -> {null, 0}
end
end,
Infos1 = lists:map(F, processes()),
Infos2 = [{Name, M} || {Name, M} <- Infos1, Name =/= null],
SortFun = fun({_, M1}, {_, M2}) -> M1 > M2 end,
Infos3 = lists:sort(SortFun, Infos2),
Infos4 = lists:sublist(Infos3, N),
[io:format("~p : ~p ~n", [Name, M]) || {Name, M} <- Infos4],
ok.
show1(N) ->
F = fun(P, Acc) ->
case catch process_info(P, [memory, dictionary]) of
[{_, Memory}, {_, Dict}] ->
InitStart = util:prop_get_value('$initial_call', Dict, null),
case lists:keyfind(InitStart, 1, Acc) of
false -> [{InitStart, Memory, 1} | Acc];
{InitStart, Memory1, Num} -> lists:keystore(InitStart, 1, Acc, {InitStart, Memory + Memory1, Num + 1})
end;
_ -> Acc
end
end,
Infos1 = lists:foldl(F, [], processes()),
Infos2 = [{Name, M, Num} || {Name, M, Num} <- Infos1, Name =/= null],
SortFun = fun({_, M1, _}, {_, M2, _}) -> M1 > M2 end,
Infos3 = lists:sort(SortFun, Infos2),
Infos4 = lists:sublist(Infos3, N),
[io:format("~p : per_memory=~p process_num=~p ~n", [Name, (M div Num), Num]) || {Name, M, Num} <- Infos4],
ok.

+ 409
- 0
src/srvNodeMgr/tools_cq/mmake.erl Dosyayı Görüntüle

@ -0,0 +1,409 @@
%% ,otp/lib/tools/src/make.erl
%% Emakefile,{mods, options},
%% ()
%% mods也可以包含多个模块,1,
%% process进行编译,.
-module(mmake).
-include_lib("kernel/include/file.hrl").
-export([
all/1,
all/2,
files/2,
files/3
]).
-define(MakeOpts, [noexec, load, netload, noload]).
all(Worker) when is_integer(Worker) ->
all(Worker, []).
all(Worker, Options) when is_integer(Worker) ->
%% io:format("make all Options:~w", [Options]),
{MakeOpts, CompileOpts} = sort_options(Options, [], []),
case read_emakefile('Emakefile', CompileOpts) of
Files when is_list(Files) ->
do_make_files(Worker, Files, MakeOpts);
error ->
error
end.
files(Worker, Fs) ->
files(Worker, Fs, []).
files(Worker, Fs0, Options) ->
Fs = [filename:rootname(F, ".erl") || F <- Fs0],
{MakeOpts, CompileOpts} = sort_options(Options, [], []),
case get_opts_from_emakefile(Fs, 'Emakefile', CompileOpts) of
Files when is_list(Files) ->
do_make_files(Worker, Files, MakeOpts);
error -> error
end.
do_make_files(Worker, Fs, Opts) ->
%io:format("worker:~p~nfs:~p~nopts:~p~n", [Worker, Fs, Opts]),
process(Fs, Worker, lists:member(noexec, Opts), load_opt(Opts)).
sort_options([H | T], Make, Comp) ->
case lists:member(H, ?MakeOpts) of
true ->
sort_options(T, [H | Make], Comp);
false ->
sort_options(T, Make, [H | Comp])
end;
sort_options([], Make, Comp) ->
{Make, lists:reverse(Comp)}.
%%% Reads the given Emakefile and returns a list of tuples: {Mods,Opts}
%%% Mods is a list of module names (strings)
%%% Opts is a list of options to be used when compiling Mods
%%%
%%% Emakefile can contain elements like this:
%%% Mod.
%%% {Mod,Opts}.
%%% Mod is a module name which might include '*' as wildcard
%%% or a list of such module names
%%%
%%% These elements are converted to [{ModList,OptList},...]
%%% ModList is a list of modulenames (strings)
read_emakefile(Emakefile, Opts) ->
case file:consult(Emakefile) of
{ok, Emake} ->
transform(Emake, Opts, [], []);
{error, enoent} ->
%% No Emakefile found - return all modules in current
%% directory and the options given at command line
Mods = [filename:rootname(F) || F <- filelib:wildcard("*.erl")],
[{Mods, Opts}];
{error, Other} ->
io:format("make: Trouble reading 'Emakefile':~n~p~n", [Other]),
error
end.
transform([{Mod, ModOpts} | Emake], Opts, Files, Already) ->
case expand(Mod, Already) of
[] ->
transform(Emake, Opts, Files, Already);
Mods ->
transform(Emake, Opts, [{Mods, ModOpts ++ Opts} | Files], Mods ++ Already)
end;
transform([Mod | Emake], Opts, Files, Already) ->
case expand(Mod, Already) of
[] ->
transform(Emake, Opts, Files, Already);
Mods ->
transform(Emake, Opts, [{Mods, Opts} | Files], Mods ++ Already)
end;
transform([], _Opts, Files, _Already) ->
lists:reverse(Files).
expand(Mod, Already) when is_atom(Mod) ->
expand(atom_to_list(Mod), Already);
expand(Mods, Already) when is_list(Mods), not is_integer(hd(Mods)) ->
lists:concat([expand(Mod, Already) || Mod <- Mods]);
expand(Mod, Already) ->
case lists:member($*, Mod) of
true ->
Fun = fun(F, Acc) ->
M = filename:rootname(F),
case lists:member(M, Already) of
true -> Acc;
false -> [M | Acc]
end
end,
lists:foldl(Fun, [], filelib:wildcard(Mod ++ ".erl"));
false ->
Mod2 = filename:rootname(Mod, ".erl"),
case lists:member(Mod2, Already) of
true -> [];
false -> [Mod2]
end
end.
%%% Reads the given Emakefile to see if there are any specific compile
%%% options given for the modules.
get_opts_from_emakefile(Mods, Emakefile, Opts) ->
case file:consult(Emakefile) of
{ok, Emake} ->
Modsandopts = transform(Emake, Opts, [], []),
ModStrings = [coerce_2_list(M) || M <- Mods],
get_opts_from_emakefile2(Modsandopts, ModStrings, Opts, []);
{error, enoent} ->
[{Mods, Opts}];
{error, Other} ->
io:format("make: Trouble reading 'Emakefile':~n~p~n", [Other]),
error
end.
get_opts_from_emakefile2([{MakefileMods, O} | Rest], Mods, Opts, Result) ->
case members(Mods, MakefileMods, [], Mods) of
{[], _} ->
get_opts_from_emakefile2(Rest, Mods, Opts, Result);
{I, RestOfMods} ->
get_opts_from_emakefile2(Rest, RestOfMods, Opts, [{I, O} | Result])
end;
get_opts_from_emakefile2([], [], _Opts, Result) ->
Result;
get_opts_from_emakefile2([], RestOfMods, Opts, Result) ->
[{RestOfMods, Opts} | Result].
members([H | T], MakefileMods, I, Rest) ->
case lists:member(H, MakefileMods) of
true ->
members(T, MakefileMods, [H | I], lists:delete(H, Rest));
false ->
members(T, MakefileMods, I, Rest)
end;
members([], _MakefileMods, I, Rest) ->
{I, Rest}.
%% Any flags that are not recognixed as make flags are passed directly
%% to the compiler.
%% So for example make:all([load,debug_info]) will make everything
%% with the debug_info flag and load it.
load_opt(Opts) ->
case lists:member(netload, Opts) of
true ->
netload;
false ->
case lists:member(load, Opts) of
true ->
load;
_ ->
noload
end
end.
%%
process([{[], _Opts} | Rest], Worker, NoExec, Load) ->
process(Rest, Worker, NoExec, Load);
process([{L, Opts} | Rest], Worker, NoExec, Load) ->
Len = length(L),
Worker2 = erlang:min(Len, Worker),
case catch do_worker(L, Opts, NoExec, Load, Worker2) of
error ->
error;
ok ->
process(Rest, Worker, NoExec, Load)
end;
process([], _Worker, _NoExec, _Load) ->
up_to_date.
%% worker进行编译
%do_worker(L, Opts, NoExec, Load, Worker) ->
% WorkerList = do_split_list(L, Worker),
% io:format("worker:~p worker list(~p)~n,WorkerList:~p~n", [Worker, length(WorkerList)]),
% %
% Ref = make_ref(),
% Pids =
% [begin
% start_worker(E, Opts, NoExec, Load, self(), Ref)
% end || E <- WorkerList],
% do_wait_worker(length(Pids), Ref).
%
%%%
%do_wait_worker(0, _Ref) ->
% ok;
%do_wait_worker(N, Ref) ->
% receive
% {ack, Ref} ->
% do_wait_worker(N - 1, Ref);
% {error, Ref} ->
% throw(error);
% {'EXIT', _P, _Reason} ->
% do_wait_worker(N, Ref);
% _Other ->
% io:format("receive unknown msg:~p~n", [_Other]),
% do_wait_worker(N, Ref)
% end.
do_worker(L, Opts, NoExec, Load, Worker) ->
%% worker个编译进程
SplitNum = min(length(L), Worker),
{L1, L2} = lists:split(SplitNum, L),
%
Ref = make_ref(),
Pids =
[begin
start_worker([E], Opts, NoExec, Load, self(), Ref)
end || E <- L1],
do_wait_worker(length(Pids), L2, Opts, NoExec, Load, Ref).
%% @doc ,
do_wait_worker(0, [], _Opts, _NoExec, _Load, _Ref) ->
ok;
do_wait_worker(N, L, Opts, NoExec, Load, Ref) ->
receive
{ack, Ref} ->
case L of
[H | T] ->
%%
start_worker(H, Opts, NoExec, Load, self(), Ref),
do_wait_worker(N, T, Opts, NoExec, Load, Ref);
[] ->
%%
do_wait_worker(N - 1, [], Opts, NoExec, Load, Ref)
end;
{error, Ref} ->
throw(error);
{'EXIT', _P, _Reason} ->
do_wait_worker(N, L, Opts, NoExec, Load, Ref);
_Other ->
io:format("receive unknown msg:~p~n", [_Other]),
do_wait_worker(N, L, Opts, NoExec, Load, Ref)
end.
%% L分割成最多包含N个子列表的列表
%do_split_list(L, N) ->
% Len = length(L),
% %
% LLen = (Len + N - 1) div N,
% do_split_list(L, LLen, []).
%
%do_split_list([], _N, Acc) ->
% lists:reverse(Acc);
%do_split_list(L, N, Acc) ->
% {L2, L3} = lists:split(erlang:min(length(L), N), L),
% do_split_list(L3, N, [L2 | Acc]).
%
%%% worker进程
%start_worker(L, Opts, NoExec, Load, Parent, Ref) ->
% Fun =
% fun() ->
% [begin
% case recompilep(coerce_2_list(F), NoExec, Load, Opts) of
% error ->
% Parent ! {error, Ref},
% exit(error);
% _ ->
% ok
% end
% end || F <- L],
% Parent ! {ack, Ref}
% end,
% spawn_link(Fun).
%% worker进程
start_worker(F, Opts, NoExec, Load, Parent, Ref) ->
Fun =
fun() ->
case recompilep(coerce_2_list(F), NoExec, Load, Opts) of
error ->
Parent ! {error, Ref},
exit(error);
_ ->
ok
end,
Parent ! {ack, Ref}
end,
spawn_link(Fun).
recompilep(File, NoExec, Load, Opts) ->
ObjName = lists:append(filename:basename(File),
code:objfile_extension()),
ObjFile = case lists:keysearch(outdir, 1, Opts) of
{value, {outdir, OutDir}} ->
filename:join(coerce_2_list(OutDir), ObjName);
false ->
ObjName
end,
case exists(ObjFile) of
true ->
recompilep1(File, NoExec, Load, Opts, ObjFile);
false ->
recompile(File, NoExec, Load, Opts)
end.
recompilep1(File, NoExec, Load, Opts, ObjFile) ->
{ok, Erl} = file:read_file_info(lists:append(File, ".erl")),
{ok, Obj} = file:read_file_info(ObjFile),
recompilep1(Erl, Obj, File, NoExec, Load, Opts).
recompilep1(#file_info{mtime = Te},
#file_info{mtime = To}, File, NoExec, Load, Opts) when Te > To ->
recompile(File, NoExec, Load, Opts);
recompilep1(_Erl, #file_info{mtime = To}, File, NoExec, Load, Opts) ->
recompile2(To, File, NoExec, Load, Opts).
%% recompile2(ObjMTime, File, NoExec, Load, Opts)
%% Check if file is of a later date than include files.
recompile2(ObjMTime, File, NoExec, Load, Opts) ->
IncludePath = include_opt(Opts),
case check_includes(lists:append(File, ".erl"), IncludePath, ObjMTime) of
true ->
recompile(File, NoExec, Load, Opts);
false ->
false
end.
include_opt([{i, Path} | Rest]) ->
[Path | include_opt(Rest)];
include_opt([_First | Rest]) ->
include_opt(Rest);
include_opt([]) ->
[].
%% recompile(File, NoExec, Load, Opts)
%% Actually recompile and load the file, depending on the flags.
%% Where load can be netload | load | noload
recompile(File, true, _Load, _Opts) ->
io:format("Out of date: ~s\n", [File]);
recompile(File, false, noload, Opts) ->
io:format("Recompile: ~s\n", [File]),
compile:file(File, [report_errors, report_warnings, error_summary | Opts]);
recompile(File, false, load, Opts) ->
io:format("Recompile: ~s\n", [File]),
c:c(File, Opts);
recompile(File, false, netload, Opts) ->
io:format("Recompile: ~s\n", [File]),
c:nc(File, Opts).
exists(File) ->
case file:read_file_info(File) of
{ok, _} ->
true;
_ ->
false
end.
coerce_2_list(X) when is_atom(X) ->
atom_to_list(X);
coerce_2_list(X) ->
X.
%%% If you an include file is found with a modification
%%% time larger than the modification time of the object
%%% file, return true. Otherwise return false.
check_includes(File, IncludePath, ObjMTime) ->
Path = [filename:dirname(File) | IncludePath],
case epp:open(File, Path, []) of
{ok, Epp} ->
check_includes2(Epp, File, ObjMTime);
_Error ->
false
end.
check_includes2(Epp, File, ObjMTime) ->
case epp:parse_erl_form(Epp) of
{ok, {attribute, 1, file, {File, 1}}} ->
check_includes2(Epp, File, ObjMTime);
{ok, {attribute, 1, file, {IncFile, 1}}} ->
case file:read_file_info(IncFile) of
{ok, #file_info{mtime = MTime}} when MTime > ObjMTime ->
epp:close(Epp),
true;
_ ->
check_includes2(Epp, File, ObjMTime)
end;
{ok, _} ->
check_includes2(Epp, File, ObjMTime);
{eof, _} ->
epp:close(Epp),
false;
{error, _Error} ->
check_includes2(Epp, File, ObjMTime)
end.

+ 704
- 0
src/srvNodeMgr/tools_cq/recon/recon.erl Dosyayı Görüntüle

@ -0,0 +1,704 @@
%%% @author Fred Hebert <mononcqc@ferd.ca>
%%% [http://ferd.ca/]
%%% @doc Recon, as a module, provides access to the high-level functionality
%%% contained in the Recon application.
%%%
%%% It has functions in five main categories:
%%%
%%% <dl>
%%% <dt>1. State information</dt>
%%% <dd>Process information is everything that has to do with the
%%% general state of the node. Functions such as {@link info/1}
%%% and {@link info/3} are wrappers to provide more details than
%%% `erlang:process_info/1', while providing it in a production-safe
%%% manner. They have equivalents to `erlang:process_info/2' in
%%% the functions {@link info/2} and {@link info/4}, respectively.</dd>
%%% <dd>{@link proc_count/2} and {@link proc_window/3} are to be used
%%% when you require information about processes in a larger sense:
%%% biggest consumers of given process information (say memory or
%%% reductions), either absolutely or over a sliding time window,
%%% respectively.</dd>
%%% <dd>{@link bin_leak/1} is a function that can be used to try and
%%% see if your Erlang node is leaking refc binaries. See the function
%%% itself for more details.</dd>
%%% <dd>Functions to access node statistics, in a manner somewhat similar
%%% to what <a href="https://github.com/ferd/vmstats">vmstats</a>
%%% provides as a library. There are 3 of them:
%%% {@link node_stats_print/2}, which displays them,
%%% {@link node_stats_list/2}, which returns them in a list, and
%%% {@link node_stats/4}, which provides a fold-like interface
%%% for stats gathering. For CPU usage specifically, see
%%% {@link scheduler_usage/1}.</dd>
%%%
%%% <dt>2. OTP tools</dt>
%%% <dd>This category provides tools to interact with pieces of OTP
%%% more easily. At this point, the only function included is
%%% {@link get_state/1}, which works as a wrapper around
%%% {@link get_state/2}, which works as a wrapper around
%%% `sys:get_state/1' in R16B01, and provides the required
%%% functionality for older versions of Erlang.</dd>
%%%
%%% <dt>3. Code Handling</dt>
%%% <dd>Specific functions are in `recon' for the sole purpose
%%% of interacting with source and compiled code.
%%% {@link remote_load/1} and {@link remote_load/2} will allow
%%% to take a local module, and load it remotely (in a diskless
%%% manner) on another Erlang node you're connected to.</dd>
%%% <dd>{@link source/1} allows to print the source of a loaded module,
%%% in case it's not available in the currently running node.</dd>
%%%
%%% <dt>4. Ports and Sockets</dt>
%%% <dd>To make it simpler to debug some network-related issues,
%%% recon contains functions to deal with Erlang ports (raw, file
%%% handles, or inet). Functions {@link tcp/0}, {@link udp/0},
%%% {@link sctp/0}, {@link files/0}, and {@link port_types/0} will
%%% list all the Erlang ports of a given type. The latter function
%%% prints counts of all individual types.</dd>
%%% <dd>Port state information can be useful to figure out why certain
%%% parts of the system misbehave. Functions such as
%%% {@link port_info/1} and {@link port_info/2} are wrappers to provide
%%% more similar or more details than `erlang:port_info/1-2', and, for
%%% inet ports, statistics and options for each socket.</dd>
%%% <dd>Finally, the functions {@link inet_count/2} and {@link inet_window/3}
%%% provide the absolute or sliding window functionality of
%%% {@link proc_count/2} and {@link proc_count/3} to inet ports
%%% and connections currently on the node.</dd>
%%%
%%% <dt>5. RPC</dt>
%%% <dd>These are wrappers to make RPC work simpler with clusters of
%%% Erlang nodes. Default RPC mechanisms (from the `rpc' module)
%%% make it somewhat painful to call shell-defined funs over node
%%% boundaries. The functions {@link rpc/1}, {@link rpc/2}, and
%%% {@link rpc/3} will do it with a simpler interface.</dd>
%%% <dd>Additionally, when you're running diagnostic code on remote
%%% nodes and want to know which node evaluated what result, using
%%% {@link named_rpc/1}, {@link named_rpc/2}, and {@link named_rpc/3}
%%% will wrap the results in a tuple that tells you which node it's
%%% coming from, making it easier to identify bad nodes.</dd>
%%% </dl>
%%% @end
-module(recon).
-export([info/1, info/2, info/3, info/4,
proc_count/2, proc_window/3,
bin_leak/1,
node_stats_print/2, node_stats_list/2, node_stats/4,
scheduler_usage/1]).
-export([get_state/1, get_state/2]).
-export([remote_load/1, remote_load/2,
source/1]).
-export([tcp/0, udp/0, sctp/0, files/0, port_types/0,
inet_count/2, inet_window/3,
port_info/1, port_info/2]).
-export([rpc/1, rpc/2, rpc/3,
named_rpc/1, named_rpc/2, named_rpc/3]).
%%%%%%%%%%%%%
%%% TYPES %%%
%%%%%%%%%%%%%
-type proc_attrs() :: {pid(),
Attr :: _,
[Name :: atom()
|{current_function, mfa()}
|{initial_call, mfa()}, ...]}.
-type inet_attrs() :: {port(),
Attr :: _,
[{atom(), term()}]}.
-type pid_term() :: pid() | atom() | string()
| {global, term()} | {via, module(), term()}
| {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
-type info_type() :: meta | signals | location | memory_used | work.
-type info_meta_key() :: registered_name | dictionary | group_leader | status.
-type info_signals_key() :: links | monitors | monitored_by | trap_exit.
-type info_location_key() :: initial_call | current_stacktrace.
-type info_memory_key() :: memory | message_queue_len | heap_size
| total_heap_size | garbage_collection.
-type info_work_key() :: reductions.
-type info_key() :: info_meta_key() | info_signals_key() | info_location_key()
| info_memory_key() | info_work_key().
-type port_term() :: port() | string() | atom() | pos_integer().
-type port_info_type() :: meta | signals | io | memory_used | specific.
-type port_info_meta_key() :: registered_name | id | name | os_pid.
-type port_info_signals_key() :: connected | links | monitors.
-type port_info_io_key() :: input | output.
-type port_info_memory_key() :: memory | queue_size.
-type port_info_specific_key() :: atom().
-type port_info_key() :: port_info_meta_key() | port_info_signals_key()
| port_info_io_key() | port_info_memory_key()
| port_info_specific_key().
-export_type([proc_attrs/0, inet_attrs/0, pid_term/0, port_term/0]).
-export_type([info_type/0, info_key/0,
info_meta_key/0, info_signals_key/0, info_location_key/0,
info_memory_key/0, info_work_key/0]).
-export_type([port_info_type/0, port_info_key/0,
port_info_meta_key/0, port_info_signals_key/0, port_info_io_key/0,
port_info_memory_key/0, port_info_specific_key/0]).
%%%%%%%%%%%%%%%%%%
%%% PUBLIC API %%%
%%%%%%%%%%%%%%%%%%
%%% Process Info %%%
%% @doc Equivalent to `info(<A.B.C>)' where `A', `B', and `C' are integers part
%% of a pid
-spec info(N, N, N) -> [{info_type(), [{info_key(), term()}]}, ...] when
N :: non_neg_integer().
info(A, B, C) -> info(recon_lib:triple_to_pid(A, B, C)).
%% @doc Equivalent to `info(<A.B.C>, Key)' where `A', `B', and `C' are integers part
%% of a pid
-spec info(N, N, N, Key) -> term() when
N :: non_neg_integer(),
Key :: info_type() | [atom()] | atom().
info(A, B, C, Key) -> info(recon_lib:triple_to_pid(A, B, C), Key).
%% @doc Allows to be similar to `erlang:process_info/1', but excludes fields
%% such as the mailbox, which have a tendency to grow and be unsafe when called
%% in production systems. Also includes a few more fields than what is usually
%% given (`monitors', `monitored_by', etc.), and separates the fields in a more
%% readable format based on the type of information contained.
%%
%% Moreover, it will fetch and read information on local processes that were
%% registered locally (an atom), globally (`{global, Name}'), or through
%% another registry supported in the `{via, Module, Name}' syntax (must have a
%% `Module:whereis_name/1' function). Pids can also be passed in as a string
%% (`"<0.39.0>"') or a triple (`{0,39,0}') and will be converted to be used.
-spec info(pid_term()) -> [{info_type(), [{info_key(), Value}]}, ...] when
Value :: term().
info(PidTerm) ->
Pid = recon_lib:term_to_pid(PidTerm),
[info(Pid, Type) || Type <- [meta, signals, location, memory_used, work]].
%% @doc Allows to be similar to `erlang:process_info/2', but allows to
%% sort fields by safe categories and pre-selections, avoiding items such
%% as the mailbox, which may have a tendency to grow and be unsafe when
%% called in production systems.
%%
%% Moreover, it will fetch and read information on local processes that were
%% registered locally (an atom), globally (`{global, Name}'), or through
%% another registry supported in the `{via, Module, Name}' syntax (must have a
%% `Module:whereis_name/1' function). Pids can also be passed in as a string
%% (`"<0.39.0>"') or a triple (`{0,39,0}') and will be converted to be used.
%%
%% Although the type signature doesn't show it in generated documentation,
%% a list of arguments or individual arguments accepted by
%% `erlang:process_info/2' and return them as that function would.
%%
%% A fake attribute `binary_memory' is also available to return the
%% amount of memory used by refc binaries for a process.
-spec info(pid_term(), info_type()) -> {info_type(), [{info_key(), term()}]}
; (pid_term(), [atom()]) -> [{atom(), term()}]
; (pid_term(), atom()) -> {atom(), term()}.
info(PidTerm, meta) ->
info_type(PidTerm, meta, [registered_name, dictionary, group_leader,
status]);
info(PidTerm, signals) ->
info_type(PidTerm, signals, [links, monitors, monitored_by, trap_exit]);
info(PidTerm, location) ->
info_type(PidTerm, location, [initial_call, current_stacktrace]);
info(PidTerm, memory_used) ->
info_type(PidTerm, memory_used, [memory, message_queue_len, heap_size,
total_heap_size, garbage_collection]);
info(PidTerm, work) ->
info_type(PidTerm, work, [reductions]);
info(PidTerm, Keys) ->
proc_info(recon_lib:term_to_pid(PidTerm), Keys).
%% @private makes access to `info_type()' calls simpler.
-spec info_type(pid_term(), info_type(), [info_key()]) ->
{info_type(), [{info_key(), term()}]}.
info_type(PidTerm, Type, Keys) ->
Pid = recon_lib:term_to_pid(PidTerm),
{Type, proc_info(Pid, Keys)}.
%% @private wrapper around `erlang:process_info/2' that allows special
%% attribute handling for items like `binary_memory'.
proc_info(Pid, binary_memory) ->
{binary, Bins} = erlang:process_info(Pid, binary),
{binary_memory, recon_lib:binary_memory(Bins)};
proc_info(Pid, Term) when is_atom(Term) ->
erlang:process_info(Pid, Term);
proc_info(Pid, List) when is_list(List) ->
case lists:member(binary_memory, List) of
false ->
erlang:process_info(Pid, List);
true ->
Res = erlang:process_info(Pid, replace(binary_memory, binary, List)),
proc_fake(List, Res)
end.
%% @private Replace keys around
replace(_, _, []) -> [];
replace(H, Val, [H | T]) -> [Val | replace(H, Val, T)];
replace(R, Val, [H | T]) -> [H | replace(R, Val, T)].
proc_fake([], []) ->
[];
proc_fake([binary_memory | T1], [{binary, Bins} | T2]) ->
[{binary_memory, recon_lib:binary_memory(Bins)}
| proc_fake(T1, T2)];
proc_fake([_ | T1], [H | T2]) ->
[H | proc_fake(T1, T2)].
%% @doc Fetches a given attribute from all processes (except the
%% caller) and returns the biggest `Num' consumers.
%% @todo Implement this function so it only stores `Num' entries in
%% memory at any given time, instead of as many as there are
%% processes.
-spec proc_count(AttributeName, Num) -> [proc_attrs()] when
AttributeName :: atom(),
Num :: non_neg_integer().
proc_count(AttrName, Num) ->
recon_lib:sublist_top_n_attrs(recon_lib:proc_attrs(AttrName), Num).
%% @doc Fetches a given attribute from all processes (except the
%% caller) and returns the biggest entries, over a sliding time window.
%%
%% This function is particularly useful when processes on the node
%% are mostly short-lived, usually too short to inspect through other
%% tools, in order to figure out what kind of processes are eating
%% through a lot resources on a given node.
%%
%% It is important to see this function as a snapshot over a sliding
%% window. A program's timeline during sampling might look like this:
%%
%% `--w---- [Sample1] ---x-------------y----- [Sample2] ---z--->'
%%
%% Some processes will live between `w' and die at `x', some between `y' and
%% `z', and some between `x' and `y'. These samples will not be too significant
%% as they're incomplete. If the majority of your processes run between a time
%% interval `x'...`y' (in absolute terms), you should make sure that your
%% sampling time is smaller than this so that for many processes, their
%% lifetime spans the equivalent of `w' and `z'. Not doing this can skew the
%% results: long-lived processes, that have 10 times the time to accumulate
%% data (say reductions) will look like bottlenecks when they're not one.
%%
%% Warning: this function depends on data gathered at two snapshots, and then
%% building a dictionary with entries to differentiate them. This can take a
%% heavy toll on memory when you have many dozens of thousands of processes.
-spec proc_window(AttributeName, Num, Milliseconds) -> [proc_attrs()] when
AttributeName :: atom(),
Num :: non_neg_integer(),
Milliseconds :: pos_integer().
proc_window(AttrName, Num, Time) ->
Sample = fun() -> recon_lib:proc_attrs(AttrName) end,
{First, Last} = recon_lib:sample(Time, Sample),
recon_lib:sublist_top_n_attrs(recon_lib:sliding_window(First, Last), Num).
%% @doc Refc binaries can be leaking when barely-busy processes route them
%% around and do little else, or when extremely busy processes reach a stable
%% amount of memory allocated and do the vast majority of their work with refc
%% binaries. When this happens, it may take a very long while before references
%% get deallocated and refc binaries get to be garbage collected, leading to
%% Out Of Memory crashes.
%% This function fetches the number of refc binary references in each process
%% of the node, garbage collects them, and compares the resulting number of
%% references in each of them. The function then returns the `N' processes
%% that freed the biggest amount of binaries, potentially highlighting leaks.
%%
%% See <a href="http://www.erlang.org/doc/efficiency_guide/binaryhandling.html#id65722">The efficiency guide</a>
%% for more details on refc binaries
-spec bin_leak(pos_integer()) -> [proc_attrs()].
bin_leak(N) ->
Procs = recon_lib:sublist_top_n_attrs([
try
{ok, {_, Pre, Id}} = recon_lib:proc_attrs(binary, Pid),
erlang:garbage_collect(Pid),
{ok, {_, Post, _}} = recon_lib:proc_attrs(binary, Pid),
{Pid, length(Pre) - length(Post), Id}
catch
_:_ -> {Pid, 0, []}
end || Pid <- processes()
], N),
[{Pid, -Val, Id} || {Pid, Val, Id} <- Procs].
%% @doc Shorthand for `node_stats(N, Interval, fun(X,_) -> io:format("~p~n",[X]) end, nostate)'.
-spec node_stats_print(Repeat, Interval) -> term() when
Repeat :: non_neg_integer(),
Interval :: pos_integer().
node_stats_print(N, Interval) ->
node_stats(N, Interval, fun(X, _) -> io:format("~p~n", [X]) end, ok).
%% @doc Because Erlang CPU usage as reported from `top' isn't the most
%% reliable value (due to schedulers doing idle spinning to avoid going
%% to sleep and impacting latency), a metric exists that is based on
%% scheduler wall time.
%%
%% For any time interval, Scheduler wall time can be used as a measure
%% of how 'busy' a scheduler is. A scheduler is busy when:
%%
%% <ul>
%% <li>executing process code</li>
%% <li>executing driver code</li>
%% <li>executing NIF code</li>
%% <li>executing BIFs</li>
%% <li>garbage collecting</li>
%% <li>doing memory management</li>
%% </ul>
%%
%% A scheduler isn't busy when doing anything else.
-spec scheduler_usage(Millisecs) -> [{SchedulerId, Usage}] when
Millisecs :: non_neg_integer(),
SchedulerId :: pos_integer(),
Usage :: number().
scheduler_usage(Interval) when is_integer(Interval) ->
%% We start and stop the scheduler_wall_time system flag if
%% it wasn't in place already. Usually setting the flag should
%% have a CPU impact (making it higher) only when under low usage.
FormerFlag = erlang:system_flag(scheduler_wall_time, true),
First = erlang:statistics(scheduler_wall_time),
timer:sleep(Interval),
Last = erlang:statistics(scheduler_wall_time),
erlang:system_flag(scheduler_wall_time, FormerFlag),
recon_lib:scheduler_usage_diff(First, Last).
%% @doc Shorthand for `node_stats(N, Interval, fun(X,Acc) -> [X|Acc] end, [])'
%% with the results reversed to be in the right temporal order.
-spec node_stats_list(Repeat, Interval) -> [Stats] when
Repeat :: non_neg_integer(),
Interval :: pos_integer(),
Stats :: {[Absolutes :: {atom(), term()}],
[Increments :: {atom(), term()}]}.
node_stats_list(N, Interval) ->
lists:reverse(node_stats(N, Interval, fun(X, Acc) -> [X | Acc] end, [])).
%% @doc Gathers statistics `N' time, waiting `Interval' milliseconds between
%% each run, and accumulates results using a folding function `FoldFun'.
%% The function will gather statistics in two forms: Absolutes and Increments.
%%
%% Absolutes are values that keep changing with time, and are useful to know
%% about as a datapoint: process count, size of the run queue, error_logger
%% queue length, and the memory of the node (total, processes, atoms, binaries,
%% and ets tables).
%%
%% Increments are values that are mostly useful when compared to a previous
%% one to have an idea what they're doing, because otherwise they'd never
%% stop increasing: bytes in and out of the node, number of garbage colelctor
%% runs, words of memory that were garbage collected, and the global reductions
%% count for the node.
-spec node_stats(N, Interval, FoldFun, Acc) -> Acc when
N :: non_neg_integer(),
Interval :: pos_integer(),
FoldFun :: fun((Stats, Acc) -> Acc),
Acc :: term(),
Stats :: {[Absolutes :: {atom(), term()}],
[Increments :: {atom(), term()}]}.
node_stats(N, Interval, FoldFun, Init) ->
%% Turn on scheduler wall time if it wasn't there already
FormerFlag = erlang:system_flag(scheduler_wall_time, true),
%% Stats is an ugly fun, but it does its thing.
Stats = fun({{OldIn, OldOut}, {OldGCs, OldWords, _}, SchedWall}) ->
%% Absolutes
ProcC = erlang:system_info(process_count),
RunQ = erlang:statistics(run_queue),
{_, LogQ} = process_info(whereis(error_logger), message_queue_len),
%% Mem (Absolutes)
Mem = erlang:memory(),
Tot = proplists:get_value(total, Mem),
ProcM = proplists:get_value(processes_used, Mem),
Atom = proplists:get_value(atom_used, Mem),
Bin = proplists:get_value(binary, Mem),
Ets = proplists:get_value(ets, Mem),
%% Incremental
{{input, In}, {output, Out}} = erlang:statistics(io),
GC = {GCs, Words, _} = erlang:statistics(garbage_collection),
BytesIn = In - OldIn,
BytesOut = Out - OldOut,
GCCount = GCs - OldGCs,
GCWords = Words - OldWords,
{_, Reds} = erlang:statistics(reductions),
SchedWallNew = erlang:statistics(scheduler_wall_time),
SchedUsage = recon_lib:scheduler_usage_diff(SchedWall, SchedWallNew),
%% Stats Results
{{[{process_count, ProcC}, {run_queue, RunQ},
{error_logger_queue_len, LogQ}, {memory_total, Tot},
{memory_procs, ProcM}, {memory_atoms, Atom},
{memory_bin, Bin}, {memory_ets, Ets}],
[{bytes_in, BytesIn}, {bytes_out, BytesOut},
{gc_count, GCCount}, {gc_words_reclaimed, GCWords},
{reductions, Reds}, {scheduler_usage, SchedUsage}]},
%% New State
{{In, Out}, GC, SchedWallNew}}
end,
{{input, In}, {output, Out}} = erlang:statistics(io),
Gc = erlang:statistics(garbage_collection),
SchedWall = erlang:statistics(scheduler_wall_time),
Result = recon_lib:time_fold(
N, Interval, Stats,
{{In, Out}, Gc, SchedWall},
FoldFun, Init),
%% Set scheduler wall time back to what it was
erlang:system_flag(scheduler_wall_time, FormerFlag),
Result.
%%% OTP & Manipulations %%%
%% @doc Shorthand call to `recon:get_state(PidTerm, 5000)'
-spec get_state(pid_term()) -> term().
get_state(PidTerm) -> get_state(PidTerm, 5000).
%% @doc Fetch the internal state of an OTP process.
%% Calls `sys:get_state/2' directly in R16B01+, and fetches
%% it dynamically on older versions of OTP.
-spec get_state(pid_term(), Ms :: non_neg_integer() | 'infinity') -> term().
get_state(PidTerm, Timeout) ->
Proc = recon_lib:term_to_pid(PidTerm),
try
sys:get_state(Proc, Timeout)
catch
error:undef ->
case sys:get_status(Proc, Timeout) of
{status, _Pid, {module, gen_server}, Data} ->
{data, Props} = lists:last(lists:nth(5, Data)),
proplists:get_value("State", Props);
{status, _Pod, {module, gen_fsm}, Data} ->
{data, Props} = lists:last(lists:nth(5, Data)),
proplists:get_value("StateData", Props)
end
end.
%%% Code & Stuff %%%
%% @equiv remote_load(nodes(), Mod)
-spec remote_load(module()) -> term().
remote_load(Mod) -> remote_load(nodes(), Mod).
%% @doc Loads one or more modules remotely, in a diskless manner. Allows to
%% share code loaded locally with a remote node that doesn't have it
-spec remote_load(Nodes, module()) -> term() when
Nodes :: [node(), ...] | node().
remote_load(Nodes = [_ | _], Mod) when is_atom(Mod) ->
{Mod, Bin, File} = code:get_object_code(Mod),
rpc:multicall(Nodes, code, load_binary, [Mod, File, Bin]);
remote_load(Nodes = [_ | _], Modules) when is_list(Modules) ->
[remote_load(Nodes, Mod) || Mod <- Modules];
remote_load(Node, Mod) ->
remote_load([Node], Mod).
%% @doc Obtain the source code of a module compiled with `debug_info'.
%% The returned list sadly does not allow to format the types and typed
%% records the way they look in the original module, but instead goes to
%% an intermediary form used in the AST. They will still be placed
%% in the right module attributes, however.
%% @todo Figure out a way to pretty-print typespecs and records.
-spec source(module()) -> iolist().
source(Module) ->
Path = code:which(Module),
{ok, {_, [{abstract_code, {_, AC}}]}} = beam_lib:chunks(Path, [abstract_code]),
erl_prettypr:format(erl_syntax:form_list(AC)).
%%% Ports Info %%%
%% @doc returns a list of all TCP ports (the data type) open on the node.
-spec tcp() -> [port()].
tcp() -> recon_lib:port_list(name, "tcp_inet").
%% @doc returns a list of all UDP ports (the data type) open on the node.
-spec udp() -> [port()].
udp() -> recon_lib:port_list(name, "udp_inet").
%% @doc returns a list of all SCTP ports (the data type) open on the node.
-spec sctp() -> [port()].
sctp() -> recon_lib:port_list(name, "sctp_inet").
%% @doc returns a list of all file handles open on the node.
-spec files() -> [port()].
files() -> recon_lib:port_list(name, "efile").
%% @doc Shows a list of all different ports on the node with their respective
%% types.
-spec port_types() -> [{Type :: string(), Count :: pos_integer()}].
port_types() ->
lists:usort(
%% sorts by biggest count, smallest type
fun({KA, VA}, {KB, VB}) -> {VA, KB} > {VB, KA} end,
recon_lib:count([Name || {_, Name} <- recon_lib:port_list(name)])
).
%% @doc Fetches a given attribute from all inet ports (TCP, UDP, SCTP)
%% and returns the biggest `Num' consumers.
%%
%% The values to be used can be the number of octets (bytes) sent, received,
%% or both (`send_oct', `recv_oct', `oct', respectively), or the number
%% of packets sent, received, or both (`send_cnt', `recv_cnt', `cnt',
%% respectively). Individual absolute values for each metric will be returned
%% in the 3rd position of the resulting tuple.
%%
%% @todo Implement this function so it only stores `Num' entries in
%% memory at any given time, instead of as many as there are
%% processes.
-spec inet_count(AttributeName, Num) -> [inet_attrs()] when
AttributeName :: 'recv_cnt' | 'recv_oct' | 'send_cnt' | 'send_oct'
| 'cnt' | 'oct',
Num :: non_neg_integer().
inet_count(Attr, Num) ->
recon_lib:sublist_top_n_attrs(recon_lib:inet_attrs(Attr), Num).
%% @doc Fetches a given attribute from all inet ports (TCP, UDP, SCTP)
%% and returns the biggest entries, over a sliding time window.
%%
%% Warning: this function depends on data gathered at two snapshots, and then
%% building a dictionary with entries to differentiate them. This can take a
%% heavy toll on memory when you have many dozens of thousands of ports open.
%%
%% The values to be used can be the number of octets (bytes) sent, received,
%% or both (`send_oct', `recv_oct', `oct', respectively), or the number
%% of packets sent, received, or both (`send_cnt', `recv_cnt', `cnt',
%% respectively). Individual absolute values for each metric will be returned
%% in the 3rd position of the resulting tuple.
-spec inet_window(AttributeName, Num, Milliseconds) -> [inet_attrs()] when
AttributeName :: 'recv_cnt' | 'recv_oct' | 'send_cnt' | 'send_oct'
| 'cnt' | 'oct',
Num :: non_neg_integer(),
Milliseconds :: pos_integer().
inet_window(Attr, Num, Time) when is_atom(Attr) ->
Sample = fun() -> recon_lib:inet_attrs(Attr) end,
{First, Last} = recon_lib:sample(Time, Sample),
recon_lib:sublist_top_n_attrs(recon_lib:sliding_window(First, Last), Num).
%% @doc Allows to be similar to `erlang:port_info/1', but allows
%% more flexible port usage: usual ports, ports that were registered
%% locally (an atom), ports represented as strings (`"#Port<0.2013>"'),
%% or through an index lookup (`2013', for the same result as
%% `"#Port<0.2013>"').
%%
%% Moreover, the function will try to fetch implementation-specific
%% details based on the port type (only inet ports have this feature
%% so far). For example, TCP ports will include information about the
%% remote peer, transfer statistics, and socket options being used.
%%
%% The information-specific and the basic port info are sorted and
%% categorized in broader categories ({@link port_info_type()}).
-spec port_info(port_term()) -> [{port_info_type(),
[{port_info_key(), term()}]}, ...].
port_info(PortTerm) ->
Port = recon_lib:term_to_port(PortTerm),
[port_info(Port, Type) || Type <- [meta, signals, io, memory_used,
specific]].
%% @doc Allows to be similar to `erlang:port_info/2', but allows
%% more flexible port usage: usual ports, ports that were registered
%% locally (an atom), ports represented as strings (`"#Port<0.2013>"'),
%% or through an index lookup (`2013', for the same result as
%% `"#Port<0.2013>"').
%%
%% Moreover, the function allows to to fetch information by category
%% as defined in {@link port_info_type()}, and although the type signature
%% doesn't show it in the generated documentation, individual items
%% accepted by `erlang:port_info/2' are accepted, and lists of them too.
-spec port_info(port_term(), port_info_type()) -> {port_info_type(),
[{port_info_key(), _}]}
; (port_term(), [atom()]) -> [{atom(), term()}]
; (port_term(), atom()) -> {atom(), term()}.
port_info(PortTerm, meta) ->
{meta, List} = port_info_type(PortTerm, meta, [id, name, os_pid]),
case port_info(PortTerm, registered_name) of
[] -> {meta, List};
Name -> {meta, [Name | List]}
end;
port_info(PortTerm, signals) ->
port_info_type(PortTerm, signals, [connected, links, monitors]);
port_info(PortTerm, io) ->
port_info_type(PortTerm, io, [input, output]);
port_info(PortTerm, memory_used) ->
port_info_type(PortTerm, memory_used, [memory, queue_size]);
port_info(PortTerm, specific) ->
Port = recon_lib:term_to_port(PortTerm),
Props = case erlang:port_info(Port, name) of
{_, Type} when Type =:= "udp_inet";
Type =:= "tcp_inet";
Type =:= "sctp_inet" ->
case inet:getstat(Port) of
{ok, Stats} -> [{statistics, Stats}];
_ -> []
end ++
case inet:peername(Port) of
{ok, Peer} -> [{peername, Peer}];
{error, _} -> []
end ++
case inet:sockname(Port) of
{ok, Local} -> [{sockname, Local}];
{error, _} -> []
end ++
case inet:getopts(Port, [active, broadcast, buffer, delay_send,
dontroute, exit_on_close, header,
high_watermark, ipv6_v6only, keepalive,
linger, low_watermark, mode, nodelay,
packet, packet_size, priority,
read_packets, recbuf, reuseaddr,
send_timeout, sndbuf]) of
{ok, Opts} -> [{options, Opts}];
{error, _} -> []
end;
{_, "efile"} ->
%% would be nice to support file-specific info, but things
%% are too vague with the file_server and how it works in
%% order to make this work efficiently
[];
_ ->
[]
end,
{type, Props};
port_info(PortTerm, Keys) when is_list(Keys) ->
Port = recon_lib:term_to_port(PortTerm),
[erlang:port_info(Port, Key) || Key <- Keys];
port_info(PortTerm, Key) when is_atom(Key) ->
erlang:port_info(recon_lib:term_to_port(PortTerm), Key).
%% @private makes access to `port_info_type()' calls simpler.
%-spec port_info_type(pid_term(), port_info_type(), [port_info_key()]) ->
% {port_info_type(), [{port_info_key(), term()}]}.
port_info_type(PortTerm, Type, Keys) ->
Port = recon_lib:term_to_port(PortTerm),
{Type, [erlang:port_info(Port, Key) || Key <- Keys]}.
%%% RPC Utils %%%
%% @doc Shorthand for `rpc([node()|nodes()], Fun)'.
-spec rpc(fun(() -> term())) -> {[Success :: _], [Fail :: _]}.
rpc(Fun) ->
rpc([node() | nodes()], Fun).
%% @doc Shorthand for `rpc(Nodes, Fun, infinity)'.
-spec rpc(node()|[node(), ...], fun(() -> term())) -> {[Success :: _], [Fail :: _]}.
rpc(Nodes, Fun) ->
rpc(Nodes, Fun, infinity).
%% @doc Runs an arbitrary fun (of arity 0) over one or more nodes.
-spec rpc(node()|[node(), ...], fun(() -> term()), timeout()) -> {[Success :: _], [Fail :: _]}.
rpc(Nodes = [_ | _], Fun, Timeout) when is_function(Fun, 0) ->
rpc:multicall(Nodes, erlang, apply, [Fun, []], Timeout);
rpc(Node, Fun, Timeout) when is_atom(Node) ->
rpc([Node], Fun, Timeout).
%% @doc Shorthand for `named_rpc([node()|nodes()], Fun)'.
-spec named_rpc(fun(() -> term())) -> {[Success :: _], [Fail :: _]}.
named_rpc(Fun) ->
named_rpc([node() | nodes()], Fun).
%% @doc Shorthand for `named_rpc(Nodes, Fun, infinity)'.
-spec named_rpc(node()|[node(), ...], fun(() -> term())) -> {[Success :: _], [Fail :: _]}.
named_rpc(Nodes, Fun) ->
named_rpc(Nodes, Fun, infinity).
%% @doc Runs an arbitrary fun (of arity 0) over one or more nodes, and returns the
%% name of the node that computed a given result along with it, in a tuple.
-spec named_rpc(node()|[node(), ...], fun(() -> term()), timeout()) -> {[Success :: _], [Fail :: _]}.
named_rpc(Nodes = [_ | _], Fun, Timeout) when is_function(Fun, 0) ->
rpc:multicall(Nodes, erlang, apply, [fun() -> {node(), Fun()} end, []], Timeout);
named_rpc(Node, Fun, Timeout) when is_atom(Node) ->
named_rpc([Node], Fun, Timeout).

+ 726
- 0
src/srvNodeMgr/tools_cq/recon/recon_alloc.erl Dosyayı Görüntüle

@ -0,0 +1,726 @@
%%% @author Fred Hebert <mononcqc@ferd.ca>
%%% [http://ferd.ca/]
%%% @author Lukas Larsson <lukas@erlang.org>
%%% @doc Functions to deal with
%%% <a href="http://www.erlang.org/doc/man/erts_alloc.html">Erlang's memory
%%% allocators</a>, or particularly, to try to present the allocator data
%%% in a way that makes it simpler to discover possible problems.
%%%
%%% Tweaking Erlang memory allocators and their behaviour is a very tricky
%%% ordeal whenever you have to give up the default settings. This module
%%% (and its documentation) will try and provide helpful pointers to help
%%% in this task.
%%%
%%% This module should mostly be helpful to figure out <em>if</em> there is
%%% a problem, but will offer little help to figure out <em>what</em> is wrong.
%%%
%%% To figure this out, you need to dig deeper into the allocator data
%%% (obtainable with {@link allocators/0}), and/or have some precise knowledge
%%% about the type of load and work done by the VM to be able to assess what
%%% each reaction to individual tweak should be.
%%%
%%% A lot of trial and error might be required to figure out if tweaks have
%%% helped or not, ultimately.
%%%
%%% In order to help do offline debugging of memory allocator problems
%%% recon_alloc also has a few functions that store snapshots of the
%%% memory statistics.
%%% These snapshots can be used to freeze the current allocation values so that
%%% they do not change during analysis while using the regular functionality of
%%% this module, so that the allocator values can be saved, or that
%%% they can be shared, dumped, and reloaded for further analysis using files.
%%% See {@link snapshot_load/1} for a simple use-case.
%%%
%%% Glossary:
%%% <dl>
%%% <dt>sys_alloc</dt>
%%% <dd>System allocator, usually just malloc</dd>
%%%
%%% <dt>mseg_alloc</dt>
%%% <dd>Used by other allocators, can do mmap. Caches allocations</dd>
%%%
%%% <dt>temp_alloc</dt>
%%% <dd>Used for temporary allocations</dd>
%%%
%%% <dt>eheap_alloc</dt>
%%% <dd>Heap data (i.e. process heaps) allocator</dd>
%%%
%%% <dt>binary_alloc</dt>
%%% <dd>Global binary heap allocator</dd>
%%%
%%% <dt>ets_alloc</dt>
%%% <dd>ETS data allocator</dd>
%%%
%%% <dt>driver_alloc</dt>
%%% <dd>Driver data allocator</dd>
%%%
%%% <dt>sl_alloc</dt>
%%% <dd>Short-lived memory blocks allocator</dd>
%%%
%%% <dt>ll_alloc</dt>
%%% <dd>Long-lived data (i.e. Erlang code itself) allocator</dd>
%%%
%%% <dt>fix_alloc</dt>
%%% <dd>Frequently used fixed-size data allocator</dd>
%%%
%%% <dt>std_alloc</dt>
%%% <dd>Allocator for other memory blocks</dd>
%%%
%%% <dt>carrier</dt>
%%% <dd>When a given area of memory is allocated by the OS to the
%%% VM (through sys_alloc or mseg_alloc), it is put into a 'carrier'. There
%%% are two kinds of carriers: multiblock and single block. The default
%%% carriers data is sent to are multiblock carriers, owned by a specific
%%% allocator (ets_alloc, binary_alloc, etc.). The specific allocator can
%%% thus do allocation for specific Erlang requirements within bits of
%%% memory that has been preallocated before. This allows more reuse,
%%% and we can even measure the cache hit rates {@link cache_hit_rates/0}.
%%%
%%% There is however a threshold above which an item in memory won't fit
%%% a multiblock carrier. When that happens, the specific allocator does
%%% a special allocation to a single block carrier. This is done by the
%%% allocator basically asking for space directly from sys_alloc or
%%% mseg_alloc rather than a previously multiblock area already obtained
%%% before.
%%%
%%% This leads to various allocation strategies where you decide to
%%% choose:
%%% <ol>
%%% <li>which multiblock carrier you're going to (if at all)</li>
%%% <li>which block in that carrier you're going to</li>
%%% </ol>
%%%
%%% See <a href="http://www.erlang.org/doc/man/erts_alloc.html">the official
%%% documentation on erts_alloc</a> for more details.
%%% </dd>
%%%
%%% <dt>mbcs</dt>
%%% <dd>Multiblock carriers.</dd>
%%%
%%% <dt>sbcs</dt>
%%% <dd>Single block carriers.</dd>
%%%
%%% <dt>lmbcs</dt>
%%% <dd>Largest multiblock carrier size</dd>
%%%
%%% <dt>smbcs</dt>
%%% <dd>Smallest multiblock carrier size</dd>
%%%
%%% <dt>sbct</dt>
%%% <dd>Single block carrier threshold</dd>
%%% </dl>
%%%
%%% By default all sizes returned by this module are in bytes. You can change
%%% this by calling {@link set_unit/1}.
%%%
-module(recon_alloc).
-define(UTIL_ALLOCATORS, [temp_alloc,
eheap_alloc,
binary_alloc,
ets_alloc,
driver_alloc,
sl_alloc,
ll_alloc,
fix_alloc,
std_alloc
]).
-type allocator() :: temp_alloc | eheap_alloc | binary_alloc | ets_alloc
| driver_alloc | sl_alloc | ll_alloc | fix_alloc
| std_alloc.
-type instance() :: non_neg_integer().
-type allocdata(T) :: {{allocator(), instance()}, T}.
-type allocdata_types(T) :: {{allocator(), [instance()]}, T}.
-export_type([allocator/0, instance/0, allocdata/1]).
-define(CURRENT_POS, 2). % pos in sizes tuples for current value
-define(MAX_POS, 4). % pos in sizes tuples for max value
-export([memory/1, memory/2, fragmentation/1, cache_hit_rates/0,
average_block_sizes/1, sbcs_to_mbcs/1, allocators/0,
allocators/1]).
%% Snapshot handling
-type memory() :: [{atom(), atom()}].
-type snapshot() :: {memory(), [allocdata(term())]}.
-export_type([memory/0, snapshot/0]).
-export([snapshot/0, snapshot_clear/0,
snapshot_print/0, snapshot_get/0,
snapshot_save/1, snapshot_load/1]).
%% Unit handling
-export([set_unit/1]).
%%%%%%%%%%%%%%
%%% Public %%%
%%%%%%%%%%%%%%
%% @doc Equivalent to `memory(Key, current)'.
-spec memory(used | allocated | unused) -> pos_integer()
; (usage) -> number()
; (allocated_types | allocated_instances) ->
[{allocator(), pos_integer()}].
memory(Key) -> memory(Key, current).
%% @doc reports one of multiple possible memory values for the entire
%% node depending on what is to be reported:
%%
%% <ul>
%% <li>`used' reports the memory that is actively used for allocated
%% Erlang data;</li>
%% <li>`allocated' reports the memory that is reserved by the VM. It
%% includes the memory used, but also the memory yet-to-be-used but still
%% given by the OS. This is the amount you want if you're dealing with
%% ulimit and OS-reported values. </li>
%% <li>`allocated_types' report the memory that is reserved by the
%% VM grouped into the different util allocators.</li>
%% <li>`allocated_instances' report the memory that is reserved
%% by the VM grouped into the different schedulers. Note that
%% instance id 0 is the global allocator used to allocate data from
%% non-managed threads, i.e. async and driver threads.</li>
%% <li>`unused' reports the amount of memory reserved by the VM that
%% is not being allocated.
%% Equivalent to `allocated - used'.</li>
%% <li>`usage' returns a percentage (0.0 .. 1.0) of `used/allocated'
%% memory ratios.</li>
%% </ul>
%%
%% The memory reported by `allocated' should roughly
%% match what the OS reports. If this amount is different by a large margin,
%% it may be the sign that someone is allocating memory in C directly, outside
%% of Erlang's own allocator -- a big warning sign. There are currently
%% three sources of memory alloction that are not counted towards this value:
%% The cached segments in the mseg allocator, any memory allocated as a
%% super carrier, and small pieces of memory allocated during startup
%% before the memory allocators are initialized.
%%
%% Also note that low memory usages can be the sign of fragmentation in
%% memory, in which case exploring which specific allocator is at fault
%% is recommended (see {@link fragmentation/1})
-spec memory(used | allocated | unused, current | max) -> pos_integer()
; (usage, current | max) -> number()
; (allocated_types|allocated_instances, current | max) ->
[{allocator(), pos_integer()}].
memory(used, Keyword) ->
lists:sum(lists:map(fun({_, Prop}) ->
container_size(Prop, Keyword, blocks_size)
end, util_alloc()));
memory(allocated, Keyword) ->
lists:sum(lists:map(fun({_, Prop}) ->
container_size(Prop, Keyword, carriers_size)
end, util_alloc()));
memory(allocated_types, Keyword) ->
lists:foldl(fun({{Alloc, _N}, Props}, Acc) ->
CZ = container_size(Props, Keyword, carriers_size),
orddict:update_counter(Alloc, CZ, Acc)
end, orddict:new(), util_alloc());
memory(allocated_instances, Keyword) ->
lists:foldl(fun({{_Alloc, N}, Props}, Acc) ->
CZ = container_size(Props, Keyword, carriers_size),
orddict:update_counter(N, CZ, Acc)
end, orddict:new(), util_alloc());
memory(unused, Keyword) ->
memory(allocated, Keyword) - memory(used, Keyword);
memory(usage, Keyword) ->
memory(used, Keyword) / memory(allocated, Keyword).
%% @doc Compares the block sizes to the carrier sizes, both for
%% single block (`sbcs') and multiblock (`mbcs') carriers.
%%
%% The returned results are sorted by a weight system that is
%% somewhat likely to return the most fragmented allocators first,
%% based on their percentage of use and the total size of the carriers,
%% for both `sbcs' and `mbcs'.
%%
%% The values can both be returned for `current' allocator values, and
%% for `max' allocator values. The current values hold the present allocation
%% numbers, and max values, the values at the peak. Comparing both together
%% can give an idea of whether the node is currently being at its memory peak
%% when possibly leaky, or if it isn't. This information can in turn
%% influence the tuning of allocators to better fit sizes of blocks and/or
%% carriers.
-spec fragmentation(current | max) -> [allocdata([{atom(), term()}])].
fragmentation(Keyword) ->
WeighedData = [begin
BlockSbcs = container_value(Props, Keyword, sbcs, blocks_size),
CarSbcs = container_value(Props, Keyword, sbcs, carriers_size),
BlockMbcs = container_value(Props, Keyword, mbcs, blocks_size),
CarMbcs = container_value(Props, Keyword, mbcs, carriers_size),
{Weight, Vals} = weighed_values({BlockSbcs, CarSbcs},
{BlockMbcs, CarMbcs}),
{Weight, {Allocator, N}, Vals}
end || {{Allocator, N}, Props} <- util_alloc()],
[{Key, Val} || {_W, Key, Val} <- lists:reverse(lists:sort(WeighedData))].
%% @doc looks at the `mseg_alloc' allocator (allocator used by all the
%% allocators in {@link allocator()}) and returns information relative to
%% the cache hit rates. Unless memory has expected spiky behaviour, it should
%% usually be above 0.80 (80%).
%%
%% Cache can be tweaked using three VM flags: `+MMmcs', `+MMrmcbf', and
%% `+MMamcbf'.
%%
%% `+MMmcs' stands for the maximum amount of cached memory segments. Its
%% default value is '10' and can be anything from 0 to 30. Increasing
%% it first and verifying if cache hits get better should be the first
%% step taken.
%%
%% The two other options specify what are the maximal values of a segment
%% to cache, in relative (in percent) and absolute terms (in kilobytes),
%% respectively. Increasing these may allow more segments to be cached, but
%% should also add overheads to memory allocation. An Erlang node that has
%% limited memory and increases these values may make things worse on
%% that point.
%%
%% The values returned by this function are sorted by a weight combining
%% the lower cache hit joined to the largest memory values allocated.
-spec cache_hit_rates() -> [{{instance, instance()}, [{Key, Val}]}] when
Key :: hit_rate | hits | calls,
Val :: term().
cache_hit_rates() ->
WeighedData = [begin
Mem = proplists:get_value(memkind, Props),
{_, Hits} = lists:keyfind(cache_hits, 1, proplists:get_value(status, Mem)),
{_, Giga, Ones} = lists:keyfind(mseg_alloc, 1, proplists:get_value(calls, Mem)),
Calls = 1000000000 * Giga + Ones,
HitRate = usage(Hits, Calls),
Weight = (1.00 - HitRate) * Calls,
{Weight, {instance, N}, [{hit_rate, HitRate}, {hits, Hits}, {calls, Calls}]}
end || {{_, N}, Props} <- alloc([mseg_alloc])],
[{Key, Val} || {_W, Key, Val} <- lists:reverse(lists:sort(WeighedData))].
%% @doc Checks all allocators in {@link allocator()} and returns the average
%% block sizes being used for `mbcs' and `sbcs'. This value is interesting
%% to use because it will tell us how large most blocks are.
%% This can be related to the VM's largest multiblock carrier size
%% (`lmbcs') and smallest multiblock carrier size (`smbcs') to specify
%% allocation strategies regarding the carrier sizes to be used.
%%
%% This function isn't exceptionally useful unless you know you have some
%% specific problem, say with sbcs/mbcs ratios (see {@link sbcs_to_mbcs/0})
%% or fragmentation for a specific allocator, and want to figure out what
%% values to pick to increase or decrease sizes compared to the currently
%% configured value.
%%
%% Do note that values for `lmbcs' and `smbcs' are going to be rounded up
%% to the next power of two when configuring them.
-spec average_block_sizes(current | max) -> [{allocator(), [{Key, Val}]}] when
Key :: mbcs | sbcs,
Val :: number().
average_block_sizes(Keyword) ->
Dict = lists:foldl(fun({{Instance, _}, Props}, Dict0) ->
CarSbcs = container_value(Props, Keyword, sbcs, blocks),
SizeSbcs = container_value(Props, Keyword, sbcs, blocks_size),
CarMbcs = container_value(Props, Keyword, mbcs, blocks),
SizeMbcs = container_value(Props, Keyword, mbcs, blocks_size),
Dict1 = dict:update_counter({Instance, sbcs, count}, CarSbcs, Dict0),
Dict2 = dict:update_counter({Instance, sbcs, size}, SizeSbcs, Dict1),
Dict3 = dict:update_counter({Instance, mbcs, count}, CarMbcs, Dict2),
Dict4 = dict:update_counter({Instance, mbcs, size}, SizeMbcs, Dict3),
Dict4
end,
dict:new(),
util_alloc()),
average_group(average_calc(lists:sort(dict:to_list(Dict)))).
%% @doc compares the amount of single block carriers (`sbcs') vs the
%% number of multiblock carriers (`mbcs') for each individual allocator in
%% {@link allocator()}.
%%
%% When a specific piece of data is allocated, it is compared to a threshold,
%% called the 'single block carrier threshold' (`sbct'). When the data is
%% larger than the `sbct', it gets sent to a single block carrier. When the
%% data is smaller than the `sbct', it gets placed into a multiblock carrier.
%%
%% mbcs are to be prefered to sbcs because they basically represent pre-
%% allocated memory, whereas sbcs will map to one call to sys_alloc
%% or mseg_alloc, which is more expensive than redistributing
%% data that was obtained for multiblock carriers. Moreover, the VM is able to
%% do specific work with mbcs that should help reduce fragmentation in ways
%% sys_alloc or mmap usually won't.
%%
%% Ideally, most of the data should fit inside multiblock carriers. If
%% most of the data ends up in `sbcs', you may need to adjust the multiblock
%% carrier sizes, specifically the maximal value (`lmbcs') and the threshold
%% (`sbct'). On 32 bit VMs, `sbct' is limited to 8MBs, but 64 bit VMs can go
%% to pretty much any practical size.
%%
%% Given the value returned is a ratio of sbcs/mbcs, the higher the value,
%% the worst the condition. The list is sorted accordingly.
-spec sbcs_to_mbcs(max | current) -> [allocdata(term())].
sbcs_to_mbcs(Keyword) ->
WeightedList = [begin
Sbcs = container_value(Props, Keyword, sbcs, blocks),
Mbcs = container_value(Props, Keyword, mbcs, blocks),
Ratio = case {Sbcs, Mbcs} of
{0, 0} -> 0;
{_, 0} -> infinity; % that is bad!
{_, _} -> Sbcs / Mbcs
end,
{Ratio, {Allocator, N}}
end || {{Allocator, N}, Props} <- util_alloc()],
[{Alloc, Ratio} || {Ratio, Alloc} <- lists:reverse(lists:sort(WeightedList))].
%% @doc returns a dump of all allocator settings and values
-spec allocators() -> [allocdata(term())].
allocators() ->
UtilAllocators = erlang:system_info(alloc_util_allocators),
Allocators = [sys_alloc, mseg_alloc | UtilAllocators],
%% versions is deleted in order to allow the use of the orddict api,
%% and never really having come across a case where it was useful to know.
[{{A, N}, lists:sort(proplists:delete(versions, Props))} ||
A <- Allocators,
Allocs <- [erlang:system_info({allocator, A})],
Allocs =/= false,
{_, N, Props} <- Allocs].
%% @doc returns a dump of all allocator settings and values modified
%% depending on the argument.
%% <ul>
%% <li>`types` report the settings and accumulated values for each
%% allocator type. This is useful when looking for anomalies
%% in the system as a whole and not specific instances.</li>
%% </ul>
-spec allocators(types) -> [allocdata_types(term())].
allocators(types) ->
allocators_types(alloc(), []).
allocators_types([{{Type, No}, Vs} | T], As) ->
case lists:keytake(Type, 1, As) of
false ->
allocators_types(T, [{Type, [No], sort_values(Type, Vs)} | As]);
{value, {Type, Nos, OVs}, NAs} ->
MergedValues = merge_values(sort_values(Type, Vs), OVs),
allocators_types(T, [{Type, [No | Nos], MergedValues} | NAs])
end;
allocators_types([], As) ->
[{{Type, Nos}, Vs} || {Type, Nos, Vs} <- As].
merge_values([{Key, Vs} | T1], [{Key, OVs} | T2]) when Key =:= memkind ->
[{Key, merge_values(Vs, OVs)} | merge_values(T1, T2)];
merge_values([{Key, Vs} | T1], [{Key, OVs} | T2]) when Key =:= calls;
Key =:= fix_types;
Key =:= sbmbcs;
Key =:= mbcs;
Key =:= mbcs_pool;
Key =:= sbcs;
Key =:= status ->
[{Key, lists:map(
fun({{K, MV1, V1}, {K, MV2, V2}}) ->
%% Merge the MegaVs + Vs into one
V = MV1 * 1000000 + V1 + MV2 * 1000000 + V2,
{K, V div 1000000, V rem 1000000};
({{K, V1}, {K, V2}}) when K =:= segments_watermark ->
%% We take the maximum watermark as that is
%% a value that we can use somewhat. Ideally
%% maybe the average should be used, but the
%% value is very rarely important so leave it
%% like this for now.
{K, lists:max([V1, V2])};
({{K, V1}, {K, V2}}) ->
{K, V1 + V2};
({{K, C1, L1, M1}, {K, C2, L2, M2}}) ->
%% Merge the Curr, Last, Max into one
{K, C1 + C2, L1 + L2, M1 + M2}
end, lists:zip(Vs, OVs))} | merge_values(T1, T2)];
merge_values([{Type, _Vs} = E | T1], T2) when Type =:= mbcs_pool ->
%% For values never showing up in instance 0 but in all other
[E | merge_values(T1, T2)];
merge_values(T1, [{Type, _Vs} = E | T2]) when Type =:= fix_types ->
%% For values only showing up in instance 0
[E | merge_values(T1, T2)];
merge_values([E | T1], [E | T2]) ->
%% For values that are constant
[E | merge_values(T1, T2)];
merge_values([{options, _Vs1} | T1], [{options, _Vs2} = E | T2]) ->
%% Options change a but in between instance 0 and the other,
%% We show the others as they are the most interesting.
[E | merge_values(T1, T2)];
merge_values([], []) ->
[].
sort_values(mseg_alloc, Vs) ->
{value, {memkind, MemKindVs}, OVs} = lists:keytake(memkind, 1, Vs),
lists:sort([{memkind, lists:sort(MemKindVs)} | OVs]);
sort_values(_Type, Vs) ->
lists:sort(Vs).
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Snapshot handling %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
%% @doc Take a new snapshot of the current memory allocator statistics.
%% The snapshot is stored in the process dictionary of the calling process,
%% with all the limitations that it implies (i.e. no garbage-collection).
%% To unsert the snapshot, see {@link snapshot_clear/1}.
-spec snapshot() -> snapshot() | undefined.
snapshot() ->
put(recon_alloc_snapshot, snapshot_int()).
%% @doc clear the current snapshot in the process dictionary, if present,
%% and return the value it had before being unset.
%% @end
%% Maybe we should use erlang:delete(Key) here instead?
-spec snapshot_clear() -> snapshot() | undefined.
snapshot_clear() ->
put(recon_alloc_snapshot, undefined).
%% @doc print a dump of the current snapshot stored by {@link snapshot/0}
%% Prints `undefined' if no snapshot has been taken.
-spec snapshot_print() -> ok.
snapshot_print() ->
io:format("~p.~n", [snapshot_get()]).
%% @doc returns the current snapshot stored by {@link snapshot/0}.
%% Returns `undefined' if no snapshot has been taken.
-spec snapshot_get() -> snapshot() | undefined.
snapshot_get() ->
get(recon_alloc_snapshot).
%% @doc save the current snapshot taken by {@link snapshot/0} to a file.
%% If there is no current snapshot, a snaphot of the current allocator
%% statistics will be written to the file.
-spec snapshot_save(Filename) -> ok when
Filename :: file:name().
snapshot_save(Filename) ->
Snapshot = case snapshot_get() of
undefined ->
snapshot_int();
Snap ->
Snap
end,
case file:write_file(Filename, io_lib:format("~p.~n", [Snapshot])) of
ok -> ok;
{error, Reason} ->
erlang:error(Reason, [Filename])
end.
%% @doc load a snapshot from a given file. The format of the data in the
%% file can be either the same as output by {@link snapshot_save()},
%% or the output obtained by calling
%% `{erlang:memory(),[{A,erlang:system_info({allocator,A})} || A <- erlang:system_info(alloc_util_allocators)++[sys_alloc,mseg_alloc]]}.'
%% and storing it in a file.
%% If the latter option is taken, please remember to add a full stop at the end
%% of the resulting Erlang term, as this function uses `file:consult/1' to load
%% the file.
%%
%% Example usage:
%%
%%```On target machine:
%% 1> recon_alloc:snapshot().
%% undefined
%% 2> recon_alloc:memory(used).
%% 18411064
%% 3> recon_alloc:snapshot_save("recon_snapshot.terms").
%% ok
%%
%% On other machine:
%% 1> recon_alloc:snapshot_load("recon_snapshot.terms").
%% undefined
%% 2> recon_alloc:memory(used).
%% 18411064'''
%%
-spec snapshot_load(Filename) -> snapshot() | undefined when
Filename :: file:name().
snapshot_load(Filename) ->
{ok, [Terms]} = file:consult(Filename),
Snapshot =
case Terms of
%% We handle someone using
%% {erlang:memory(),
%% [{A,erlang:system_info({allocator,A})} ||
%% A <- erlang:system_info(alloc_util_allocators)++[sys_alloc,mseg_alloc]]}
%% to dump data.
{M, [{Alloc, _D} | _] = Allocs} when is_atom(Alloc) ->
{M, [{{A, N}, lists:sort(proplists:delete(versions, Props))} ||
{A, Instances = [_ | _]} <- Allocs,
{_, N, Props} <- Instances]};
%% We assume someone used recon_alloc:snapshot() to store this one
{M, Allocs} ->
{M, [{AN, lists:sort(proplists:delete(versions, Props))} ||
{AN, Props} <- Allocs]}
end,
put(recon_alloc_snapshot, Snapshot).
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Handling of units %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
%% @doc set the current unit to be used by recon_alloc. This effects all
%% functions that return bytes.
%%
%% Eg.
%% ```1> recon_alloc:memory(used,current).
%% 17548752
%% 2> recon_alloc:set_unit(kilobyte).
%% undefined
%% 3> recon_alloc:memory(used,current).
%% 17576.90625'''
%%
-spec set_unit(byte | kilobyte | megabyte | gigabyte) -> ok.
set_unit(byte) ->
put(recon_alloc_unit, undefined);
set_unit(kilobyte) ->
put(recon_alloc_unit, 1024);
set_unit(megabyte) ->
put(recon_alloc_unit, 1024 * 1024);
set_unit(gigabyte) ->
put(recon_alloc_unit, 1024 * 1024 * 1024).
conv({Mem, Allocs} = D) ->
case get(recon_alloc_unit) of
undefined ->
D;
Factor ->
{conv_mem(Mem, Factor), conv_alloc(Allocs, Factor)}
end.
conv_mem(Mem, Factor) ->
[{T, M / Factor} || {T, M} <- Mem].
conv_alloc([{{sys_alloc, _I}, _Props} = Alloc | R], Factor) ->
[Alloc | conv_alloc(R, Factor)];
conv_alloc([{{mseg_alloc, _I} = AI, Props} | R], Factor) ->
MemKind = orddict:fetch(memkind, Props),
Status = orddict:fetch(status, MemKind),
{segments_size, Curr, Last, Max} = lists:keyfind(segments_size, 1, Status),
NewSegSize = {segments_size, Curr / Factor, Last / Factor, Max / Factor},
NewStatus = lists:keyreplace(segments_size, 1, Status, NewSegSize),
NewProps = orddict:store(memkind, orddict:store(status, NewStatus, MemKind),
Props),
[{AI, NewProps} | conv_alloc(R, Factor)];
conv_alloc([{AI, Props} | R], Factor) ->
FactorFun = fun({T, Curr}) when
T =:= blocks_size; T =:= carriers_size ->
{T, Curr / Factor};
({T, Curr, Last, Max}) when
T =:= blocks_size; T =:= carriers_size;
T =:= mseg_alloc_carriers_size;
T =:= sys_alloc_carriers_size ->
{T, Curr / Factor, Last / Factor, Max / Factor};
(T) ->
T
end,
NewMbcsProp = [FactorFun(Prop) || Prop <- orddict:fetch(mbcs, Props)],
NewSbcsProp = [FactorFun(Prop) || Prop <- orddict:fetch(sbcs, Props)],
NewProps = orddict:store(sbcs, NewSbcsProp,
orddict:store(mbcs, NewMbcsProp, Props)),
case orddict:find(mbcs_pool, Props) of
error ->
[{AI, NewProps} | conv_alloc(R, Factor)];
{ok, MbcsPoolProps} ->
NewMbcsPoolProp = [FactorFun(Prop) || Prop <- MbcsPoolProps],
NewPoolProps = orddict:store(mbcs_pool, NewMbcsPoolProp, NewProps),
[{AI, NewPoolProps} | conv_alloc(R, Factor)]
end;
conv_alloc([], _Factor) ->
[].
%%%%%%%%%%%%%%%
%%% Private %%%
%%%%%%%%%%%%%%%
%% Sort on small usage vs large size.
%% The weight cares about both the sbcs and mbcs values, and also
%% returns a proplist of possibly interesting values.
weighed_values({SbcsBlockSize, SbcsCarrierSize},
{MbcsBlockSize, MbcsCarrierSize}) ->
SbcsUsage = usage(SbcsBlockSize, SbcsCarrierSize),
MbcsUsage = usage(MbcsBlockSize, MbcsCarrierSize),
SbcsWeight = (1.00 - SbcsUsage) * SbcsCarrierSize,
MbcsWeight = (1.00 - MbcsUsage) * MbcsCarrierSize,
Weight = SbcsWeight + MbcsWeight,
{Weight, [{sbcs_usage, SbcsUsage},
{mbcs_usage, MbcsUsage},
{sbcs_block_size, SbcsBlockSize},
{sbcs_carriers_size, SbcsCarrierSize},
{mbcs_block_size, MbcsBlockSize},
{mbcs_carriers_size, MbcsCarrierSize}]}.
%% Returns the `BlockSize/CarrierSize' as a 0.0 -> 1.0 percentage,
%% but also takes 0/0 to be 100% to make working with sorting and
%% weights simpler.
usage(0, 0) -> 1.00;
usage(0.0, 0.0) -> 1.00;
%usage(N,0) -> ???;
usage(Block, Carrier) -> Block / Carrier.
%% Calculation for the average of blocks being used.
average_calc([]) ->
[];
average_calc([{{Instance, Type, count}, Ct}, {{Instance, Type, size}, Size} | Rest]) ->
case {Size, Ct} of
{_, 0} when Size == 0 -> [{Instance, Type, 0} | average_calc(Rest)];
_ -> [{Instance, Type, Size / Ct} | average_calc(Rest)]
end.
%% Regrouping/merging values together in proplists
average_group([]) -> [];
average_group([{Instance, Type1, N}, {Instance, Type2, M} | Rest]) ->
[{Instance, [{Type1, N}, {Type2, M}]} | average_group(Rest)].
%% Get the total carrier size
container_size(Props, Keyword, Container) ->
Sbcs = container_value(Props, Keyword, sbcs, Container),
Mbcs = container_value(Props, Keyword, mbcs, Container),
Sbcs + Mbcs.
container_value(Props, Keyword, Type, Container)
when is_atom(Keyword) ->
container_value(Props, key2pos(Keyword), Type, Container);
container_value(Props, Pos, mbcs = Type, Container)
when Pos == ?CURRENT_POS,
((Container =:= blocks) or (Container =:= blocks_size)
or (Container =:= carriers) or (Container =:= carriers_size)) ->
%% We include the mbcs_pool into the value for mbcs.
%% The mbcs_pool contains carriers that have been abandoned
%% by the specific allocator instance and can therefore be
%% grabbed by another instance of the same type.
%% The pool was added in R16B02 and enabled by default in 17.0.
%% See erts/emulator/internal_docs/CarrierMigration.md in
%% Erlang/OTP repo for more details.
Pool = case proplists:get_value(mbcs_pool, Props) of
PoolProps when PoolProps =/= undefined ->
element(Pos, lists:keyfind(Container, 1, PoolProps));
_ -> 0
end,
TypeProps = proplists:get_value(Type, Props),
Pool + element(Pos, lists:keyfind(Container, 1, TypeProps));
container_value(Props, Pos, Type, Container)
when Type =:= sbcs; Type =:= mbcs ->
TypeProps = proplists:get_value(Type, Props),
element(Pos, lists:keyfind(Container, 1, TypeProps)).
%% Create a new snapshot
snapshot_int() ->
{erlang:memory(), allocators()}.
%% If no snapshot has been taken/loaded then we use current values
snapshot_get_int() ->
case snapshot_get() of
undefined ->
conv(snapshot_int());
Snapshot ->
conv(Snapshot)
end.
%% Get the alloc part of a snapshot
alloc() ->
{_Mem, Allocs} = snapshot_get_int(),
Allocs.
alloc(Type) ->
[{{T, Instance}, Props} || {{T, Instance}, Props} <- alloc(),
lists:member(T, Type)].
%% Get only alloc_util allocs
util_alloc() ->
alloc(?UTIL_ALLOCATORS).
key2pos(current) ->
?CURRENT_POS;
key2pos(max) ->
?MAX_POS.

+ 278
- 0
src/srvNodeMgr/tools_cq/recon/recon_lib.erl Dosyayı Görüntüle

@ -0,0 +1,278 @@
%%% @author Fred Hebert <mononcqc@ferd.ca>
%%% [http://ferd.ca/]
%%% @doc Regroups useful functionality used by recon when dealing with data
%%% from the node. The functions in this module allow quick runtime access
%%% to fancier behaviour than what would be done using recon module itself.
%%% @end
-module(recon_lib).
-export([sliding_window/2, sample/2, count/1,
port_list/1, port_list/2,
proc_attrs/1, proc_attrs/2,
inet_attrs/1, inet_attrs/2,
triple_to_pid/3, term_to_pid/1,
term_to_port/1,
time_map/5, time_fold/6,
scheduler_usage_diff/2,
sublist_top_n_attrs/2]).
%% private exports
-export([binary_memory/1]).
-type diff() :: [recon:proc_attrs() | recon:inet_attrs()].
%% @doc Compare two samples and return a list based on some key. The type mentioned
%% for the structure is `diff()' (`{Key,Val,Other}'), which is compatible with
%% the {@link recon:proc_attrs()} type.
-spec sliding_window(First :: diff(), Last :: diff()) -> diff().
sliding_window(First, Last) ->
Dict = lists:foldl(
fun({Key, {Current, Other}}, Acc) ->
dict:update(Key,
fun({Old, _Other}) -> {Current - Old, Other} end,
{Current, Other},
Acc)
end,
dict:from_list([{K, {V, O}} || {K, V, O} <- First]),
[{K, {V, O}} || {K, V, O} <- Last]
),
[{K, V, O} || {K, {V, O}} <- dict:to_list(Dict)].
%% @doc Runs a fun once, waits `Ms', runs the fun again,
%% and returns both results.
-spec sample(Ms :: non_neg_integer(), fun(() -> term())) ->
{First :: term(), Second :: term()}.
sample(Delay, Fun) ->
First = Fun(),
timer:sleep(Delay),
Second = Fun(),
{First, Second}.
%% @doc Takes a list of terms, and counts how often each of
%% them appears in the list. The list returned is in no
%% particular order.
-spec count([term()]) -> [{term(), Count :: integer()}].
count(Terms) ->
Dict = lists:foldl(
fun(Val, Acc) -> dict:update_counter(Val, 1, Acc) end,
dict:new(),
Terms
),
dict:to_list(Dict).
%% @doc Returns a list of all the open ports in the VM, coupled with
%% one of the properties desired from `erlang:port_info/1-2'.
-spec port_list(Attr :: atom()) -> [{port(), term()}].
port_list(Attr) ->
[{Port, Val} || Port <- erlang:ports(),
{_, Val} <- [erlang:port_info(Port, Attr)]].
%% @doc Returns a list of all the open ports in the VM, but only
%% if the `Attr''s resulting value matches `Val'. `Attr' must be
%% a property accepted by `erlang:port_info/2'.
-spec port_list(Attr :: atom(), term()) -> [port()].
port_list(Attr, Val) ->
[Port || Port <- erlang:ports(),
{Attr, Val} =:= erlang:port_info(Port, Attr)].
%% @doc Returns the attributes ({@link recon:proc_attrs()}) of
%% all processes of the node, except the caller.
-spec proc_attrs(term()) -> [recon:proc_attrs()].
proc_attrs(AttrName) ->
[Attrs || Pid <- processes() -- [self()],
{ok, Attrs} <- [proc_attrs(AttrName, Pid)]].
%% @doc Returns the attributes of a given process. This form of attributes
%% is standard for most comparison functions for processes in recon.
%%
%% A special attribute is `binary_memory', which will reduce the memory used
%% by the process for binary data on the global heap.
-spec proc_attrs(term(), pid()) -> {ok, recon:proc_attrs()} | {error, term()}.
proc_attrs(binary_memory, Pid) ->
case process_info(Pid, [binary, registered_name,
current_function, initial_call]) of
[{_, Bins}, {registered_name, Name}, Init, Cur] ->
{ok, {Pid, binary_memory(Bins), [Name || is_atom(Name)] ++ [Init, Cur]}};
undefined ->
{error, undefined}
end;
proc_attrs(AttrName, Pid) ->
case process_info(Pid, [AttrName, registered_name,
current_function, initial_call]) of
[{_, Attr}, {registered_name, Name}, Init, Cur] ->
{ok, {Pid, Attr, [Name || is_atom(Name)] ++ [Init, Cur]}};
undefined ->
{error, undefined}
end.
%% @doc Returns the attributes ({@link recon:inet_attrs()}) of
%% all inet ports (UDP, SCTP, TCP) of the node.
-spec inet_attrs(term()) -> [recon:inet_attrs()].
inet_attrs(AttrName) ->
Ports = [Port || Port <- erlang:ports(),
{_, Name} <- [erlang:port_info(Port, name)],
Name =:= "tcp_inet" orelse
Name =:= "udp_inet" orelse
Name =:= "sctp_inet"],
[Attrs || Port <- Ports,
{ok, Attrs} <- [inet_attrs(AttrName, Port)]].
%% @doc Returns the attributes required for a given inet port (UDP,
%% SCTP, TCP). This form of attributes is standard for most comparison
%% functions for processes in recon.
-spec inet_attrs(AttributeName, port()) -> {ok, recon:inet_attrs()}
| {error, term()} when
AttributeName :: 'recv_cnt' | 'recv_oct' | 'send_cnt' | 'send_oct'
| 'cnt' | 'oct'.
inet_attrs(Attr, Port) ->
Attrs = case Attr of
cnt -> [recv_cnt, send_cnt];
oct -> [recv_oct, send_oct];
_ -> [Attr]
end,
case inet:getstat(Port, Attrs) of
{ok, Props} ->
ValSum = lists:foldl(fun({_, X}, Y) -> X + Y end, 0, Props),
{ok, {Port, ValSum, Props}};
{error, Reason} ->
{error, Reason}
end.
%% @doc Equivalent of `pid(X,Y,Z)' in the Erlang shell.
-spec triple_to_pid(N, N, N) -> pid() when
N :: non_neg_integer().
triple_to_pid(X, Y, Z) ->
list_to_pid("<" ++ integer_to_list(X) ++ "." ++
integer_to_list(Y) ++ "." ++
integer_to_list(Z) ++ ">").
%% @doc Transforms a given term to a pid.
-spec term_to_pid(recon:pid_term()) -> pid().
term_to_pid(Pid) when is_pid(Pid) -> Pid;
term_to_pid(Name) when is_atom(Name) -> whereis(Name);
term_to_pid(List = "<0." ++ _) -> list_to_pid(List);
term_to_pid(Binary = <<"<0.", _/binary>>) -> list_to_pid(binary_to_list(Binary));
term_to_pid({global, Name}) -> global:whereis_name(Name);
term_to_pid({via, Module, Name}) -> Module:whereis_name(Name);
term_to_pid({X, Y, Z}) when is_integer(X), is_integer(Y), is_integer(Z) ->
triple_to_pid(X, Y, Z).
%% @doc Transforms a given term to a port
-spec term_to_port(recon:port_term()) -> port().
term_to_port(Port) when is_port(Port) -> Port;
term_to_port(Name) when is_atom(Name) -> whereis(Name);
term_to_port("#Port<0." ++ Id) ->
N = list_to_integer(lists:sublist(Id, length(Id) - 1)), % drop trailing '>'
term_to_port(N);
term_to_port(N) when is_integer(N) ->
%% We rebuild the term from the int received:
%% http://www.erlang.org/doc/apps/erts/erl_ext_dist.html#id86892
Name = iolist_to_binary(atom_to_list(node())),
NameLen = iolist_size(Name),
Vsn = binary:last(term_to_binary(self())),
Bin = <<131, % term encoding value
102, % port tag
100, % atom ext tag, used for node name
NameLen:2/unit:8,
Name:NameLen/binary,
N:4/unit:8, % actual counter value
Vsn:8>>, % version
binary_to_term(Bin).
%% @doc Calls a given function every `Interval' milliseconds and supports
%% a map-like interface (each result is modified and returned)
-spec time_map(N, Interval, Fun, State, MapFun) -> [term()] when
N :: non_neg_integer(),
Interval :: pos_integer(),
Fun :: fun((State) -> {term(), State}),
State :: term(),
MapFun :: fun((_) -> term()).
time_map(0, _, _, _, _) ->
[];
time_map(N, Interval, Fun, State, MapFun) ->
{Res, NewState} = Fun(State),
timer:sleep(Interval),
[MapFun(Res) | time_map(N - 1, Interval, Fun, NewState, MapFun)].
%% @doc Calls a given function every `Interval' milliseconds and supports
%% a fold-like interface (each result is modified and accumulated)
-spec time_fold(N, Interval, Fun, State, FoldFun, Init) -> [term()] when
N :: non_neg_integer(),
Interval :: pos_integer(),
Fun :: fun((State) -> {term(), State}),
State :: term(),
FoldFun :: fun((term(), Init) -> Init),
Init :: term().
time_fold(0, _, _, _, _, Acc) ->
Acc;
time_fold(N, Interval, Fun, State, FoldFun, Init) ->
{Res, NewState} = Fun(State),
timer:sleep(Interval),
Acc = FoldFun(Res, Init),
time_fold(N - 1, Interval, Fun, NewState, FoldFun, Acc).
%% @doc Diffs two runs of erlang:statistics(scheduler_wall_time) and
%% returns usage metrics in terms of cores and 0..1 percentages.
-spec scheduler_usage_diff(SchedTime, SchedTime) -> [{SchedulerId, Usage}] when
SchedTime :: [{SchedulerId, ActiveTime, TotalTime}],
SchedulerId :: pos_integer(),
Usage :: number(),
ActiveTime :: non_neg_integer(),
TotalTime :: non_neg_integer().
scheduler_usage_diff(First, Last) ->
lists:map(
fun({{I, _A0, T}, {I, _A1, T}}) -> {I, 0.0}; % Avoid divide by zero
({{I, A0, T0}, {I, A1, T1}}) -> {I, (A1 - A0) / (T1 - T0)}
end,
lists:zip(lists:sort(First), lists:sort(Last))
).
%% @doc Returns the top n element of a list of process or inet attributes
-spec sublist_top_n_attrs([Attrs], pos_integer()) -> [Attrs]
when Attrs :: recon:proc_attrs() | recon:inet_attrs().
sublist_top_n_attrs(_, 0) ->
%% matching lists:sublist/2 behaviour
[];
sublist_top_n_attrs(List, Len) ->
pheap_fill(List, Len, []).
%% @private crush binaries from process_info into their amount of place
%% taken in memory.
binary_memory(Bins) ->
lists:foldl(fun({_, Mem, _}, Tot) -> Mem + Tot end, 0, Bins).
%%%%%%%%%%%%%%%
%%% PRIVATE %%%
%%%%%%%%%%%%%%%
pheap_fill(List, 0, Heap) ->
pheap_full(List, Heap);
pheap_fill([], _, Heap) ->
pheap_to_list(Heap, []);
pheap_fill([{Y, X, _} = H | T], N, Heap) ->
pheap_fill(T, N - 1, insert({{X, Y}, H}, Heap)).
pheap_full([], Heap) ->
pheap_to_list(Heap, []);
pheap_full([{Y, X, _} = H | T], [{K, _} | HeapT] = Heap) ->
case {X, Y} of
N when N > K ->
pheap_full(T, insert({N, H}, merge_pairs(HeapT)));
_ ->
pheap_full(T, Heap)
end.
pheap_to_list([], Acc) -> Acc;
pheap_to_list([{_, H} | T], Acc) ->
pheap_to_list(merge_pairs(T), [H | Acc]).
-compile({inline, [insert/2, merge/2]}).
insert(E, []) -> [E]; %% merge([E], H)
insert(E, [E2 | _] = H) when E =< E2 -> [E, H];
insert(E, [E2 | H]) -> [E2, [E] | H].
merge(H1, []) -> H1;
merge([E1 | H1], [E2 | _] = H2) when E1 =< E2 -> [E1, H2 | H1];
merge(H1, [E2 | H2]) -> [E2, H1 | H2].
merge_pairs([]) -> [];
merge_pairs([H]) -> H;
merge_pairs([A, B | T]) -> merge(merge(A, B), merge_pairs(T)).

+ 644
- 0
src/srvNodeMgr/tools_cq/recon/recon_trace.erl Dosyayı Görüntüle

@ -0,0 +1,644 @@
%%% @author Fred Hebert <mononcqc@ferd.ca>
%%% [http://ferd.ca/]
%%% @doc
%%% `recon_trace' is a module that handles tracing in a safe manner for single
%%% Erlang nodes, currently for function calls only. Functionality includes:
%%%
%%% <ul>
%%% <li>Nicer to use interface (arguably) than `dbg' or trace BIFs.</li>
%%% <li>Protection against dumb decisions (matching all calls on a node
%%% being traced, for example)</li>
%%% <li>Adding safe guards in terms of absolute trace count or
%%% rate-limitting</li>
%%% <li>Nicer formatting than default traces</li>
%%% </ul>
%%%
%%% == Tracing Erlang Code ==
%%%
%%% The Erlang Trace BIFs allow to trace any Erlang code at all. They work in
%%% two parts: pid specifications, and trace patterns.
%%%
%%% Pid specifications let you decide which processes to target. They can be
%%% specific pids, `all' pids, `existing' pids, or `new' pids (those not
%%% spawned at the time of the function call).
%%%
%%% The trace patterns represent functions. Functions can be specified in two
%%% parts: specifying the modules, functions, and arguments, and then with
%%% Erlang match specifications to add constraints to arguments (see
%%% {@link calls/3} for details).
%%%
%%% What defines whether you get traced or not is the intersection of both:
%%%
%%% ```
%%% _,--------,_ _,--------,_
%%% ,-' `-,,-' `-,
%%% ,-' ,-' '-, `-,
%%% | Matching -' '- Matching |
%%% | Pids | Getting | Trace |
%%% | | Traced | Patterns |
%%% | -, ,- |
%%% '-, '-, ,-' ,-'
%%% '-,_ _,-''-,_ _,-'
%%% '--------' '--------'
%%% '''
%%%
%%% If either the pid specification excludes a process or a trace pattern
%%% excludes a given call, no trace will be received.
%%%
%%% == Example Session ==
%%%
%%% First let's trace the `queue:new' functions in any process:
%%%
%%% ```
%%% 1> recon_trace:calls({queue, new, '_'}, 1).
%%% 1
%%% 13:14:34.086078 <0.44.0> queue:new()
%%% Recon tracer rate limit tripped.
%%% '''
%%%
%%% The limit was set to `1' trace message at most, and `recon' let us
%%% know when that limit was reached.
%%%
%%% Let's instead look for all the `queue:in/2' calls, to see what it is
%%% we're inserting in queues:
%%%
%%% ```
%%% 2> recon_trace:calls({queue, in, 2}, 1).
%%% 1
%%% 13:14:55.365157 <0.44.0> queue:in(a, {[],[]})
%%% Recon tracer rate limit tripped.
%%% '''
%%%
%%% In order to see the content we want, we should change the trace patterns
%%% to use a `fun' that matches on all arguments in a list (`_') and returns
%%% `return_trace()'. This last part will generate a second trace for each
%%% call that includes the return value:
%%%
%%% ```
%%% 3> recon_trace:calls({queue, in, fun(_) -> return_trace() end}, 3).
%%% 1
%%%
%%% 13:15:27.655132 <0.44.0> queue:in(a, {[],[]})
%%%
%%% 13:15:27.655467 <0.44.0> queue:in/2 --> {[a],[]}
%%%
%%% 13:15:27.757921 <0.44.0> queue:in(a, {[],[]})
%%% Recon tracer rate limit tripped.
%%% '''
%%%
%%% Matching on argument lists can be done in a more complex manner:
%%%
%%% ```
%%% 4> recon_trace:calls(
%%% 4> {queue, '_', fun([A,_]) when is_list(A); is_integer(A) andalso A > 1 -> return_trace() end},
%%% 4> {10,100}
%%% 4> ).
%%% 32
%%%
%%% 13:24:21.324309 <0.38.0> queue:in(3, {[],[]})
%%%
%%% 13:24:21.371473 <0.38.0> queue:in/2 --> {[3],[]}
%%%
%%% 13:25:14.694865 <0.53.0> queue:split(4, {[10,9,8,7],[1,2,3,4,5,6]})
%%%
%%% 13:25:14.695194 <0.53.0> queue:split/2 --> {{[4,3,2],[1]},{[10,9,8,7],[5,6]}}
%%%
%%% 5> recon_trace:clear().
%%% ok
%%% '''
%%%
%%% Note that in the pattern above, no specific function (<code>'_'</code>) was
%%% matched against. Instead, the `fun' used restricted functions to those
%%% having two arguments, the first of which is either a list or an integer
%%% greater than `1'.
%%%
%%% The limit was also set using `{10,100}' instead of an integer, making the
%%% rate-limitting at 10 messages per 100 milliseconds, instead of an absolute
%%% value.
%%%
%%% Any tracing can be manually interrupted by calling `recon_trace:clear()',
%%% or killing the shell process.
%%%
%%% Be aware that extremely broad patterns with lax rate-limitting (or very
%%% high absolute limits) may impact your node's stability in ways
%%% `recon_trace' cannot easily help you with.
%%%
%%% In doubt, start with the most restrictive tracing possible, with low
%%% limits, and progressively increase your scope.
%%%
%%% See {@link calls/3} for more details and tracing possibilities.
%%%
%%% == Structure ==
%%%
%%% This library is production-safe due to taking the following structure for
%%% tracing:
%%%
%%% ```
%%% [IO/Group leader] <---------------------,
%%% | |
%%% [shell] ---> [tracer process] ----> [formatter]
%%% '''
%%%
%%% The tracer process receives trace messages from the node, and enforces
%%% limits in absolute terms or trace rates, before forwarding the messages
%%% to the formatter. This is done so the tracer can do as little work as
%%% possible and never block while building up a large mailbox.
%%%
%%% The tracer process is linked to the shell, and the formatter to the
%%% tracer process. The formatter also traps exits to be able to handle
%%% all received trace messages until the tracer termination, but will then
%%% shut down as soon as possible.
%%%
%%% In case the operator is tracing from a remote shell which gets
%%% disconnected, the links between the shell and the tracer should make it
%%% so tracing is automatically turned off once you disconnect.
%%%
%%% If sending output to the Group Leader is not desired, you may specify
%%% a different pid() via the option `io_server' in the {@link calls/3} function.
%%% For instance to write the traces to a file you can do something like
%%%
%%% ```
%%% 1> {ok, Dev} = file:open("/tmp/trace",[write]).
%%% 2> recon_trace:calls({queue, in, fun(_) -> return_trace() end}, 3, [{io_server, Dev}]).
%%% 1
%%% 3>
%%% Recon tracer rate limit tripped.
%%% 4> file:close(Dev).
%%% '''
%%%
%%% The only output still sent to the Group Leader is the rate limit being
%%% tripped, and any errors. The rest will be sent to the other IO
%%% server (see [http://erlang.org/doc/apps/stdlib/io_protocol.html]).
%%% @end
-module(recon_trace).
%% API
-export([clear/0, calls/2, calls/3]).
-export([format/1]).
%% Internal exports
-export([count_tracer/1, rate_tracer/2, formatter/5]).
-type matchspec() :: [{[term()], [term()], [term()]}].
-type shellfun() :: fun((_) -> term()).
-type formatterfun() :: fun((_) -> iodata()).
-type millisecs() :: non_neg_integer().
-type pidspec() :: all | existing | new | recon:pid_term().
-type max_traces() :: non_neg_integer().
-type max_rate() :: {max_traces(), millisecs()}.
%% trace options
-type options() :: [{pid, pidspec() | [pidspec(), ...]} % default: all
| {timestamp, formatter | trace} % default: formatter
| {args, args | arity} % default: args
| {io_server, pid()} % default: group_leader()
| {formatter, formatterfun()} % default: internal formatter
| return_to | {return_to, boolean()} % default: false
%% match pattern options
| {scope, global | local} % default: global
].
-type mod() :: '_' | module().
-type fn() :: '_' | atom().
-type args() :: '_' | 0..255 | return_trace | matchspec() | shellfun().
-type tspec() :: {mod(), fn(), args()}.
-type max() :: max_traces() | max_rate().
-type num_matches() :: non_neg_integer().
-export_type([mod/0, fn/0, args/0, tspec/0, num_matches/0, options/0,
max_traces/0, max_rate/0]).
%%%%%%%%%%%%%%
%%% PUBLIC %%%
%%%%%%%%%%%%%%
%% @doc Stops all tracing at once.
-spec clear() -> ok.
clear() ->
erlang:trace(all, false, [all]),
erlang:trace_pattern({'_', '_', '_'}, false, [local, meta, call_count, call_time]),
erlang:trace_pattern({'_', '_', '_'}, false, []), % unsets global
maybe_kill(recon_trace_tracer),
maybe_kill(recon_trace_formatter),
ok.
%% @equiv calls({Mod, Fun, Args}, Max, [])
-spec calls(tspec() | [tspec(), ...], max()) -> num_matches().
calls({Mod, Fun, Args}, Max) ->
calls([{Mod, Fun, Args}], Max, []);
calls(TSpecs = [_ | _], Max) ->
calls(TSpecs, Max, []).
%% @doc Allows to set trace patterns and pid specifications to trace
%% function calls.
%%
%% The basic calls take the trace patterns as tuples of the form
%% `{Module, Function, Args}' where:
%%
%% <ul>
%% <li>`Module' is any atom representing a module</li>
%% <li>`Function' is any atom representing a function, or the wildcard
%% <code>'_'</code></li>
%% <li>`Args' is either the arity of a function (`0..255'), a wildcard
%% pattern (<code>'_'</code>), a
%% <a href="http://learnyousomeerlang.com/ets#you-have-been-selected">match specification</a>,
%% or a function from a shell session that can be transformed into
%% a match specification</li>
%% </ul>
%%
%% There is also an argument specifying either a maximal count (a number)
%% of trace messages to be received, or a maximal frequency (`{Num, Millisecs}').
%%
%% Here are examples of things to trace:
%%
%% <ul>
%% <li>All calls from the `queue' module, with 10 calls printed at most:
%% ``recon_trace:calls({queue, '_', '_'}, 10)''</li>
%% <li>All calls to `lists:seq(A,B)', with 100 calls printed at most:
%% `recon_trace:calls({lists, seq, 2}, 100)'</li>
%% <li>All calls to `lists:seq(A,B)', with 100 calls per second at most:
%% `recon_trace:calls({lists, seq, 2}, {100, 1000})'</li>
%% <li>All calls to `lists:seq(A,B,2)' (all sequences increasing by two)
%% with 100 calls at most:
%% `recon_trace:calls({lists, seq, fun([_,_,2]) -> ok end}, 100)'</li>
%% <li>All calls to `iolist_to_binary/1' made with a binary as an argument
%% already (kind of useless conversion!):
%% `recon_trace:calls({erlang, iolist_to_binary, fun([X]) when is_binary(X) -> ok end}, 10)'</li>
%% <li>Calls to the queue module only in a given process `Pid', at a rate
%% of 50 per second at most:
%% ``recon_trace:calls({queue, '_', '_'}, {50,1000}, [{pid, Pid}])''</li>
%% <li>Print the traces with the function arity instead of literal arguments:
%% `recon_trace:calls(TSpec, Max, [{args, arity}])'</li>
%% <li>Matching the `filter/2' functions of both `dict' and `lists' modules,
%% across new processes only:
%% `recon_trace:calls([{dict,filter,2},{lists,filter,2}], 10, [{pid, new}])'</li>
%% <li>Tracing the `handle_call/3' functions of a given module for all new processes,
%% and those of an existing one registered with `gproc':
%% `recon_trace:calls({Mod,handle_call,3}, {10,100}, [{pid, [{via, gproc, Name}, new]}'</li>
%% <li>Show the result of a given function call:
%% `recon_trace:calls({Mod,Fun,fun(_) -> return_trace() end}, Max, Opts)'
%% or
%% ``recon_trace:calls({Mod,Fun,[{'_', [], [{return_trace}]}]}, Max, Opts)'',
%% the important bit being the `return_trace()' call or the
%% `{return_trace}' match spec value.
%% A short-hand version for this pattern of 'match anything, trace everything'
%% for a function is `recon_trace:calls({Mod, Fun, return_trace})'. </li>
%% </ul>
%%
%% There's a few more combination possible, with multiple trace patterns per call, and more
%% options:
%%
%% <ul>
%% <li>`{pid, PidSpec}': which processes to trace. Valid options is any of
%% `all', `new', `existing', or a process descriptor (`{A,B,C}',
%% `"<A.B.C>"', an atom representing a name, `{global, Name}',
%% `{via, Registrar, Name}', or a pid). It's also possible to specify
%% more than one by putting them in a list.</li>
%% <li>`{timestamp, formatter | trace}': by default, the formatter process
%% adds timestamps to messages received. If accurate timestamps are
%% required, it's possible to force the usage of timestamps within
%% trace messages by adding the option `{timestamp, trace}'.</li>
%% <li>`{args, arity | args}': whether to print arity in function calls
%% or their (by default) literal representation.</li>
%% <li>`{scope, global | local}': by default, only 'global' (fully qualified
%% function calls) are traced, not calls made internally. To force tracing
%% of local calls, pass in `{scope, local}'. This is useful whenever
%% you want to track the changes of code in a process that isn't called
%% with `Module:Fun(Args)', but just `Fun(Args)'.</li>
%% <li>`{formatter, fun(Term) -> io_data() end}': override the default
%% formatting functionality provided by recon.</li>
%% <li>`{io_server, pid() | atom()}': by default, recon logs to the current
%% group leader, usually the shell. This option allows to redirect
%% trace output to a different IO server (such as a file handle).</li>
%% <li>`return_to': If this option is set (in conjunction with the match
%% option `{scope, local}'), the function to which the value is returned
%% is output in a trace. Note that this is distinct from giving the
%% *caller* since exception handling or calls in tail position may
%% hide the original caller.</li>
%% </ul>
%%
%% Also note that putting extremely large `Max' values (i.e. `99999999' or
%% `{10000,1}') will probably negate most of the safe-guarding this library
%% does and be dangerous to your node. Similarly, tracing extremely large
%% amounts of function calls (all of them, or all of `io' for example)
%% can be risky if more trace messages are generated than any process on
%% the node could ever handle, despite the precautions taken by this library.
%% @end
-spec calls(tspec() | [tspec(), ...], max(), options()) -> num_matches().
calls({Mod, Fun, Args}, Max, Opts) ->
calls([{Mod, Fun, Args}], Max, Opts);
calls(TSpecs = [_ | _], {Max, Time}, Opts) ->
Pid = setup(rate_tracer, [Max, Time],
validate_formatter(Opts), validate_io_server(Opts)),
trace_calls(TSpecs, Pid, Opts);
calls(TSpecs = [_ | _], Max, Opts) ->
Pid = setup(count_tracer, [Max],
validate_formatter(Opts), validate_io_server(Opts)),
trace_calls(TSpecs, Pid, Opts).
%%%%%%%%%%%%%%%%%%%%%%%
%%% PRIVATE EXPORTS %%%
%%%%%%%%%%%%%%%%%%%%%%%
%% @private Stops when N trace messages have been received
count_tracer(0) ->
exit(normal);
count_tracer(N) ->
receive
Msg ->
recon_trace_formatter ! Msg,
count_tracer(N - 1)
end.
%% @private Stops whenever the trace message rates goes higher than
%% `Max' messages in `Time' milliseconds. Note that if the rate
%% proposed is higher than what the IO system of the formatter
%% can handle, this can still put a node at risk.
%%
%% It is recommended to try stricter rates to begin with.
rate_tracer(Max, Time) -> rate_tracer(Max, Time, 0, os:timestamp()).
rate_tracer(Max, Time, Count, Start) ->
receive
Msg ->
recon_trace_formatter ! Msg,
Now = os:timestamp(),
Delay = timer:now_diff(Now, Start) div 1000,
if Delay > Time -> rate_tracer(Max, Time, 0, Now)
; Max > Count -> rate_tracer(Max, Time, Count + 1, Start)
; Max =:= Count -> exit(normal)
end
end.
%% @private Formats traces to be output
formatter(Tracer, Parent, Ref, FormatterFun, IOServer) ->
process_flag(trap_exit, true),
link(Tracer),
Parent ! {Ref, linked},
formatter(Tracer, IOServer, FormatterFun).
formatter(Tracer, IOServer, FormatterFun) ->
receive
{'EXIT', Tracer, normal} ->
io:format("Recon tracer rate limit tripped.~n"),
exit(normal);
{'EXIT', Tracer, Reason} ->
exit(Reason);
TraceMsg ->
io:format(IOServer, FormatterFun(TraceMsg), []),
formatter(Tracer, IOServer, FormatterFun)
end.
%%%%%%%%%%%%%%%%%%%%%%%
%%% SETUP FUNCTIONS %%%
%%%%%%%%%%%%%%%%%%%%%%%
%% starts the tracer and formatter processes, and
%% cleans them up before each call.
setup(TracerFun, TracerArgs, FormatterFun, IOServer) ->
clear(),
Ref = make_ref(),
Tracer = spawn_link(?MODULE, TracerFun, TracerArgs),
register(recon_trace_tracer, Tracer),
Format = spawn(?MODULE, formatter, [Tracer, self(), Ref, FormatterFun, IOServer]),
register(recon_trace_formatter, Format),
receive
{Ref, linked} -> Tracer
after 5000 ->
error(setup_failed)
end.
%% Sets the traces in action
trace_calls(TSpecs, Pid, Opts) ->
{PidSpecs, TraceOpts, MatchOpts} = validate_opts(Opts),
Matches = [begin
{Arity, Spec} = validate_tspec(Mod, Fun, Args),
erlang:trace_pattern({Mod, Fun, Arity}, Spec, MatchOpts)
end || {Mod, Fun, Args} <- TSpecs],
[erlang:trace(PidSpec, true, [call, {tracer, Pid} | TraceOpts])
|| PidSpec <- PidSpecs],
lists:sum(Matches).
%%%%%%%%%%%%%%%%%%
%%% VALIDATION %%%
%%%%%%%%%%%%%%%%%%
validate_opts(Opts) ->
PidSpecs = validate_pid_specs(proplists:get_value(pid, Opts, all)),
Scope = proplists:get_value(scope, Opts, global),
TraceOpts = case proplists:get_value(timestamp, Opts, formatter) of
formatter -> [];
trace -> [timestamp]
end ++
case proplists:get_value(args, Opts, args) of
args -> [];
arity -> [arity]
end ++
case proplists:get_value(return_to, Opts, undefined) of
true when Scope =:= local ->
[return_to];
true when Scope =:= global ->
io:format("Option return_to only works with option {scope, local}~n"),
%% Set it anyway
[return_to];
_ ->
[]
end,
MatchOpts = [Scope],
{PidSpecs, TraceOpts, MatchOpts}.
%% Support the regular specs, but also allow `recon:pid_term()' and lists
%% of further pid specs.
-spec validate_pid_specs(pidspec() | [pidspec(), ...]) ->
[all | new | existing | pid(), ...].
validate_pid_specs(all) -> [all];
validate_pid_specs(existing) -> [existing];
validate_pid_specs(new) -> [new];
validate_pid_specs([Spec]) -> validate_pid_specs(Spec);
validate_pid_specs(PidTerm = [Spec | Rest]) ->
%% can be "<a.b.c>" or [pidspec()]
try
[recon_lib:term_to_pid(PidTerm)]
catch
error:function_clause ->
validate_pid_specs(Spec) ++ validate_pid_specs(Rest)
end;
validate_pid_specs(PidTerm) ->
%% has to be `recon:pid_term()'.
[recon_lib:term_to_pid(PidTerm)].
validate_tspec(Mod, Fun, Args) when is_function(Args) ->
validate_tspec(Mod, Fun, fun_to_ms(Args));
%% helper to save typing for common actions
validate_tspec(Mod, Fun, return_trace) ->
validate_tspec(Mod, Fun, [{'_', [], [{return_trace}]}]);
validate_tspec(Mod, Fun, Args) ->
BannedMods = ['_', ?MODULE, io, lists],
%% The banned mod check can be bypassed by using
%% match specs if you really feel like being dumb.
case {lists:member(Mod, BannedMods), Args} of
{true, '_'} -> error({dangerous_combo, {Mod, Fun, Args}});
{true, []} -> error({dangerous_combo, {Mod, Fun, Args}});
_ -> ok
end,
case Args of
'_' -> {'_', true};
_ when is_list(Args) -> {'_', Args};
_ when Args >= 0, Args =< 255 -> {Args, true}
end.
validate_formatter(Opts) ->
case proplists:get_value(formatter, Opts) of
F when is_function(F, 1) -> F;
_ -> fun format/1
end.
validate_io_server(Opts) ->
proplists:get_value(io_server, Opts, group_leader()).
%%%%%%%%%%%%%%%%%%%%%%%%
%%% TRACE FORMATTING %%%
%%%%%%%%%%%%%%%%%%%%%%%%
%% Thanks Geoff Cant for the foundations for this.
format(TraceMsg) ->
{Type, Pid, {Hour, Min, Sec}, TraceInfo} = extract_info(TraceMsg),
{FormatStr, FormatArgs} = case {Type, TraceInfo} of
%% {trace, Pid, 'receive', Msg}
{'receive', [Msg]} ->
{"< ~p", [Msg]};
%% {trace, Pid, send, Msg, To}
{send, [Msg, To]} ->
{" > ~p: ~p", [To, Msg]};
%% {trace, Pid, send_to_non_existing_process, Msg, To}
{send_to_non_existing_process, [Msg, To]} ->
{" > (non_existent) ~p: ~p", [To, Msg]};
%% {trace, Pid, call, {M, F, Args}}
{call, [{M, F, Args}]} ->
{"~p:~p~s", [M, F, format_args(Args)]};
%% {trace, Pid, return_to, {M, F, Arity}}
{return_to, [{M, F, Arity}]} ->
{" '--> ~p:~p/~p", [M, F, Arity]};
%% {trace, Pid, return_from, {M, F, Arity}, ReturnValue}
{return_from, [{M, F, Arity}, Return]} ->
{"~p:~p/~p --> ~p", [M, F, Arity, Return]};
%% {trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}
{exception_from, [{M, F, Arity}, {Class, Val}]} ->
{"~p:~p/~p ~p ~p", [M, F, Arity, Class, Val]};
%% {trace, Pid, spawn, Spawned, {M, F, Args}}
{spawn, [Spawned, {M, F, Args}]} ->
{"spawned ~p as ~p:~p~s", [Spawned, M, F, format_args(Args)]};
%% {trace, Pid, exit, Reason}
{exit, [Reason]} ->
{"EXIT ~p", [Reason]};
%% {trace, Pid, link, Pid2}
{link, [Linked]} ->
{"link(~p)", [Linked]};
%% {trace, Pid, unlink, Pid2}
{unlink, [Linked]} ->
{"unlink(~p)", [Linked]};
%% {trace, Pid, getting_linked, Pid2}
{getting_linked, [Linker]} ->
{"getting linked by ~p", [Linker]};
%% {trace, Pid, getting_unlinked, Pid2}
{getting_unlinked, [Unlinker]} ->
{"getting unlinked by ~p", [Unlinker]};
%% {trace, Pid, register, RegName}
{register, [Name]} ->
{"registered as ~p", [Name]};
%% {trace, Pid, unregister, RegName}
{unregister, [Name]} ->
{"no longer registered as ~p", [Name]};
%% {trace, Pid, in, {M, F, Arity} | 0}
{in, [{M, F, Arity}]} ->
{"scheduled in for ~p:~p/~p", [M, F, Arity]};
{in, [0]} ->
{"scheduled in", []};
%% {trace, Pid, out, {M, F, Arity} | 0}
{out, [{M, F, Arity}]} ->
{"scheduled out from ~p:~p/~p", [M, F, Arity]};
{out, [0]} ->
{"scheduled out", []};
%% {trace, Pid, gc_start, Info}
{gc_start, [Info]} ->
HeapSize = proplists:get_value(heap_size, Info),
OldHeapSize = proplists:get_value(old_heap_size, Info),
MbufSize = proplists:get_value(mbuf_size, Info),
{"gc beginning -- heap ~p bytes",
[HeapSize + OldHeapSize + MbufSize]};
%% {trace, Pid, gc_end, Info}
{gc_end, [Info]} ->
HeapSize = proplists:get_value(heap_size, Info),
OldHeapSize = proplists:get_value(old_heap_size, Info),
MbufSize = proplists:get_value(mbuf_size, Info),
{"gc finished -- heap ~p bytes",
[HeapSize + OldHeapSize + MbufSize]};
_ ->
{"unknown trace type ~p -- ~p", [Type, TraceInfo]}
end,
io_lib:format("~n~p:~p:~9.6.0f ~p " ++ FormatStr ++ "~n",
[Hour, Min, Sec, Pid] ++ FormatArgs).
extract_info(TraceMsg) ->
case tuple_to_list(TraceMsg) of
[trace_ts, Pid, Type | Info] ->
{TraceInfo, [Timestamp]} = lists:split(length(Info) - 1, Info),
{Type, Pid, to_hms(Timestamp), TraceInfo};
[trace, Pid, Type | TraceInfo] ->
{Type, Pid, to_hms(os:timestamp()), TraceInfo}
end.
to_hms(Stamp = {_, _, Micro}) ->
{_, {H, M, Secs}} = calendar:now_to_local_time(Stamp),
Seconds = Secs rem 60 + (Micro / 1000000),
{H, M, Seconds};
to_hms(_) ->
{0, 0, 0}.
format_args(Arity) when is_integer(Arity) ->
"/" ++ integer_to_list(Arity);
format_args(Args) when is_list(Args) ->
"(" ++ string:join([io_lib:format("~p", [Arg]) || Arg <- Args], ", ") ++ ")".
%%%%%%%%%%%%%%%
%%% HELPERS %%%
%%%%%%%%%%%%%%%
maybe_kill(Name) ->
case whereis(Name) of
undefined ->
ok;
Pid ->
unlink(Pid),
exit(Pid, kill),
wait_for_death(Pid, Name)
end.
wait_for_death(Pid, Name) ->
case is_process_alive(Pid) orelse whereis(Name) =:= Pid of
true ->
timer:sleep(10),
wait_for_death(Pid, Name);
false ->
ok
end.
%% Borrowed from dbg
fun_to_ms(ShellFun) when is_function(ShellFun) ->
case erl_eval:fun_data(ShellFun) of
{fun_data, ImportList, Clauses} ->
case ms_transform:transform_from_shell(
dbg, Clauses, ImportList) of
{error, [{_, [{_, _, Code} | _]} | _], _} ->
io:format("Error: ~s~n",
[ms_transform:format_error(Code)]),
{error, transform_error};
Else ->
Else
end;
false ->
exit(shell_funs_only)
end.

+ 249
- 0
src/srvNodeMgr/tools_cq/seek_info.erl Dosyayı Görüntüle

@ -0,0 +1,249 @@
-module(seek_info).
%% API
-export([
eprof_start/0,
eprof_stop/0,
fprof_start/0,
fprof_start/1,
fprof_stop/0,
fprof_analyze/0,
queue/1,
memory/1,
reds/1,
help/0
]).
-define(APPS, [kernel, game]).
%%====================================================================
%% API
%%====================================================================
help() ->
io:format("Brief help:~n"
"~p:queue(N) -> show top N pids sorted by queue length~n"
"~p:memory(N) -> show top N pids sorted by memory usage~n"
"~p:reds(N) -> show top N pids sorted by reductions~n"
"Erlang shell with Ctrl+C~n"
"~p:eprof_start() -> start eprof on all available pids; "
"DO NOT use on production system!~n"
"~p:eprof_stop() -> stop eprof and print result~n"
"~p:fprof_start() -> start fprof on all available pids; "
"DO NOT use on production system!~n"
"~p:fprof_stop() -> stop eprof and print formatted result~n"
"~p:fprof_start(N) -> start and run fprof for N seconds; "
"use ~p:fprof_analyze() to analyze collected statistics and "
"print formatted result; use on production system with CARE~n"
"~p:fprof_analyze() -> analyze previously collected statistics "
"using ~p:fprof_start(N) and print formatted result~n"
"~p:help() -> print this help~n",
lists:duplicate(12, ?MODULE)).
eprof_start() ->
eprof:start(),
case lists:keyfind(running, 1, application:info()) of
{_, Apps} ->
case get_procs(?APPS, Apps) of
[] ->
{error, no_procs_found};
Procs ->
eprof:start_profiling(Procs)
end;
_ ->
{error, no_app_info}
end.
fprof_start() ->
fprof_start(0).
fprof_start(Duration) ->
case lists:keyfind(running, 1, application:info()) of
{_, Apps} ->
case get_procs(?APPS, Apps) of
[] ->
{error, no_procs_found};
Procs ->
fprof:trace([start, {procs, Procs}]),
io:format("Profiling started~n"),
if Duration > 0 ->
timer:sleep(Duration * 1000),
fprof:trace([stop]),
fprof:stop();
true ->
ok
end
end;
_ ->
{error, no_app_info}
end.
fprof_stop() ->
fprof:trace([stop]),
fprof:profile(),
fprof:analyse([totals, no_details, {sort, own},
no_callers, {dest, "fprof.analysis"}]),
fprof:stop(),
format_fprof_analyze().
fprof_analyze() ->
fprof_stop().
eprof_stop() ->
eprof:stop_profiling(),
eprof:analyze().
queue(N) ->
dump(N, lists:reverse(lists:ukeysort(1, all_pids(queue)))).
memory(N) ->
dump(N, lists:reverse(lists:ukeysort(3, all_pids(memory)))).
reds(N) ->
dump(N, lists:reverse(lists:ukeysort(4, all_pids(reductions)))).
%%====================================================================
%% Internal functions
%%====================================================================
get_procs(Apps, AppList) ->
io:format("Searching for processes to profile...~n", []),
Procs = lists:foldl(
fun({App, Leader}, Acc) when is_pid(Leader) ->
case lists:member(App, Apps) of
true ->
[get_procs2(Leader) | Acc];
false ->
Acc
end;
(_, Acc) ->
Acc
end, [], AppList),
io:format("Found ~p processes~n", [length(Procs)]),
Procs.
get_procs2(Leader) ->
lists:filter(
fun(Pid) ->
case process_info(Pid, group_leader) of
{_, Leader} ->
true;
_ ->
false
end
end, processes()).
format_fprof_analyze() ->
case file:consult("fprof.analysis") of
{ok, [_, [{totals, _, _, TotalOWN}] | Rest]} ->
OWNs =
lists:flatmap(
fun({MFA, _, _, OWN}) ->
Percent = OWN * 100 / TotalOWN,
case round(Percent) of
0 -> [];
_ -> [{mfa_to_list(MFA), Percent}]
end
end, Rest),
ACCs = collect_accs(Rest),
MaxACC = find_max(ACCs),
MaxOWN = find_max(OWNs),
io:format("=== Sorted by OWN:~n"),
lists:foreach(
fun({MFA, Per}) ->
L = length(MFA),
S = lists:duplicate(MaxOWN - L + 2, $ ),
io:format("~s~s~.2f%~n", [MFA, S, Per])
end, lists:reverse(lists:keysort(2, OWNs))),
io:format("~n=== Sorted by ACC:~n"),
lists:foreach(
fun({MFA, Per}) ->
L = length(MFA),
S = lists:duplicate(MaxACC - L + 2, $ ),
io:format("~s~s~.2f%~n", [MFA, S, Per])
end, lists:reverse(lists:keysort(2, ACCs)));
Err ->
Err
end.
mfa_to_list({M, F, A}) ->
atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A);
mfa_to_list(F) when is_atom(F) ->
atom_to_list(F).
find_max(List) ->
find_max(List, 0).
find_max([{V, _} | Tail], Acc) ->
find_max(Tail, lists:max([length(V), Acc]));
find_max([], Acc) ->
Acc.
collect_accs(List) ->
List1 = lists:filter(
fun({{sys, _, _}, _, _, _}) ->
false;
({suspend, _, _, _}) ->
false;
({{gen_fsm, _, _}, _, _, _}) ->
false;
({{gen, _, _}, _, _, _}) ->
false;
({{gen_server, _, _}, _, _, _}) ->
false;
({{proc_lib, _, _}, _, _, _}) ->
false;
(_) ->
true
end, List),
calculate(List1).
calculate(List1) ->
TotalACC = lists:sum([A || {_, _, A, _} <- List1]),
List2 = lists:foldl(fun({MFA, _, ACC, _}, NewList) ->
Percent = ACC * 100 / TotalACC,
case round(Percent) of
0 -> NewList;
_ -> [{mfa_to_list(MFA), Percent} | NewList]
end
end, [], List1),
lists:reverse(List2).
all_pids(Type) ->
lists:foldl(
fun(P, Acc) when P == self() ->
Acc;
(P, Acc) ->
case catch process_info(
P, [message_queue_len, memory, reductions,
dictionary, current_function, registered_name]) of
[{_, Len}, {_, Memory}, {_, Reds},
{_, Dict}, {_, CurFun}, {_, RegName}] ->
IntQLen = get_internal_queue_len(Dict),
if Type == queue andalso Len == 0 andalso IntQLen == 0 ->
Acc;
true ->
[{lists:max([Len, IntQLen]),
Len, Memory, Reds, Dict, CurFun, P, RegName} | Acc]
end;
_ ->
Acc
end
end, [], processes()).
get_internal_queue_len(Dict) ->
case lists:keysearch('$internal_queue_len', 1, Dict) of
{value, {_, N}} -> N;
_ -> 0
end.
dump(N, Rs) ->
lists:foreach(
fun({_, MsgQLen, Memory, Reds, Dict, CurFun, Pid, RegName}) ->
io:format("** pid(~s)~n"
"** registered name: ~p~n"
"** memory: ~p~n"
"** reductions: ~p~n"
"** message queue len: ~p~n"
"** current_function: ~p~n"
"** dictionary: ~p~n~n",
[pid_to_list(Pid), RegName, Memory, Reds, MsgQLen, CurFun, Dict])
end, lists:sublist(Rs, N)).

+ 103
- 0
src/srvNodeMgr/tools_cq/test.erl Dosyayı Görüntüle

@ -0,0 +1,103 @@
-module(test).
-export([
time_compare/2,
time_compare/3
]).
%% Apis ----------------------------------------
% @doc
% @spec time_compare(Num, TList) -> ok | skip.
% Num :: integer()
% TList :: [Test]
% Test :: {InfoString :: string(), Fun :: fun()}
% format the test result as following:
%
time_compare(Num, TList) ->
time_compare(Num, TList, []).
% @doc
% @spec time_compare(Num, TList, Option) -> ok | skip.
% same as time_compare/2
% Option :: nyi (Not Yet Implemented)
time_compare(0, _TList, _Opt) ->
skip;
time_compare(Num, TList, _Opt) ->
ResultList = [do_time_compare(Num, Tester) || Tester <- TList],
io:format("=============================================================================================~n"),
do_print_out(ResultList),
io:format("=============================================================================================~n").
%% Privates ------------------------------------
do_time_compare(Num, {Label, Func}) ->
statistics(wall_clock),
do_time_compare_f1(1, Num, Func),
{_, Time} = statistics(wall_clock),
US = Time * 1000 / Num,
io:format("~-30s [wall_clock: total:~10w ms avg:~7.3f us]~n", [Label, Time, US]),
{Label, Time};
do_time_compare(Num, {Label, Func, ProcessNum}) ->
Pids = do_time_compare_init(Num, 0, ProcessNum, Func, []),
statistics(wall_clock),
[erlang:send(Pid, go) || Pid <- Pids],
do_time_compare_water(length(Pids)),
{_, Time} = statistics(wall_clock),
US = Time * 1000 / Num,
io:format("~-30s [wall_clock: total: ~10w ms avg: ~7.3f)us]~n", [Label, Time, US]),
{Label, Time}.
do_time_compare_init(0, _Start, _ProcessNum, _Func, Pids) ->
Pids;
do_time_compare_init(Num, Start, 1, Func, Pids) ->
Self = erlang:self(),
Pid = spawn_link(fun() -> do_time_compare_worker(Self, Func, Start + 1, Start + Num) end),
[Pid | Pids];
do_time_compare_init(Num, Start, ProcessNum, Func, Pids) ->
Self = erlang:self(),
DoRound = Num div ProcessNum,
Pid = spawn_link(fun() -> do_time_compare_worker(Self, Func, Start + 1, Start + DoRound) end),
do_time_compare_init(Num - DoRound, Start + DoRound, ProcessNum - 1, Func, [Pid | Pids]).
do_time_compare_water(0) ->
ok;
do_time_compare_water(Num) ->
receive
ok ->
do_time_compare_water(Num - 1);
Msg ->
erlang:error(io_lib:format("bad message: ~w", [Msg]))
end.
do_time_compare_worker(Pid, Func, From, To) ->
receive
go ->
do_time_compare_f1(From, To, Func),
Pid ! ok;
_ ->
ok
end.
do_time_compare_f1(Max, Max, Func) ->
Func(Max);
do_time_compare_f1(I, Max, Func) ->
Func(I),
do_time_compare_f1(I + 1, Max, Func).
do_print_out([{_LabelBase, TimeBase} | _] = ResultList) ->
do_print_out(ResultList, TimeBase).
% @doc
% @spec do_print_out(ResultList, {RunTimeBase, WallClockBase}) -> ok.
% ResultList :: [Result]
% Result :: [Label, RunTime, WallClock]
% Label :: string()
% RunTimeBase = WallClockBase :: integer()
do_print_out(ResultList, TimeBase) ->
[
io:format(
"~-30s [ wall_clock: ~10w ms percentage: ~7.2f%]~n",
[Label, Time, Time / (TimeBase + 0.000000001) * 100]
)
|| {Label, Time} <- ResultList
].

+ 74
- 0
src/srvNodeMgr/tools_cq/tester.erl Dosyayı Görüntüle

@ -0,0 +1,74 @@
-module(tester).
-include("common.hrl").
-export([
test_online_num/1,
test_scene_sign/0,
test_lists_and_proplists/0,
test_lists_and_proplists/3
]).
%% Apis ------------------------------
test_online_num(Repeat) ->
F1 = fun(_) -> lib_world_boss:online_num() end,
F2 = fun(_) -> lib_world_boss:online_num2() end,
Tester = [
{"lib_world_boss:online_num", F1},
{"lib_world_boss:online_num2", F2}
],
test:time_compare(Repeat, Tester).
test_lists_and_proplists() ->
test_lists_and_proplists(10000, 10, 50).
test_lists_and_proplists(Repeat, ListSize, FindSize) ->
{ToFindKeys, MaterialList} = gen_list_material(ListSize, FindSize),
F1 = fun(_) -> [lists:keyfind(K, 1, MaterialList) || K <- ToFindKeys] end,
F2 = fun(_) -> [proplists:get_value(K, MaterialList) || K <- ToFindKeys] end,
Tester = [
{"lists:keyfind/3", F1},
{"proplists:get_value/2", F2}
],
test:time_compare(Repeat, Tester).
%% @doc
test_scene_sign() ->
case conf_scene_list:get_id_list() of
SceneList when SceneList =/= [] ->
SceneID = util:list_rand(SceneList),
test_scene_sign(10000, SceneID, 100);
_ ->
ignore
end.
test_scene_sign(Repeat, SceneID, FindSize) ->
{MaxX, MaxY} = lib_scene_sign:get_max_xy(SceneID),
PosList = [{util:rand(1, MaxX), util:rand(1, MaxY)} || _ <- lists:seq(1, FindSize)],
%% s3取svr_scene_sign模块svr_scene_sign:load_sign/1call
svr_scene_sign:ensure_scene_sign(SceneID),
F1 = fun(_) ->
[svr_scene_sign:get_scene_poses({SceneID, X, Y}) || {X, Y} <- PosList]
end,
Ets = conf_scene:get_ets(SceneID),
F2 = fun(_) ->
[lib_scene_sign:is_pos_blocked(Ets, {SceneID, X, Y}) || {X, Y} <- PosList]
end,
F3 = fun(_) ->
[lib_scene_sign:is_pos_blocked({SceneID, X, Y}) || {X, Y} <- PosList]
end,
Tester = [
{"scene_sign+gen_server", F1},
{"scene_sign+ets", F2},
{"scene_sign+ets", F3}
],
test:time_compare(Repeat, Tester).
%% Privates --------------------------
gen_list_material(ListSize, FindSize) ->
Keys = [list_to_atom(lists:concat([k, I])) || I <- lists:seq(1, ListSize)],
Values = [list_to_atom(lists:concat([v, I])) || I <- lists:seq(1, ListSize)],
List = lists:zip(Keys, Values),
ToFind = util:gen_n(FindSize, Keys),
{ToFind, List}.

+ 150
- 0
src/srvNodeMgr/tools_cq/tools.erl Dosyayı Görüntüle

@ -0,0 +1,150 @@
-module(tools).
-export([
eprof_all/1,
eprof/2,
task_tc/1,
get_dic/2,
timertc/3 %
]).
eprof_all(TimeoutSec) ->
eprof(processes() -- [whereis(eprof)], TimeoutSec).
eprof(Pids, TimeoutSec) ->
eprof:start(),
eprof:start_profiling(Pids),
timer:sleep(TimeoutSec),
eprof:stop_profiling(),
eprof:analyze(total),
eprof:stop().
%% -----------------------------
%%
%% -----------------------------
%% @spec
%% ProNum:
%% ExeNum:
%% Fun:
%% @return: us
%% @end
timertc(ProNum, ExeNum, Fun) ->
Parent = self(),
lists:sum([receive {Pid, Res} -> Res end || Pid <- [spawn(fun() ->
ExeL__ = lists:seq(1, ExeNum),
{BA, BB, BC} = os:timestamp(),
Begin = 1000000000000 * BA + 1000000 * BB + BC,
[Fun() || _Exe <- ExeL__],
{EA, EB, EC} = os:timestamp(),
End = 1000000000000 * EA + 1000000 * EB + EC,
Us = End - Begin,
Parent ! {self(), Us},
ok
end) || _ProL <- lists:seq(1, ProNum)]]).
%% =================================================================================================
%%
%% =================================================================================================
%% type:term_to_bitstring erlang:term_to_binary erlang:term_to_binary 20
% test_term_to_binary(N,M) ->
% D = [{shfkshfskhf,asdfhjsfj,asdfkhaslfj,sdfkhjasklfj,sflhjaslfkj,lkhasfkljs,ksdhflhjasf,sjdflj} || _<-lists:seq(1, 500)],
% D1 = type:term_to_bitstring(D),
% D2 = erlang:term_to_binary(D),
% F11 = fun() -> type:term_to_bitstring(D) end,
% F12 = fun() -> type:bitstring_to_term(D1) end,
% A1 = timertc(N,M, F11),
% A2 = timertc(N,M, F12),
% io:format("a ~p ~p~n", [A1, A2]),
% F21 = fun() -> erlang:term_to_binary(D) end,
% F22 = fun() -> erlang:binary_to_term(D2) end,
% B1 = timertc(N,M, F21),
% B2 = timertc(N,M, F22),
% io:format("b ~p ~p~n", [B1, B2]),
% ok.
% task_tc(Msg, M, F, A) ->
% ListMsg = tuple_to_list(Msg),
% [AtomMsg | _] = ListMsg,
% statistics(runtime),
% statistics(wall_clock),
% Value = apply(M, F, A),
% {_, Time1} = statistics(runtime),
% {_, Time2} = statistics(wall_clock),
% time_test("Msg:~p, ~p:~p, Time1:~p, Time2:~p", [AtomMsg, M, F, Time1, Time2]),
% Value.
task_tc(Msg) ->
ListMsg = tuple_to_list(Msg),
[AtomMsg | _] = ListMsg,
ProInfo = erlang:process_info(self(), total_heap_size),
NowMs = time:unixtime_ms(),
LastMs =
case get(last_ms) of
undefined -> NowMs;
LM -> LM
end,
put(last_ms, NowMs),
DiffMs = NowMs - LastMs,
LastT =
case get(last_time) of
undefined -> 0;
LT -> LT
end,
Ms = DiffMs + LastT,
put(last_time, Ms),
time_test("Msg:~p, Ms:~p, ProInfo:~p", [AtomMsg, Ms, ProInfo]).
%%
time_test(Format, Args) ->
{{Year, Month, Day}, {Hour, Min, Sec}} = erlang:localtime(),
File =
case get("time_test") of
%
undefined ->
FileName = io_lib:format("time_test_~p_~p_~p.txt", [Year, Month, Day]),
PathName = config:get_log_path() ++ "/" ++ type:unicode_string(FileName),
{ok, File1} = file:open(PathName, [write, append]),
put("time_test", {File1, {Year, Month, Day}}),
File1;
%
{File2, {Year, Month, Day}} ->
File2;
%
{File2, _} ->
file:close(File2),
FileName = io_lib:format("time_test_~p_~p_~p.txt", [Year, Month, Day]),
PathName = config:get_log_path() ++ "/" ++ type:unicode_string(FileName),
{ok, File3} = file:open(PathName, [write, append]),
put("time_test", {File3, {Year, Month, Day}}),
File3
end,
%Format1 = unicode:characters_to_list("#error" ++ " ~p-~p-~p ~p:~p:~p \r\n" ++ Format ++ "\r\n~n"),
Format1 = type:unicode_string("#error" ++ " ~p-~p-~p ~p:~p:~p \r\n" ++ Format ++ "\r\n~n"),
io:format(File, Format1, [Year, Month, Day, Hour, Min, Sec] ++ Args).
get_dic(Dic, Default) ->
case get(Dic) of
undefined ->
Default;
Info ->
Info
end.

+ 137
- 0
src/srvNodeMgr/tools_cq/u.erl Dosyayı Görüntüle

@ -0,0 +1,137 @@
%%----------------------------------------------------
%% Erlang模块热更新到所有节点server的回调函数state有影响时慎用
%%
%% u:c() %% 5
%% u:c(N) %% N分钟内编译过的文件
%%
%% u:u() %% 5
%% u:u(N) %% N分钟内编译过的文件
%% u:u([svr_xx, ...]) %%
%% u:u(m) %%
%%
%% Tips: u - update, c - check
%%
%%----------------------------------------------------
-module(u).
-include_lib("kernel/include/file.hrl").
-include("common.hrl").
-export([
c/0,
c/1,
admin/0,
u/0,
u/1,
m/1,
info/1,
load/1
]).
c() ->
c(5).
c(S) when is_integer(S) ->
case file:list_dir(".") of
{ok, FileList} ->
Files = get_new_file(FileList, S * 60),
info("---------check modules---------~n~w~n=========check modules=========", [Files]);
Any ->
info("Error Dir: ~w", [Any])
end;
c(_) ->
info("ERROR======> Badarg", []).
admin() ->
spawn(fun() -> u(m) end),
ok.
u() ->
u(5).
u(m) ->
StartTime = time:unixtime(),
info("----------makes----------", []),
c:cd("../"),
make:all(),
c:cd("ebin"),
EndTime = time:unixtime(),
Time = EndTime - StartTime,
info("Make Time : ~w s", [Time]),
u(Time / 60);
u(S) when is_number(S) ->
case file:list_dir(".") of
{ok, FileList} ->
Files = get_new_file(FileList, util:ceil(S * 60) + 3),
AllZone = svr_node:get_all_node(),
info("---------modules---------~n~w~n----------nodes----------", [Files]),
load(Files),
loads(AllZone, Files);
Any ->
info("Error Dir: ~w", [Any])
end;
u(Files) when is_list(Files) ->
AllZone = svr_node:get_all_node(),
info("---------modules---------~n~w~n----------nodes----------", [Files]),
load(Files),
loads(AllZone, Files);
u(_) ->
info("ERROR======> Badarg", []).
%% m(['src/data/*','src/lib/lib_goods.erl'])
m(Files) when is_list(Files) ->
StartTime = time:unixtime(),
info("----------makes----------~n~w~n", [Files]),
c:cd("../"),
Res = make:files(Files, [debug_info, {i, "include"}, {outdir, "ebin"}]),
c:cd("ebin"),
EndTime = time:unixtime(),
Time = EndTime - StartTime,
info("Make Time : ~w s", [Time]),
Res.
info(V) ->
info(V, []).
info(V, P) ->
io:format(V ++ "~n", P).
%%
loads([], _Files) -> ok;
loads([H | T], Files) ->
info("[~w]", [H#node.name]),
rpc:cast(H#node.name, u, load, [Files]),
loads(T, Files).
get_new_file(Files, S) ->
get_new_file(Files, S, []).
get_new_file([], _S, Result) -> Result;
get_new_file([H | T], S, Result) ->
NewResult = case string:tokens(H, ".") of
[Left, Right] when Right =:= "beam" ->
case file:read_file_info(H) of
{ok, FileInfo} ->
Now = calendar:local_time(),
case calendar:time_difference(FileInfo#file_info.mtime, Now) of
{Days, Times} ->
Seconds = calendar:time_to_seconds(Times),
case Days =:= 0 andalso Seconds < S of
true ->
FileName = type:list_to_atom(Left),
[FileName | Result];
false -> Result
end;
_ -> Result
end;
_ -> Result
end;
_ -> Result
end,
get_new_file(T, S, NewResult).
load([]) -> ok;
load([FileName | T]) ->
c:l(FileName),
info("loaded: ~w", [FileName]),
load(T).

Yükleniyor…
İptal
Kaydet