Current section
Files
Jump to
Current section
Files
src/esockd_keepalive.erl
%% Copyright (c) 2019 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% copy emqx/src/emqx_keepalive here.
-module(esockd_keepalive).
-export([start/3, check/1, cancel/1]).
-record(keepalive, {statfun, statval, tsec, tmsg, tref, repeat = 0}).
-type(keepalive() :: #keepalive{}).
-export_type([keepalive/0]).
%% @doc Start a keepalive
-spec(start(fun(), integer(), any()) -> {ok, keepalive()} | {error, term()}).
start(_, 0, _) ->
{ok, #keepalive{}};
start(StatFun, TimeoutSec, TimeoutMsg) ->
try StatFun() of
{ok, StatVal} ->
{ok, #keepalive{statfun = StatFun, statval = StatVal, tsec = TimeoutSec,
tmsg = TimeoutMsg, tref = timer(TimeoutSec, TimeoutMsg)}};
{error, Error} ->
{error, Error}
catch
error:Reason ->
{error, Reason}
end.
%% @doc Check keepalive, called when timeout...
-spec(check(keepalive()) -> {ok, keepalive()} | {error, term()}).
check(KeepAlive = #keepalive{statfun = StatFun, statval = LastVal, repeat = Repeat}) ->
try StatFun() of
{ok, NewVal} ->
if
NewVal =/= LastVal ->
{ok, resume(KeepAlive#keepalive{statval = NewVal, repeat = 0})};
Repeat < 1 ->
{ok, resume(KeepAlive#keepalive{statval = NewVal, repeat = Repeat + 1})};
true -> {error, timeout}
end;
{error, Error} ->
{error, Error}
catch
error:Reason ->
{error, Reason}
end.
-spec(resume(keepalive()) -> keepalive()).
resume(KeepAlive = #keepalive{tsec = TimeoutSec, tmsg = TimeoutMsg}) ->
KeepAlive#keepalive{tref = timer(TimeoutSec, TimeoutMsg)}.
%% @doc Cancel Keepalive
-spec(cancel(keepalive()) -> ok).
cancel(#keepalive{tref = TRef}) when is_reference(TRef) ->
catch erlang:cancel_timer(TRef), ok;
cancel(_) ->
ok.
timer(Secs, Msg) ->
erlang:send_after(timer:seconds(Secs), self(), Msg).