Current section

Files

Jump to
slipstream lib slipstream connection state.ex
Raw

lib/slipstream/connection/state.ex

defmodule Slipstream.Connection.State do
@moduledoc false
alias Slipstream.Connection.Telemetry
# a struct for storing the internal state of a Slipstream.Connection
# process
# the module which implements the Slipstream behaviour is hereby known
# as the implementor
defstruct [
:connection_id,
:trace_id,
:client_pid,
:client_ref,
:config,
:conn,
:stream_ref,
:join_params,
:heartbeat_timer,
:heartbeat_ref,
:metadata,
status: :opened,
joins: %{},
leaves: %{},
current_ref: 0,
current_ref_str: "0"
]
@doc """
Creates a new State data structure
The life-cycle of a `Slipstream.Connection` matches that of a websocket
connection between client and remote websocket server, so a new `State`
data structure represents a new connection (and therefore generates a new
connection_id for telemetry purposes).
"""
@spec new(config :: Slipstream.Configuration.t(), client_pid :: pid()) ::
%__MODULE__{}
def new(config, client_pid) do
%__MODULE__{
config: config,
client_pid: client_pid,
client_ref: Process.monitor(client_pid),
trace_id: Telemetry.trace_id(),
connection_id: Telemetry.id()
}
end
@doc """
Gets the next ref and increments the ref counter in state
The `ref` passed between a client and phoenix server is a marker which
can be used to link pushes to their replies. E.g. a heartbeat message from
the client will include a ref which will match the associated heartbeat
reply from the server, when the heartbeat is sucessful.
Refs are simply strings of incrementing integers.
"""
def next_ref(state) do
ref = state.current_ref + 1
{to_string(ref),
%__MODULE__{state | current_ref: ref, current_ref_str: to_string(ref)}}
end
def next_heartbeat_ref(state) do
{ref, state} = next_ref(state)
%__MODULE__{state | heartbeat_ref: ref}
end
@doc """
Resets the heartbeat ref to nil
This is used to clear out a pending heartbeat. If the
`Slipstream.Commands.SendHeartbeat` command is received and the heartbeat_ref
in state is nil, that means we have not received a reply to our heartbeat
request and that the server is potentially stuck or otherwise not responding.
"""
def reset_heartbeat(state) do
%__MODULE__{state | heartbeat_ref: nil}
end
@doc """
Detects if a ref is one used to join a topic
"""
def join_ref?(%__MODULE__{joins: joins}, ref), do: ref in Map.values(joins)
@doc """
Detects if a ref was used to request a topic leave
"""
def leave_ref?(%__MODULE__{leaves: leaves}, ref),
do: ref in Map.values(leaves)
end