Skip to content

Commit

Permalink
Error when self-invoking send_frame/2
Browse files Browse the repository at this point in the history
- The error suggested returning a `:reply` tuple instead.

- Closes Azolo#34
  • Loading branch information
Azolo committed Nov 24, 2017
1 parent da1210a commit f3db7dc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
a callback. (e.g. an exception was raised)
- Properly handle unexpected SSL socket termination.
- This _seems_ pretty important, but I don't know...
- Return a descriptive error when trying to use `send_frame/2` in a callback.

## 0.4.0
### Breaking Changes
Expand Down
13 changes: 9 additions & 4 deletions lib/websockex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,15 @@ defmodule WebSockex do
error tuple with a `WebSockex.ConnError` exception struct as the second
element.
"""
@spec send_frame(client, frame) :: :ok | {:error, %WebSockex.FrameEncodeError{}
| %WebSockex.ConnError{}
| %WebSockex.NotConnectedError{}
| %WebSockex.InvalidFrameError{}}
@spec send_frame(client, frame) :: :ok |
{:error, %WebSockex.FrameEncodeError{}
| %WebSockex.ConnError{}
| %WebSockex.NotConnectedError{}
| %WebSockex.InvalidFrameError{}} |
none
def send_frame(client, _) when client == self() do
raise %WebSockex.CallingSelfError{function: :send_frame}
end
def send_frame(client, frame) do
try do
{:ok, res} = :gen.call(client, :"$websockex_send", frame)
Expand Down
15 changes: 15 additions & 0 deletions lib/websockex/errors.ex
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,18 @@ defmodule WebSockex.NotConnectedError do
"Not Connected: Currently Opening the Connection."
end
end

defmodule WebSockex.CallingSelfError do
defexception [:function]

def message(%__MODULE__{function: :send_frame}) do
"""
Process attempted to call itself.
The function send_frame/2 cannot be used inside of a callback. Instead try returning {:reply, frame, state} from the callback.
"""
end
def message(%__MODULE__{}) do
"Process attempted to call itself."
end
end
12 changes: 12 additions & 0 deletions test/websockex_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ defmodule WebSockexTest do
def handle_cast({:send, frame}, state), do: {:reply, frame, state}
def handle_cast(:close, state), do: {:close, state}
def handle_cast({:close, code, reason}, state), do: {:close, {code, reason}, state}
def handle_cast(:self_send, _) do
WebSockex.send_frame(self(), :ping)
end
def handle_cast(:delayed_close, state) do
receive do
{:tcp_closed, socket} ->
Expand Down Expand Up @@ -582,6 +585,15 @@ defmodule WebSockexTest do
{:error, %WebSockex.NotConnectedError{connection_state: :opening}}
end

test "returns a descriptive error message for trying to send a frame from self", context do
pid = context.pid
Process.flag(:trap_exit, true)
WebSockex.cast(pid, :self_send)

assert_receive {:EXIT, ^pid, {%WebSockex.CallingSelfError{} = error, _}}
assert Exception.message(error) =~ "try returning {:reply, frame, state} from the callback"
end

test "returns an error while closing", %{pid: pid} = context do
Process.flag(:trap_exit, true)
send(context.server_pid, :stall)
Expand Down

0 comments on commit f3db7dc

Please sign in to comment.