Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Dialyxir and fix all warnings #27

Merged
merged 15 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
lint: true
coverage: true
report: true
dialyzer: true
- erlang: "24.3"
elixir: "1.12"
- erlang: "23.3.1"
Expand Down Expand Up @@ -65,6 +66,26 @@ jobs:
run: mix compile --warnings-as-errors
if: ${{ matrix.lint }}

- name: Restore cached PLTs
uses: actions/cache@v3
id: plt_cache
with:
key: |
${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.erlang }}-plt
restore-keys: |
${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.erlang }}-plt
path: |
priv/plts

# Create PLTs if no cached PLTs were found
- name: Create PLTs
if: steps.plt_cache.outputs.cache-hit != 'true'
run: MIX_ENV=test mix dialyzer --plt

- name: Run dialyzer
run: MIX_ENV=test mix dialyzer
if: ${{ matrix.dialyzer }}

- name: Run tests with coverage
run: mix coveralls.github
if: ${{ matrix.coverage }}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ mint_web_socket-*.tar

# Temporary files for e.g. tests
/tmp

# Dialyzer PLTs
/priv/plts/*.plt
/priv/plts/*.plt.hash
16 changes: 8 additions & 8 deletions lib/mint/web_socket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ defmodule Mint.WebSocket do

alias __MODULE__.{Utils, Extension, Frame}
alias Mint.{WebSocketError, WebSocket.UpgradeFailureError}
alias Mint.{HTTP1, HTTP2}
the-mikedavis marked this conversation as resolved.
Show resolved Hide resolved
import Mint.HTTP, only: [get_private: 2, put_private: 3, protocol: 1]

@typedoc """
Expand Down Expand Up @@ -267,11 +266,12 @@ defmodule Mint.WebSocket do

headers = Utils.headers({:http1, nonce}, extensions) ++ headers

Mint.HTTP1.request(conn, "GET", path, headers, nil)
Mint.HTTP.request(conn, "GET", path, headers, nil)
end

@dialyzer {:no_opaque, do_upgrade: 6}
defp do_upgrade(scheme, :http2, conn, path, headers, opts) do
if HTTP2.get_server_setting(conn, :enable_connect_protocol) == true do
if Mint.HTTP2.get_server_setting(conn, :enable_connect_protocol) == true do
extensions = get_extensions(opts)
conn = put_private(conn, :extensions, extensions)

Expand Down Expand Up @@ -395,23 +395,23 @@ defmodule Mint.WebSocket do
# we take manual control of the :gen_tcp and :ssl messages in HTTP/1 because
# we have taken over the transport
defp stream_http1(conn, request_ref, message) do
socket = HTTP1.get_socket(conn)
socket = Mint.HTTP.get_socket(conn)
tag = if get_private(conn, :scheme) == :ws, do: :tcp, else: :ssl

case message do
{^tag, ^socket, data} ->
reset_mode(conn, [{:data, request_ref, data}])

_ ->
HTTP1.stream(conn, message)
Mint.HTTP.stream(conn, message)
end
end

defp reset_mode(conn, responses) do
module = if get_private(conn, :scheme) == :ws, do: :inet, else: :ssl

with :active <- get_private(conn, :mode),
{:error, reason} <- module.setopts(HTTP1.get_socket(conn), active: :once) do
{:error, reason} <- module.setopts(Mint.HTTP.get_socket(conn), active: :once) do
{:error, conn, %Mint.TransportError{reason: reason}, responses}
else
_ -> {:ok, conn, responses}
Expand Down Expand Up @@ -448,7 +448,7 @@ defmodule Mint.WebSocket do

defp recv_http1(conn, request_ref, byte_count, timeout) do
module = if get_private(conn, :scheme) == :ws, do: :gen_tcp, else: :ssl
socket = HTTP1.get_socket(conn)
socket = Mint.HTTP.get_socket(conn)

case module.recv(socket, byte_count, timeout) do
{:ok, data} ->
Expand Down Expand Up @@ -498,7 +498,7 @@ defmodule Mint.WebSocket do
defp stream_request_body_http1(conn, data) do
transport = if get_private(conn, :scheme) == :ws, do: :gen_tcp, else: :ssl

case transport.send(Mint.HTTP1.get_socket(conn), data) do
case transport.send(Mint.HTTP.get_socket(conn), data) do
:ok -> {:ok, conn}
{:error, reason} -> {:error, conn, %Mint.TransportError{reason: reason}}
end
Expand Down
4 changes: 2 additions & 2 deletions lib/mint/web_socket/extension.ex
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ defmodule Mint.WebSocket.Extension do
defstruct [:name, :module, :state, opts: [], params: []]

@doc false
@spec encode(tuple(), [t()]) :: {:ok, tuple(), [t()]} | {:error, term()}
@spec encode(tuple(), [t()]) :: {tuple(), [t()]} | no_return()
def encode(frame, extensions) do
encode_all_extensions(frame, extensions, [])
end
Expand All @@ -180,7 +180,7 @@ defmodule Mint.WebSocket.Extension do
end

@doc false
@spec decode(tuple(), [t()]) :: {:ok, tuple(), [t()]} | {:error, term()}
@spec decode(tuple(), [t()]) :: {tuple(), [t()]} | {{:error, term()}, [t()]}
def decode(frame, extensions) do
decode_all_extensions(frame, extensions, [])
end
Expand Down
39 changes: 37 additions & 2 deletions lib/mint/web_socket/frame.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,39 @@ defmodule Mint.WebSocket.Frame do
defrecord :ping, shared
defrecord :pong, shared

@typep continuation_frame() ::
record(:continuation,
reserved: <<_::3>>,
mask: binary(),
data: binary(),
fin?: boolean()
)
@type text_frame() ::
record(:text, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
@type binary_frame() ::
record(:binary, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
@type close_frame() ::
record(:close,
reserved: <<_::3>>,
mask: binary(),
data: binary(),
fin?: boolean(),
code: binary(),
reason: binary()
)
@type ping_frame() ::
record(:ping, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
@type pong_frame() ::
record(:pong, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())

@type frame_record() ::
continuation_frame()
| text_frame()
| binary_frame()
| close_frame()
| ping_frame()
| pong_frame()

defguard is_control(frame)
when is_tuple(frame) and
(elem(frame, 0) == :close or elem(frame, 0) == :ping or elem(frame, 0) == :pong)
Expand Down Expand Up @@ -60,6 +93,9 @@ defmodule Mint.WebSocket.Frame do

def new_mask, do: :crypto.strong_rand_bytes(4)

@spec encode(Mint.WebSocket.t(), Mint.WebSocket.frame()) ::
{:ok, Mint.WebSocket.t(), bitstring()}
| {:error, Mint.WebSocket.t(), WebSocketError.t()}
def encode(websocket, frame) when is_friendly_frame(frame) do
{frame, extensions} =
frame
Expand All @@ -74,7 +110,7 @@ defmodule Mint.WebSocket.Frame do
:throw, {:mint, reason} -> {:error, websocket, reason}
end

@spec encode_to_binary(tuple()) :: binary()
@spec encode_to_binary(frame_record()) :: bitstring()
defp encode_to_binary(frame) do
payload = payload(frame)
mask = mask(frame)
Expand Down Expand Up @@ -340,7 +376,6 @@ defmodule Mint.WebSocket.Frame do
# translate from user-friendly tuple into record defined in this module
# (and the reverse)
@spec translate(Mint.WebSocket.frame() | Mint.WebSocket.shorthand_frame()) :: tuple()
@spec translate(tuple) :: Mint.WebSocket.frame()
for opcode <- Map.keys(@opcodes) do
def translate(unquote(opcode)(reserved: <<reserved::bitstring>>))
when reserved != <<0::size(3)>> do
Expand Down
4 changes: 4 additions & 0 deletions lib/mint/web_socket/upgrade_failure_error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Mint.WebSocket.UpgradeFailureError do
An error representing a failure to upgrade protocols from HTTP to WebSocket
"""

@type t() :: %__MODULE__{
status_code: Mint.Types.status(),
headers: [Mint.Types.headers()]
}
defexception [:status_code, :headers]

def message(%__MODULE__{} = error) do
Expand Down
7 changes: 6 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ defmodule MintWebSocket.MixProject do
"coveralls.github": :test,
docs: :dev
],
dialyzer: [
plt_local_path: "priv/plts",
plt_add_apps: [:mix]
],
package: package(),
description: description(),
source_url: @source_url,
Expand All @@ -41,7 +45,8 @@ defmodule MintWebSocket.MixProject do
{:jason, ">= 0.0.0", only: [:dev, :test]},
{:cowboy, "~> 2.9", only: [:test]},
{:gun, "== 2.0.0-rc.2", only: [:test]},
{:excoveralls, "~> 0.14", only: [:test]}
{:excoveralls, "~> 0.14", only: [:test]},
{:dialyxir, "~> 1.2", only: [:dev, :test], runtime: false}
]
end

Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"},
"excoveralls": {:hex, :excoveralls, "0.14.4", "295498f1ae47bdc6dce59af9a585c381e1aefc63298d48172efaaa90c3d251db", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e3ab02f2df4c1c7a519728a6f0a747e71d7d6e846020aae338173619217931c1"},
"gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"},
Expand Down
22 changes: 14 additions & 8 deletions test/fixtures/autobahn_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule AutobahnClient do
defstruct [:conn, :websocket, :ref, messages: [], next: :cont, sent_close?: false, buffer: <<>>]

defguardp is_close_frame(frame)
when frame == :close or (is_tuple(frame) and elem(frame, 0) == :close)
when is_tuple(frame) and elem(frame, 0) == :close

def get_case_count do
%{messages: [{:text, count} | _]} = connect("/getCaseCount") |> decode_buffer()
Expand Down Expand Up @@ -149,18 +149,24 @@ defmodule AutobahnClient do
def send(state, frame) do
Logger.debug("Sending #{inspect(frame, printable_limit: 30)}")

with {:ok, %Mint.WebSocket{} = websocket, data} <-
Mint.WebSocket.encode(state.websocket, frame),
{:ok, conn} <- Mint.WebSocket.stream_request_body(state.conn, state.ref, data) do
Logger.debug("Sent.")
%__MODULE__{state | conn: conn, websocket: websocket, sent_close?: is_close_frame(frame)}
else
{:error, %Mint.WebSocket{} = websocket, reason} ->
case Mint.WebSocket.encode(state.websocket, frame) do
{:ok, websocket, data} ->
do_send(put_in(state.websocket, websocket), frame, data)

{:error, websocket, reason} ->
Logger.debug(
"Could not send frame #{inspect(frame, printable_limit: 30)} because #{inspect(reason)}, sending close..."
)

send(put_in(state.websocket, websocket), {:close, 1002, ""})
end
end

defp do_send(state, frame, data) do
case Mint.WebSocket.stream_request_body(state.conn, state.ref, data) do
{:ok, conn} ->
Logger.debug("Sent.")
%__MODULE__{state | conn: conn, sent_close?: is_close_frame(frame)}

{:error, conn, %Mint.TransportError{reason: :closed}} ->
Logger.debug(
Expand Down
8 changes: 1 addition & 7 deletions test/fixtures/test_server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ defmodule TestServer do
A supervisor for the WebsocketHandler
"""

use Supervisor

def start_link(_opts) do
def start() do
dispatch =
:cowboy_router.compile([
{:_,
Expand All @@ -21,9 +19,5 @@ defmodule TestServer do
env: %{dispatch: dispatch},
enable_connect_protocol: true
})

Supervisor.start_link([], strategy: :one_for_one)
end

def init(_opts), do: {:ok, nil}
end
3 changes: 1 addition & 2 deletions test/mint/web_socket_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ defmodule Mint.WebSocketTest do
alias Mint.{HTTP1, HTTP2, WebSocket, WebSocket.UpgradeFailureError}

setup_all do
# a cowboy test server used by the HTTP/2 tests
start_supervised!(TestServer)
TestServer.start()
:ok
end

Expand Down