Skip to content

Commit

Permalink
add ChannelClosed clauses for newly seen failure-cases (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
the-mikedavis authored Feb 1, 2021
1 parent 4b4b962 commit 3e0ea4b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 22 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.2.1 - 2021-02-01

### Fixed

- Connection now correctly emits ChannelClosed events for `:gun` events which
occur when a service's network access is terminated

## 0.2.0 - 2021-02-01

### Added
Expand Down
46 changes: 24 additions & 22 deletions lib/slipstream/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,37 +61,25 @@ defmodule Slipstream.Connection do
end

def handle_info(
{:gun_down, conn, :ws, :closed, [], []},
{:gun_down, conn, :ws, :closed, _refs, []},
%State{conn: conn} = state
) do
event = %Events.ChannelClosed{reason: :closed_by_remote}
emit_channel_closed(:closed_by_remote, state)
end

# if we're already terminating, no need to duplicate the channel_closed
# event
if state.status == :terminating do
{:noreply, state}
else
state
|> State.apply_event(event)
|> Impl.handle_event(event)
end
def handle_info(
{:gun_error, conn, {:websocket, stream_ref, _, _, _},
{:closed, 'The connection was lost.'}},
%State{conn: conn, stream_ref: stream_ref} = state
) do
emit_channel_closed(:connection_lost, state)
end

def handle_info(
{:gun_ws, conn, stream_ref, {:close, _, _}},
%State{conn: conn, stream_ref: stream_ref} = state
) do
event = %Events.ChannelClosed{reason: :closed_by_remote}

# if we're already terminating, no need to duplicate the channel_closed
# event
if state.status == :terminating do
{:noreply, state}
else
state
|> State.apply_event(event)
|> Impl.handle_event(event)
end
emit_channel_closed(:closed_by_remote, state)
end

# coveralls-ignore-start
Expand Down Expand Up @@ -160,4 +148,18 @@ defmodule Slipstream.Connection do
|> State.apply_command(cmd)
|> Impl.handle_command(cmd)
end

defp emit_channel_closed(reason, state) do
event = %Events.ChannelClosed{reason: reason}

# if we're already terminating, no need to duplicate the channel_closed
# event
if state.status == :terminating do
{:noreply, state}
else
state
|> State.apply_event(event)
|> Impl.handle_event(event)
end
end
end
21 changes: 21 additions & 0 deletions test/slipstream/connection_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,27 @@ defmodule Slipstream.ConnectionTest do
refute c.socket |> await_disconnect!() |> connected?
end

# e.g. your networking interface shuts down
test """
when the remote websocket connection is lost,
then the socket is notified that the connection has been terminated
and the connection is closed
""",
c do
conn = c.conn

@gun |> expect(:close, 1, fn ^conn -> :ok end)

send(
c.socket.channel_pid,
{:gun_error, c.conn,
{:websocket, c.stream_ref, "VFeeglQh/qqSFe9rqSM5FQ==", [], %{}},
{:closed, 'The connection was lost.'}}
)

refute c.socket |> await_disconnect!() |> connected?
end

test "when the connection receives a ping, then it responds with pong", c do
conn = c.conn

Expand Down

0 comments on commit 3e0ea4b

Please sign in to comment.