Packages
sippet
1.0.14
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
An Elixir Session Initiation Protocol (SIP) stack.
Current section
Files
Jump to
Current section
Files
lib/sippet/transactions/client/non_invite.ex
defmodule Sippet.Transactions.Client.NonInvite do
@moduledoc false
use Sippet.Transactions.Client, initial_state: :trying
import Map, only: [put: 3, delete: 2]
import Process, only: [send_after: 3, cancel_timer: 1]
alias Sippet.Message.StatusLine
alias Sippet.Transactions.Client.State
require Logger
@t2 4_000
@timer_e 500
@timer_f 64 * @timer_e
# timer K is 5s
@timer_k 5_000
defp start_timers(%State{request: request, extras: extras} = data) do
extras =
extras
|> put(:deadline_timer, send_after(self(), :deadline, @timer_f))
extras =
if reliable?(request, data) do
extras
else
extras
|> put(:retry_timer, send_after(self(), @timer_e, @timer_e))
end
%{data | extras: extras}
end
defp cancel_timers(%State{extras: extras} = data) do
extras =
case extras do
%{deadline_timer: deadline_timer} ->
cancel_timer(deadline_timer)
extras
|> delete(:deadline_timer)
_ ->
extras
end
extras =
case extras do
%{retry_timer: retry_timer} ->
cancel_timer(retry_timer)
extras
|> delete(:retry_timer)
_ ->
extras
end
%{data | extras: extras}
end
defp retry(next_wait, %State{request: request, extras: extras} = data) do
send_request(request, data)
extras =
extras
|> put(:retry_timer, send_after(self(), next_wait, next_wait))
{:keep_state, %{data | extras: extras}}
end
def trying(:enter, _old_state, %State{request: request} = data) do
send_request(request, data)
{:keep_state, start_timers(data)}
end
def trying(:info, :deadline, data),
do: timeout(data)
def trying(:info, last_delay, data) when is_integer(last_delay),
do: retry(min(last_delay * 2, @t2), data)
def trying(:cast, {:incoming_response, response}, data) do
receive_response(response, data)
case StatusLine.status_code_class(response.start_line) do
1 -> {:next_state, :proceeding, data}
_ -> {:next_state, :completed, data}
end
end
def trying(:cast, {:error, reason}, data),
do: shutdown(reason, data)
def trying(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
def proceeding(:enter, _old_state, _data),
do: :keep_state_and_data
def proceeding(:info, :deadline, data),
do: timeout(data)
def proceeding(:info, last_delay, data) when is_integer(last_delay),
do: retry(@t2, data)
def proceeding(:cast, {:incoming_response, response}, data) do
receive_response(response, data)
case StatusLine.status_code_class(response.start_line) do
1 -> {:keep_state, data}
_ -> {:next_state, :completed, data}
end
end
def proceeding(:cast, {:error, reason}, data),
do: shutdown(reason, data)
def proceeding(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
def completed(:enter, _old_state, %State{request: request} = data) do
data = cancel_timers(data)
if reliable?(request, data) do
{:stop, :normal, data}
else
{:keep_state, data, [{:state_timeout, @timer_k, nil}]}
end
end
def completed(:state_timeout, _nil, data),
do: {:stop, :normal, data}
def completed(:cast, {:incoming_response, _response}, _data),
do: :keep_state_and_data
def completed(:cast, {:error, _reason}, _data),
do: :keep_state_and_data
def completed(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
end