Current section

Files

Jump to
driver8 lib driver8 session.ex
Raw

lib/driver8/session.ex

defmodule Driver8.Session do
@moduledoc false
require Logger
use GenServer
def start_link([registry, session_id, body_map] = _opts) do
GenServer.start_link(__MODULE__, [session_id, body_map],
name: registry_name(registry, session_id)
)
end
@doc """
"""
def new(supervisor, registry, opts) do
session_id = UUID.uuid1()
result =
DynamicSupervisor.start_child(supervisor, %{
id: session_id,
start: {Driver8.Session, :start_link, [[registry, session_id, opts]]},
restart: :transient
})
case result do
{:ok, _} ->
{:ok, session_id}
_ ->
{:error}
end
end
@doc """
"""
def find(registry, session_id) do
case Registry.lookup(registry, session_id) do
[{pid, _}] -> {:ok, pid}
[] -> :no_session
end
end
@doc """
Remove session with given id.
"""
def remove(registry, session_id) do
case find(registry, session_id) do
{:ok, pid} ->
Logger.info("Deleting session: #{session_id}")
GenServer.stop(pid)
:no_session ->
:no_session
end
end
def reset_timer(registry, session_id) do
case find(registry, session_id) do
{:ok, pid} ->
Logger.debug("Timer reset for session: #{session_id}")
GenServer.cast(pid, :reset_timer)
:no_session ->
Logger.warn("Trying to reset timer on invalid session #{session_id}")
end
end
@impl true
def init([session_id, body_map]) do
state =
body_map
|> Map.get("desiredCapabilities")
|> (&%{
"sessionId" => session_id,
"capabilities" => %{},
"desiredCapabilities" => &1
}).()
Logger.info("Session starting: #{session_id}")
{:ok, Map.put(state, :timeout, timeout(state))}
end
@impl true
def handle_cast(:reset_timer, %{timeout: nil} = state) do
{:noreply, state}
end
@impl true
def handle_cast(:reset_timer, %{timeout: timer_ref} = state) do
Process.cancel_timer(timer_ref)
{:noreply, %{state | timeout: timeout(state)}}
end
@impl true
def handle_info(:timeout, %{"sessionId" => session_id} = state) do
Logger.info("Session is terminating (idle timeout): #{session_id}")
{:stop, :normal, state}
end
@default_timeout 60 * 1000
defp timeout(%{"desiredCapabilities" => %{"sessionTimeout" => timeoutString}}) do
timeout = duration(timeoutString)
if timeout == 0 do
Process.send_after(self(), :timeout, @default_timeout)
else
Process.send_after(self(), :timeout, timeout)
end
end
defp timeout(_) do
Process.send_after(self(), :timeout, @default_timeout)
end
defp duration(durationString) do
captures =
Regex.named_captures(
~r/((?<hours>\d+)h)?((?<minutes>\d+)m)?((?<seconds>\d+)s)?((?<millis>\d+)[mu]s)?/,
durationString
)
millis(captures["hours"], 60 * 60 * 1000) + millis(captures["minutes"], 60 * 1000) +
millis(captures["seconds"], 1000) + millis(captures["millis"], 1)
end
defp millis(value, multiplier) do
cond do
is_nil(value) ->
0
String.length(value) === 0 ->
0
true ->
String.to_integer(value) * multiplier
end
end
defp registry_name(registry, session_id), do: {:via, Registry, {registry, session_id}}
end