-module(esSyncSrv). -behaviour(es_gen_ipc). -include("eSync.hrl"). -compile(inline). -compile({inline_size, 128}). %% API -export([ start_link/0, rescan/0, pause/0, unpause/0, setLog/1, getLog/0, curInfo/0, getOnsync/0, setOnsync/1, swSyncNode/1 ]). %% es_gen_ipc callbacks -export([ init/1, handleCall/4, handleAfter/3, handleCast/3, handleInfo/3, handleOnevent/4, terminate/3 ]). -define(SERVER, ?MODULE). -define(None, 0). -record(state, { srcFiles = #{} :: map() , onsyncFun = undefined , swSyncNode = false , sockMod = undefined , sock = undefined }). %% ************************************ API start *************************** rescan() -> es_gen_ipc:cast(?SERVER, miRescan), esUtils:logSuccess("start rescaning source files..."), ok. unpause() -> es_gen_ipc:cast(?SERVER, miUnpause), ok. pause() -> es_gen_ipc:cast(?SERVER, miPause), esUtils:logSuccess("Pausing eSync. Call eSync:run() to restart"), ok. curInfo() -> es_gen_ipc:call(?SERVER, miCurInfo). setLog(T) when ?LOG_ON(T) -> esUtils:setEnv(log, T), esUtils:loadCfg(), esUtils:logSuccess("Console Notifications Enabled"), ok; setLog(_) -> esUtils:setEnv(log, none), esUtils:loadCfg(), esUtils:logSuccess("Console Notifications Disabled"), ok. getLog() -> ?esCfgSync:getv(log). swSyncNode(IsSync) -> es_gen_ipc:cast(?SERVER, {miSyncNode, IsSync}), ok. getOnsync() -> es_gen_ipc:call(?SERVER, miGetOnsync). setOnsync(Fun) -> es_gen_ipc:call(?SERVER, {miSetOnsync, Fun}). %% ************************************ API end *************************** start_link() -> es_gen_ipc:start_link({local, ?SERVER}, ?MODULE, ?None, []). %% status :: waiting | running | pause init(_Args) -> erlang:process_flag(trap_exit, true), esUtils:loadCfg(), {ok, waiting, #state{}, {doAfter, ?None}}. handleAfter(?None, waiting, State) -> %% 启动tcp 异步监听 然后启动文件同步应用 启动定时器 等待建立连接 超时 就表示文件同步应用启动失败了 报错 ListenPort = ?esCfgSync:getv(?listenPort), case gen_tcp:listen(ListenPort, ?TCP_DEFAULT_OPTIONS) of {ok, LSock} -> case prim_inet:async_accept(LSock, -1) of {ok, _Ref} -> {ok, SockMod} = inet_db:lookup_socket(LSock), spawn(fun() -> case os:type() of {win32, _Osname} -> CmtStr = "start " ++ esUtils:fileSyncPath("fileSync.exe") ++ " ./ " ++ integer_to_list(ListenPort), CmdRet = os:cmd(CmtStr), RetMsg = io_lib:format("the os:cmd start fileSync CmtStr:~p ret:~p ~n ", [CmtStr, CmdRet]), esUtils:logErrors(RetMsg); _ -> CmtStr = esUtils:fileSyncPath("fileSync") ++ " ./ " ++ integer_to_list(ListenPort), CmdRet = os:cmd(CmtStr), RetMsg = io_lib:format("the os:cmd start fileSync CmtStr:~p ret:~p ~n ", [CmtStr, CmdRet]), esUtils:logErrors(RetMsg) end end), {kpS, State#state{sockMod = SockMod}, {sTimeout, 4000, waitConnOver}}; {error, Reason} -> Msg = io_lib:format("init prim_inet:async_accept error ~p~n", [Reason]), esUtils:logErrors(Msg), {kpS, State, {sTimeout, 2000, waitConnOver}} end; {error, Reason} -> Msg = io_lib:format("failed to listen on ~p - ~p (~s) ~n", [ListenPort, Reason, inet:format_error(Reason)]), esUtils:logErrors(Msg), {kpS, State, {sTimeout, 2000, waitConnOver}} end. handleCall(miGetOnsync, _, #state{onsyncFun = OnSync} = State, _From) -> {reply, OnSync, State}; handleCall({miSetOnsync, Fun}, _, State, _From) -> {reply, ok, State#state{onsyncFun = Fun}}; handleCall(miCurInfo, _, State, _Form) -> {reply, {erlang:get(), State}, State}; handleCall(_Request, _, _State, _From) -> kpS_S. handleCast(miPause, running, State) -> {nextS, pause, State}; handleCast(miUnpause, pause, State) -> {nextS, running, State}; handleCast({miSyncNode, IsSync}, _, State) -> case IsSync of true -> {kpS, State#state{swSyncNode = true}}; _ -> {kpS, State#state{swSyncNode = false}} end; handleCast(miRescan, _, State) -> SrcFiles = esUtils:collSrcFiles(false), {kpS_S, State#state{srcFiles = SrcFiles}}; handleCast(_Msg, _, _State) -> kpS_S. handleInfo({tcp, _Socket, Data}, running, #state{srcFiles = SrcFiles, onsyncFun = OnsyncFun, swSyncNode = SwSyncNode} = State) -> FileList = binary:split(Data, <<"\r\n">>, [global]), %% 收集改动了beam hrl src 文件 然后执行相应的逻辑 {Beams, Hrls, Srcs} = esUtils:classifyChangeFile(FileList, [], [], []), esUtils:reloadChangedMod(Beams, SwSyncNode, OnsyncFun, []), case ?esCfgSync:getv(?compileCmd) of undefined -> esUtils:recompileChangeHrlFile(Hrls, SrcFiles, SwSyncNode), esUtils:recompileChangeSrcFile(Srcs, SwSyncNode), NewSrcFiles = esUtils:addNewFile(Srcs, SrcFiles), {kpS, State#state{srcFiles = NewSrcFiles}}; CmdStr -> case Srcs =/= [] orelse Hrls =/= [] of true -> RetStr = os:cmd(CmdStr), RetList = string:split(RetStr, "\n", all), CmdMsg = io_lib:format("compile cmd:~p ~n", [CmdStr]), esUtils:logSuccess(CmdMsg), RetMsg = io_lib:format("the result: ~n ", []), esUtils:logSuccess(RetMsg), [ begin OneMsg = io_lib:format("~p ~n", [OneRet]), esUtils:logSuccess(OneMsg) end || OneRet <- RetList, OneRet =/= [] ], ok; _ -> ignore end, kpS_S end; handleInfo({inet_async, LSock, _Ref, Msg}, _, #state{sockMod = SockMod} = State) -> case Msg of {ok, Sock} -> %% make it look like gen_tcp:accept inet_db:register_socket(Sock, SockMod), inet:setopts(Sock, [{active, true}]), prim_inet:async_accept(LSock, -1), %% 建立了连接 先发送监听目录配置 {AddSrcDirs, OnlySrcDirs, DelSrcDirs} = esUtils:mergeExtraDirs(false), AddStr = string:join([filename:nativename(OneDir) || OneDir <- AddSrcDirs], "|"), OnlyStr = string:join([filename:nativename(OneDir) || OneDir <- OnlySrcDirs], "|"), DelStr = string:join([filename:nativename(OneDir) || OneDir <- DelSrcDirs], "|"), AllStr = string:join([AddStr, OnlyStr, DelStr], "\r\n"), gen_tcp:send(Sock, AllStr), esUtils:logSuccess("eSync connect fileSync success..."), case ?esCfgSync:getv(?compileCmd) of undefined -> %% 然后收集一下监听目录下的src文件 SrcFiles = esUtils:collSrcFiles(true), {nextS, running, State#state{sock = Sock, srcFiles = SrcFiles}}; _ -> {nextS, running, State} end; {error, closed} -> Msg = io_lib:format("error, closed listen sock error ~p~n", [closed]), esUtils:logErrors(Msg), {stop, normal}; {error, Reason} -> Msg = io_lib:format("listen sock error ~p~n", [Reason]), esUtils:logErrors(Msg), {stop, {lsock, Reason}} end; handleInfo({tcp_closed, _Socket}, running, _State) -> Msg = io_lib:format("esSyncSrv receive tcp_closed ~n", []), esUtils:logErrors(Msg), kpS_S; handleInfo({tcp_error, _Socket, Reason}, running, _State) -> Msg = io_lib:format("esSyncSrv receive tcp_error Reason:~p ~n", [Reason]), esUtils:logErrors(Msg), kpS_S; handleInfo(_Msg, _, _State) -> Msg = io_lib:format("esSyncSrv receive unexpect msg:~p ~n", [_Msg]), esUtils:logErrors(Msg), kpS_S. handleOnevent(sTimeout, waitConnOver, Status, State) -> Msg = io_lib:format("failed to connect the fileSync to stop stauts:~p state:~p ~n", [Status, State]), esUtils:logErrors(Msg), stop; handleOnevent(_EventType, _EventContent, _Status, _State) -> kpS_S. terminate(_Reason, _Status, _State) -> ok.