Skip to content

Commit e76205e

Browse files
authored
Add Dialyxir and fix all warnings (#27)
1 parent 4fbd3f5 commit e76205e

File tree

11 files changed

+100
-30
lines changed

11 files changed

+100
-30
lines changed

.github/workflows/main.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
lint: true
1919
coverage: true
2020
report: true
21+
dialyzer: true
2122
- erlang: "24.3"
2223
elixir: "1.12"
2324
- erlang: "23.3.1"
@@ -65,6 +66,26 @@ jobs:
6566
run: mix compile --warnings-as-errors
6667
if: ${{ matrix.lint }}
6768

69+
- name: Restore cached PLTs
70+
uses: actions/cache@v3
71+
id: plt_cache
72+
with:
73+
key: |
74+
${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.erlang }}-plt
75+
restore-keys: |
76+
${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.erlang }}-plt
77+
path: |
78+
priv/plts
79+
80+
# Create PLTs if no cached PLTs were found
81+
- name: Create PLTs
82+
if: steps.plt_cache.outputs.cache-hit != 'true'
83+
run: MIX_ENV=test mix dialyzer --plt
84+
85+
- name: Run dialyzer
86+
run: MIX_ENV=test mix dialyzer
87+
if: ${{ matrix.dialyzer }}
88+
6889
- name: Run tests with coverage
6990
run: mix coveralls.github
7091
if: ${{ matrix.coverage }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ mint_web_socket-*.tar
2525

2626
# Temporary files for e.g. tests
2727
/tmp
28+
29+
# Dialyzer PLTs
30+
/priv/plts/*.plt
31+
/priv/plts/*.plt.hash

lib/mint/web_socket.ex

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ defmodule Mint.WebSocket do
112112

113113
alias __MODULE__.{Utils, Extension, Frame}
114114
alias Mint.{WebSocketError, WebSocket.UpgradeFailureError}
115-
alias Mint.{HTTP1, HTTP2}
116115
import Mint.HTTP, only: [get_private: 2, put_private: 3, protocol: 1]
117116

118117
@typedoc """
@@ -267,11 +266,12 @@ defmodule Mint.WebSocket do
267266

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

270-
Mint.HTTP1.request(conn, "GET", path, headers, nil)
269+
Mint.HTTP.request(conn, "GET", path, headers, nil)
271270
end
272271

272+
@dialyzer {:no_opaque, do_upgrade: 6}
273273
defp do_upgrade(scheme, :http2, conn, path, headers, opts) do
274-
if HTTP2.get_server_setting(conn, :enable_connect_protocol) == true do
274+
if Mint.HTTP2.get_server_setting(conn, :enable_connect_protocol) == true do
275275
extensions = get_extensions(opts)
276276
conn = put_private(conn, :extensions, extensions)
277277

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

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

405405
_ ->
406-
HTTP1.stream(conn, message)
406+
Mint.HTTP.stream(conn, message)
407407
end
408408
end
409409

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

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

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

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

501-
case transport.send(Mint.HTTP1.get_socket(conn), data) do
501+
case transport.send(Mint.HTTP.get_socket(conn), data) do
502502
:ok -> {:ok, conn}
503503
{:error, reason} -> {:error, conn, %Mint.TransportError{reason: reason}}
504504
end

lib/mint/web_socket/extension.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ defmodule Mint.WebSocket.Extension do
156156
defstruct [:name, :module, :state, opts: [], params: []]
157157

158158
@doc false
159-
@spec encode(tuple(), [t()]) :: {:ok, tuple(), [t()]} | {:error, term()}
159+
@spec encode(tuple(), [t()]) :: {tuple(), [t()]} | no_return()
160160
def encode(frame, extensions) do
161161
encode_all_extensions(frame, extensions, [])
162162
end
@@ -180,7 +180,7 @@ defmodule Mint.WebSocket.Extension do
180180
end
181181

182182
@doc false
183-
@spec decode(tuple(), [t()]) :: {:ok, tuple(), [t()]} | {:error, term()}
183+
@spec decode(tuple(), [t()]) :: {tuple(), [t()]} | {{:error, term()}, [t()]}
184184
def decode(frame, extensions) do
185185
decode_all_extensions(frame, extensions, [])
186186
end

lib/mint/web_socket/frame.ex

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,39 @@ defmodule Mint.WebSocket.Frame do
2121
defrecord :ping, shared
2222
defrecord :pong, shared
2323

24+
@typep continuation_frame() ::
25+
record(:continuation,
26+
reserved: <<_::3>>,
27+
mask: binary(),
28+
data: binary(),
29+
fin?: boolean()
30+
)
31+
@type text_frame() ::
32+
record(:text, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
33+
@type binary_frame() ::
34+
record(:binary, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
35+
@type close_frame() ::
36+
record(:close,
37+
reserved: <<_::3>>,
38+
mask: binary(),
39+
data: binary(),
40+
fin?: boolean(),
41+
code: binary(),
42+
reason: binary()
43+
)
44+
@type ping_frame() ::
45+
record(:ping, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
46+
@type pong_frame() ::
47+
record(:pong, reserved: <<_::3>>, mask: binary(), data: binary(), fin?: boolean())
48+
49+
@type frame_record() ::
50+
continuation_frame()
51+
| text_frame()
52+
| binary_frame()
53+
| close_frame()
54+
| ping_frame()
55+
| pong_frame()
56+
2457
defguard is_control(frame)
2558
when is_tuple(frame) and
2659
(elem(frame, 0) == :close or elem(frame, 0) == :ping or elem(frame, 0) == :pong)
@@ -60,6 +93,9 @@ defmodule Mint.WebSocket.Frame do
6093

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

96+
@spec encode(Mint.WebSocket.t(), Mint.WebSocket.frame()) ::
97+
{:ok, Mint.WebSocket.t(), bitstring()}
98+
| {:error, Mint.WebSocket.t(), WebSocketError.t()}
6399
def encode(websocket, frame) when is_friendly_frame(frame) do
64100
{frame, extensions} =
65101
frame
@@ -74,7 +110,7 @@ defmodule Mint.WebSocket.Frame do
74110
:throw, {:mint, reason} -> {:error, websocket, reason}
75111
end
76112

77-
@spec encode_to_binary(tuple()) :: binary()
113+
@spec encode_to_binary(frame_record()) :: bitstring()
78114
defp encode_to_binary(frame) do
79115
payload = payload(frame)
80116
mask = mask(frame)
@@ -340,7 +376,6 @@ defmodule Mint.WebSocket.Frame do
340376
# translate from user-friendly tuple into record defined in this module
341377
# (and the reverse)
342378
@spec translate(Mint.WebSocket.frame() | Mint.WebSocket.shorthand_frame()) :: tuple()
343-
@spec translate(tuple) :: Mint.WebSocket.frame()
344379
for opcode <- Map.keys(@opcodes) do
345380
def translate(unquote(opcode)(reserved: <<reserved::bitstring>>))
346381
when reserved != <<0::size(3)>> do

lib/mint/web_socket/upgrade_failure_error.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ defmodule Mint.WebSocket.UpgradeFailureError do
33
An error representing a failure to upgrade protocols from HTTP to WebSocket
44
"""
55

6+
@type t() :: %__MODULE__{
7+
status_code: Mint.Types.status(),
8+
headers: [Mint.Types.headers()]
9+
}
610
defexception [:status_code, :headers]
711

812
def message(%__MODULE__{} = error) do

mix.exs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ defmodule MintWebSocket.MixProject do
1919
"coveralls.github": :test,
2020
docs: :dev
2121
],
22+
dialyzer: [
23+
plt_local_path: "priv/plts",
24+
plt_add_apps: [:mix]
25+
],
2226
package: package(),
2327
description: description(),
2428
source_url: @source_url,
@@ -41,7 +45,8 @@ defmodule MintWebSocket.MixProject do
4145
{:jason, ">= 0.0.0", only: [:dev, :test]},
4246
{:cowboy, "~> 2.9", only: [:test]},
4347
{:gun, "== 2.0.0-rc.2", only: [:test]},
44-
{:excoveralls, "~> 0.14", only: [:test]}
48+
{:excoveralls, "~> 0.14", only: [:test]},
49+
{:dialyxir, "~> 1.2", only: [:dev, :test], runtime: false}
4550
]
4651
end
4752

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
44
"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"},
55
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
6+
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
67
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
8+
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
79
"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"},
810
"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"},
911
"gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"},

test/fixtures/autobahn_client.ex

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule AutobahnClient do
1010
defstruct [:conn, :websocket, :ref, messages: [], next: :cont, sent_close?: false, buffer: <<>>]
1111

1212
defguardp is_close_frame(frame)
13-
when frame == :close or (is_tuple(frame) and elem(frame, 0) == :close)
13+
when is_tuple(frame) and elem(frame, 0) == :close
1414

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

152-
with {:ok, %Mint.WebSocket{} = websocket, data} <-
153-
Mint.WebSocket.encode(state.websocket, frame),
154-
{:ok, conn} <- Mint.WebSocket.stream_request_body(state.conn, state.ref, data) do
155-
Logger.debug("Sent.")
156-
%__MODULE__{state | conn: conn, websocket: websocket, sent_close?: is_close_frame(frame)}
157-
else
158-
{:error, %Mint.WebSocket{} = websocket, reason} ->
152+
case Mint.WebSocket.encode(state.websocket, frame) do
153+
{:ok, websocket, data} ->
154+
do_send(put_in(state.websocket, websocket), frame, data)
155+
156+
{:error, websocket, reason} ->
159157
Logger.debug(
160158
"Could not send frame #{inspect(frame, printable_limit: 30)} because #{inspect(reason)}, sending close..."
161159
)
162160

163161
send(put_in(state.websocket, websocket), {:close, 1002, ""})
162+
end
163+
end
164+
165+
defp do_send(state, frame, data) do
166+
case Mint.WebSocket.stream_request_body(state.conn, state.ref, data) do
167+
{:ok, conn} ->
168+
Logger.debug("Sent.")
169+
%__MODULE__{state | conn: conn, sent_close?: is_close_frame(frame)}
164170

165171
{:error, conn, %Mint.TransportError{reason: :closed}} ->
166172
Logger.debug(

test/fixtures/test_server.ex

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ defmodule TestServer do
33
A supervisor for the WebsocketHandler
44
"""
55

6-
use Supervisor
7-
8-
def start_link(_opts) do
6+
def start() do
97
dispatch =
108
:cowboy_router.compile([
119
{:_,
@@ -21,9 +19,5 @@ defmodule TestServer do
2119
env: %{dispatch: dispatch},
2220
enable_connect_protocol: true
2321
})
24-
25-
Supervisor.start_link([], strategy: :one_for_one)
2622
end
27-
28-
def init(_opts), do: {:ok, nil}
2923
end

0 commit comments

Comments
 (0)