From 11e562d6effba33828374a82d8402ab5dd8400a1 Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Thu, 3 Oct 2024 16:35:40 +0200 Subject: [PATCH 1/3] updated to Bandit --- .gitignore | 2 +- README.md | 61 ++++++++++++++----- config/config.exs | 1 + .../components/layouts/app.html.heex | 7 ++- lib/counter_web/live/counter.ex | 28 +++++---- lib/counter_web/live/counter_component.ex | 2 +- lib/counter_web/live/counter_state.ex | 8 +-- mix.exs | 27 +++++--- mix.lock | 25 +++++--- priv/static/images/logo.svg | 6 ++ test/counter_web/live/counter_test.exs | 18 ++++-- 11 files changed, 127 insertions(+), 58 deletions(-) create mode 100644 priv/static/images/logo.svg diff --git a/.gitignore b/.gitignore index e4daf621..090ebf4c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ npm-debug.log /priv/static/cache_manifest.json # Ignore assets that are produced by build tools. -/priv/static/* +#/priv/static/* # Ignore this noise: .DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 9f41a19b..b62dd5e4 100644 --- a/README.md +++ b/README.md @@ -146,16 +146,16 @@ When you run the command: elixir -v ``` -You should expect to see output similar to the following: +At the time of writing, you should expect to see output similar to the following: ```elixir -Elixir 1.15.4 (compiled with Erlang/OTP 26) +Elixir 1.17.3 (compiled with Erlang/OTP 26) ``` -This informs us we are using `Elixir version 1.15.4` +This informs us we are using `Elixir version 1.17.3` which is the _latest_ version at the time of writing. Some of the more advanced features of Phoenix 1.7 during compilation time require elixir -`1.14` although the code will work in previous versions. +`1.17` although the code will work in previous versions.
@@ -171,7 +171,7 @@ mix phx.new -v You should see something similar to the following: ```sh -Phoenix installer v1.7.7 +Phoenix installer v1.7.14 ``` If you have an earlier version, @@ -676,7 +676,9 @@ defmodule CounterWeb.Counter do @topic "live" def mount(_session, _params, socket) do - CounterWeb.Endpoint.subscribe(@topic) # subscribe to the channel + if connected?(socket) do + CounterWeb.Endpoint.subscribe(@topic) # subscribe to the channel + end {:ok, assign(socket, :val, 0)} end @@ -721,12 +723,28 @@ The second change is on [Line 7](https://github.com/dwyl/phoenix-liveview-counter-tutorial/blob/664228ac564a79a0dd92d06857622c1ba22cda71/lib/counter_web/live/counter.exL7) where the [`mount/3`](https://github.com/dwyl/phoenix-liveview-counter-tutorial/blob/d3cddb14dff911a377d0e41b916cfe57b0557606/lib/counter_web/live/counter.ex#L6) -function now creates a subscription to the `@topic`: +function now creates a subscription to the `@topic` when the socket is connected: ```elixir CounterWeb.Endpoint.subscribe(@topic) # subscribe to the channel topic ``` +When the client (the browser) connects to the Phoenix server, +a websocket connection is established. +The interface is the `socket` and +we know that the socket is connected +when the [connected?/1](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#connected?/1) function returns `true`. +This is why we only subscribe to the channel +when the socket is connected. +Why do we do this? +Because a websocket connection starts with an HTTP request +and HTTP is a stateless protocol. +So when the client connects to the server, +the server does not know if the client is already connected to the server. +Once the websocket connection is established, +the server knows that the client is connected, +thus `connected?(ocket) == true`. + Each client connected to the App subscribes to the `@topic` so when the count is updated on any of the clients, @@ -1371,8 +1389,9 @@ defmodule CounterWeb.Counter do @topic Count.topic def mount(_params, _session, socket) do - PubSub.subscribe(Counter.PubSub, @topic) - + if connected?(socket) do + PubSub.subscribe(Counter.PubSub, @topic) + end {:ok, assign(socket, val: Count.current()) } end @@ -1567,6 +1586,12 @@ but not here) so the rest of the code goes into 2. We handle Presence updates and use the current count, adding joiners and subtracting leavers to calculate the current numbers 'present'. We do that in a pattern matched `handle_info`. + Notice that since we populate the socket's state in the `mount/3` callback, + and compute the Presence there, we need to remove the connected client + from the joins in the `handle_info` callback. + We use `Map.delete` to remove the client from the joins. + This works because the client is identified by the socket's `id` and Presence + process returns a map whose key value is the `socket.id`. 3. We publish the additional data to the client in `render` ```diff @@ -1580,14 +1605,19 @@ defmodule CounterWeb.Counter do + @presence_topic "presence" def mount(_params, _session, socket) do - PubSub.subscribe(Counter.PubSub, @topic) -+ Presence.track(self(), @presence_topic, socket.id, %{}) -+ CounterWeb.Endpoint.subscribe(@presence_topic) -+ + initial_present = -+ Presence.list(@presence_topic) -+ |> map_size + if connected?(socket) do + PubSub.subscribe(Counter.PubSub, @topic) + ++ Presence.track(self(), @presence_topic, socket.id, %{}) ++ CounterWeb.Endpoint.subscribe(@presence_topic) ++ ++ Presence.list(@presence_topic) ++ |> map_size ++ else ++ 0 ++ end + {:ok, assign(socket, val: Count.current(), present: initial_present) } - {:ok, assign(socket, val: Count.current()) } @@ -1609,6 +1639,7 @@ defmodule CounterWeb.Counter do + %{event: "presence_diff", payload: %{joins: joins, leaves: leaves}}, + %{assigns: %{present: present}} = socket + ) do ++ {_, joins} = Map.pop!(joins, socket.id, %{}) + new_present = present + map_size(joins) - map_size(leaves) + + {:noreply, assign(socket, :present, new_present)} diff --git a/config/config.exs b/config/config.exs index d96c0c88..996c8620 100644 --- a/config/config.exs +++ b/config/config.exs @@ -10,6 +10,7 @@ import Config # Configures the endpoint config :counter, CounterWeb.Endpoint, url: [host: "localhost"], + adapter: Bandit.PhoenixAdapter, render_errors: [ formats: [html: CounterWeb.ErrorHTML, json: CounterWeb.ErrorJSON], layout: false diff --git a/lib/counter_web/components/layouts/app.html.heex b/lib/counter_web/components/layouts/app.html.heex index 1a2aab10..7a58188f 100644 --- a/lib/counter_web/components/layouts/app.html.heex +++ b/lib/counter_web/components/layouts/app.html.heex @@ -9,7 +9,10 @@

- + GitHub <%= @inner_content %>
- \ No newline at end of file + diff --git a/lib/counter_web/live/counter.ex b/lib/counter_web/live/counter.ex index 30b54d39..88f398e4 100644 --- a/lib/counter_web/live/counter.ex +++ b/lib/counter_web/live/counter.ex @@ -4,20 +4,22 @@ defmodule CounterWeb.Counter do alias Phoenix.PubSub alias Counter.Presence - @topic Count.topic + @topic Count.topic() @presence_topic "presence" def mount(_params, _session, socket) do - PubSub.subscribe(Counter.PubSub, @topic) - Presence.track(self(), @presence_topic, socket.id, %{}) - initial_present = - Presence.list(@presence_topic) - |> map_size + if connected?(socket) do + PubSub.subscribe(Counter.PubSub, @topic) + CounterWeb.Endpoint.subscribe(@presence_topic) + Presence.track(self(), @presence_topic, socket.id, %{}) - CounterWeb.Endpoint.subscribe(@presence_topic) + Presence.list(@presence_topic) |> map_size() + else + 0 + end - {:ok, assign(socket, val: Count.current(), present: initial_present) } + {:ok, assign(socket, val: Count.current(), present: initial_present)} end def handle_event("inc", _, socket) do @@ -33,11 +35,13 @@ defmodule CounterWeb.Counter do end def handle_info( - %{event: "presence_diff", payload: %{joins: joins, leaves: leaves}}, - %{assigns: %{present: present}} = socket - ) do - new_present = present + map_size(joins) - map_size(leaves) + %{event: "presence_diff", payload: %{joins: joins, leaves: leaves}}, + %{assigns: %{present: present}} = socket + ) do + {_, joins} = Map.pop(joins, socket.id, %{}) + changes = map_size(joins) - map_size(leaves) + new_present = present + changes {:noreply, assign(socket, :present, new_present)} end diff --git a/lib/counter_web/live/counter_component.ex b/lib/counter_web/live/counter_component.ex index 1c3dcd6f..239ad902 100644 --- a/lib/counter_web/live/counter_component.ex +++ b/lib/counter_web/live/counter_component.ex @@ -9,7 +9,7 @@ defmodule CounterComponent do def render(assigns) do ~H"""
-

Counter: <%= @val %>

+

Counter: <%= @val %>

diff --git a/lib/counter_web/live/counter_state.ex b/lib/counter_web/live/counter_state.ex index 164a1f5d..1e01b75b 100644 --- a/lib/counter_web/live/counter_state.ex +++ b/lib/counter_web/live/counter_state.ex @@ -16,15 +16,15 @@ defmodule Counter.Count do end def incr() do - GenServer.call @name, :incr + GenServer.call(@name, :incr) end def decr() do - GenServer.call @name, :decr + GenServer.call(@name, :decr) end def current() do - GenServer.call @name, :current + GenServer.call(@name, :current) end def init(start_count) do @@ -34,7 +34,7 @@ defmodule Counter.Count do # Implementation (Runs in GenServer process) def handle_call(:current, _from, count) do - {:reply, count, count} + {:reply, count, count} end def handle_call(:incr, _from, count) do diff --git a/mix.exs b/mix.exs index 7429c96a..dedc3c51 100644 --- a/mix.exs +++ b/mix.exs @@ -4,8 +4,8 @@ defmodule Counter.MixProject do def project do [ app: :counter, - version: "1.7.7", - elixir: "~> 1.14", + version: "1.8.0", + elixir: "~> 1.17", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, aliases: aliases(), @@ -42,20 +42,29 @@ defmodule Counter.MixProject do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.7.7"}, - {:phoenix_html, "~> 4.0"}, + {:phoenix, "~> 1.7.14"}, + {:phoenix_html, "~> 4.1"}, {:phoenix_live_reload, "~> 1.2", only: :dev}, - {:phoenix_live_view, "~> 0.20.0"}, + # TODO bump on release to {:phoenix_live_view, "~> 1.0.0"}, + {:phoenix_live_view, "~> 1.0.0-rc.1", override: true}, {:floki, ">= 0.30.0", only: :test}, - {:esbuild, "~> 0.7", runtime: Mix.env() == :dev}, - {:tailwind, "~> 0.2.1", runtime: Mix.env() == :dev}, + {:esbuild, "~> 0.8", runtime: Mix.env() == :dev}, + {:tailwind, "~> 0.2", runtime: Mix.env() == :dev}, + {:heroicons, + github: "tailwindlabs/heroicons", + tag: "v2.1.1", + sparse: "optimized", + app: false, + compile: false, + depth: 1}, {:telemetry_metrics, "~> 1.0"}, {:telemetry_poller, "~> 1.0"}, {:jason, "~> 1.2"}, - {:plug_cowboy, "~> 2.5"}, + {:dns_cluster, "~> 0.1.1"}, + {:bandit, "~> 1.5"}, # Track test coverage: github.com/parroty/excoveralls - {:excoveralls, "~> 0.18.0", only: [:test, :dev]}, + {:excoveralls, "~> 0.16.0", only: [:test, :dev]} ] end diff --git a/mix.lock b/mix.lock index 398a205c..8b6f6130 100644 --- a/mix.lock +++ b/mix.lock @@ -1,24 +1,28 @@ %{ - "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"}, + "castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, - "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]}, + "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, - "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.2", "354460993a480656b71c3887f5565f612b3bdbdd8688c83f9e6f512307067dd4", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "2bb3722f327e14a7aa47b1acf27ed633c8cd27b167e18b8237954b9b4804af39"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.0-rc.6", "47d2669995ea326e5c71f5c1bc9177109cebf211385c638faa7b5862a401e516", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e56e4f1642a0b20edc2488cab30e5439595e0d8b5b259f76ef98b1c4e2e5b527"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, @@ -30,7 +34,8 @@ "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"}, "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, + "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"}, } diff --git a/priv/static/images/logo.svg b/priv/static/images/logo.svg new file mode 100644 index 00000000..9f26baba --- /dev/null +++ b/priv/static/images/logo.svg @@ -0,0 +1,6 @@ + diff --git a/test/counter_web/live/counter_test.exs b/test/counter_web/live/counter_test.exs index 83f811ef..c3e49a5a 100644 --- a/test/counter_web/live/counter_test.exs +++ b/test/counter_web/live/counter_test.exs @@ -28,20 +28,30 @@ defmodule CounterWeb.CounterTest do test "handle_info/2 Presence Update - Joiner", %{conn: conn} do {:ok, view, html} = live(conn, "/") assert html =~ "Connected Clients: 1" + send(view.pid, %{ event: "presence_diff", - payload: %{joins: %{"phx-Fhb_dqdqsOCzKQAl" => %{metas: [%{phx_ref: "Fhb_dqdrwlCmfABl"}]}}, - leaves: %{}}}) + payload: %{ + joins: %{"phx-Fhb_dqdqsOCzKQAl" => %{metas: [%{phx_ref: "Fhb_dqdrwlCmfABl"}]}}, + leaves: %{} + } + }) + assert render(view) =~ "Connected Clients: 2" end test "handle_info/2 Presence Update - Leaver", %{conn: conn} do {:ok, view, html} = live(conn, "/") assert html =~ "Connected Clients: 1" + send(view.pid, %{ event: "presence_diff", - payload: %{joins: %{}, - leaves: %{"phx-Fhb_dqdqsOCzKQAl" => %{metas: [%{phx_ref: "Fhb_dqdrwlCmfABl"}]}}}}) + payload: %{ + joins: %{}, + leaves: %{"phx-Fhb_dqdqsOCzKQAl" => %{metas: [%{phx_ref: "Fhb_dqdrwlCmfABl"}]}} + } + }) + assert render(view) =~ "Connected Clients: 0" end end From 152c224f2084ea9195cc73203f935ad4df7af235 Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Thu, 3 Oct 2024 16:36:51 +0200 Subject: [PATCH 2/3] updated to Bandit --- lib/counter_web/live/counter.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/counter_web/live/counter.ex b/lib/counter_web/live/counter.ex index 88f398e4..72d9e0cc 100644 --- a/lib/counter_web/live/counter.ex +++ b/lib/counter_web/live/counter.ex @@ -5,6 +5,7 @@ defmodule CounterWeb.Counter do alias Counter.Presence @topic Count.topic() + @presence_topic "presence" def mount(_params, _session, socket) do From 1177026fa4acd8550c9b5dc8cbae9b47bbc9278e Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Thu, 3 Oct 2024 17:12:04 +0200 Subject: [PATCH 3/3] updated to Bandit --- .github/workflows/ci.yml | 4 ++-- lib/counter_web/live/counter_component.ex | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1924c967..d8372119 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ jobs: - name: Set up Elixir uses: erlef/setup-beam@v1 with: - elixir-version: '1.14.2' # Define the elixir version [required] - otp-version: '25.1.2' # Define the OTP version [required] + elixir-version: '1.17.3' # Define the elixir version [required] + otp-version: '26.2' # Define the OTP version [required] - name: Restore dependencies cache uses: actions/cache@v2 with: diff --git a/lib/counter_web/live/counter_component.ex b/lib/counter_web/live/counter_component.ex index 239ad902..eacc54ba 100644 --- a/lib/counter_web/live/counter_component.ex +++ b/lib/counter_web/live/counter_component.ex @@ -9,6 +9,7 @@ defmodule CounterComponent do def render(assigns) do ~H"""
+

Counter: <%= @val %>