Permalink
Browse files

implement everything needed for debouncing websocket message

This can be used with `WebsocketDemoWeb.Endpoint.broadcast!("demo:32211", "debounce_ping", %{})`

It requires that demo:id (which is dynamic based on id) is grabbed from the frontend manually
  • Loading branch information...
sb8244 committed Feb 13, 2018
1 parent 6ed70a0 commit 18dac56092ed6f495270a5316d246c655dd88d90
@@ -2,7 +2,7 @@ defmodule WebsocketDemoWeb.DemoChannel do
require Logger
use Phoenix.Channel
intercept []
intercept ["debounce_ping"]
def join("demo:" <> _id, _params, socket) do
timer_ref = Process.send(self(), :tick, [])
@@ -11,6 +11,7 @@ defmodule WebsocketDemoWeb.DemoChannel do
socket
|> assign(:current_tick, 0)
|> assign(:tick_timer, timer_ref)
|> assign(:debounce_ping_debounce_state, :idle)
{:ok, socket}
end
@@ -45,4 +46,38 @@ defmodule WebsocketDemoWeb.DemoChannel do
{:noreply, new_socket}
end
def handle_info(:debounce_ping, socket = %{assigns: %{debounce_ping_debounce_state: :debouncing}}) do
new_socket =
socket
|> assign(:debounce_ping_debounce_state, :idle)
|> assign(:debounce_ping_debounce_timer, nil)
{:noreply, new_socket}
end
def handle_info(:debounce_ping, socket = %{assigns: %{debounce_ping_debounce_state: :called}}) do
{:noreply, handle_debounce_ping_call(socket)}
end
def handle_out("debounce_ping", _, socket = %{assigns: %{debounce_ping_debounce_state: :idle}}) do
{:noreply, handle_debounce_ping_call(socket)}
end
def handle_out("debounce_ping", _, socket = %{assigns: %{debounce_ping_debounce_state: :debouncing}}) do
{:noreply, assign(socket, :debounce_ping_debounce_state, :called)}
end
def handle_out("debounce_ping", _, socket = %{assigns: %{debounce_ping_debounce_state: :called}}) do
{:noreply, socket}
end
defp handle_debounce_ping_call(socket) do
push socket, "debounce_ping", %{}
timer = Process.send_after(self(), :debounce_ping, 3000)
socket
|> assign(:debounce_ping_debounce_state, :debouncing)
|> assign(:debounce_ping_debounce_timer, timer)
end
end
@@ -31,7 +31,7 @@ defmodule WebsocketDemoWeb.DemoChannelTest do
assert :sys.get_state(socket.channel_pid).assigns.current_tick == 1
Process.send(socket.channel_pid, :tick, [])
assert :sys.get_state(socket.channel_pid).assigns.current_tick == 2
assert Process.read_timer(socket.assigns.tick_timer) == 5000
assert_in_delta Process.read_timer(socket.assigns.tick_timer), 5000, 10
end
end
@@ -65,4 +65,94 @@ defmodule WebsocketDemoWeb.DemoChannelTest do
leave(socket)
end
end
describe "handle_out debounce_ping" do
test "state=idle, the socket receives an immediate push" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
end
test "state=idle, the timer is setup for 3s from now, and sets the next state" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
state = :sys.get_state(socket.channel_pid).assigns
assert_in_delta Process.read_timer(state.debounce_ping_debounce_timer), 3000, 10
assert state.debounce_ping_debounce_state == :debouncing
end
test "state=debouncing, the state is set to called" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
broadcast_from! socket, "debounce_ping", %{}
state = :sys.get_state(socket.channel_pid).assigns
assert_in_delta Process.read_timer(state.debounce_ping_debounce_timer), 3000, 10
assert state.debounce_ping_debounce_state == :called
end
test "state=called, the state is not changed" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
broadcast_from! socket, "debounce_ping", %{}
broadcast_from! socket, "debounce_ping", %{}
state = :sys.get_state(socket.channel_pid).assigns
assert_in_delta Process.read_timer(state.debounce_ping_debounce_timer), 3000, 10
assert state.debounce_ping_debounce_state == :called
end
end
describe "handle_info :debounce_ping" do
test "from state=debouncing, sets the state to idle without a push" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
send socket.channel_pid, :debounce_ping
state = :sys.get_state(socket.channel_pid).assigns
assert state.debounce_ping_debounce_timer == nil
assert state.debounce_ping_debounce_state == :idle
end
test "from state=called, sets the state to debouncing with a push" do
{:ok, _, socket} =
socket(nil, %{})
|> subscribe_and_join(DemoChannel, "demo:1")
broadcast_from! socket, "debounce_ping", %{}
assert_push "debounce_ping", %{}
broadcast_from! socket, "debounce_ping", %{}
state = :sys.get_state(socket.channel_pid).assigns
assert state.debounce_ping_debounce_state == :called
send socket.channel_pid, :debounce_ping
assert_push "debounce_ping", %{}
state = :sys.get_state(socket.channel_pid).assigns
assert_in_delta Process.read_timer(state.debounce_ping_debounce_timer), 3000, 10
assert state.debounce_ping_debounce_state == :debouncing
end
end
end

0 comments on commit 18dac56

Please sign in to comment.