@ -1,124 +0,0 @@ | |||||
%%%----------------------------------- | |||||
%%% @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. |
@ -1,202 +0,0 @@ | |||||
%%%----------------------------------- | |||||
%%% @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. |
@ -1,24 +0,0 @@ | |||||
%%%----------------------------------- | |||||
%%% @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)). |
@ -1,332 +0,0 @@ | |||||
-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. | |||||
%%获取节点1的id | |||||
get_domain() -> | |||||
case application:get_env(server, domain) of | |||||
{ok, N} -> | |||||
N; | |||||
_ -> | |||||
1 | |||||
end. | |||||
%%获取节点2的id | |||||
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. |
@ -1,270 +0,0 @@ | |||||
%% 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. |
@ -1,41 +0,0 @@ | |||||
%%%---------------------------------------- | |||||
%%% @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}. |
@ -1,131 +0,0 @@ | |||||
%%%---------------------------------------------------------------------- | |||||
%%% 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 | |||||
%% -------------------------------------------------------------------- |
@ -1,238 +0,0 @@ | |||||
%%%---------------------------------------------------------------------- | |||||
%%% 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). % 1小时新开1个log文件 | |||||
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. |
@ -1,114 +0,0 @@ | |||||
%%%---------------------------------------------------------------------- | |||||
%%% 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). | |||||
". |