-
-
Save sb8244/e6884ad08d91de8c4aa5bf32418557e1 to your computer and use it in GitHub Desktop.
Debounced Phoenix Channel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Demo.ApiChannel do | |
require Logger | |
use Phoenix.Channel | |
intercept ["api:show"] | |
# External broadcast interface | |
def broadcast(:show, tenant_id) do | |
Demo.Endpoint.broadcast!("api:t" <> to_string(tenant_id), "api:show", %{}) | |
:ok | |
end | |
# Internal channel | |
def join("api:t" <> ch_tenant_id, _params, socket = %{assigns: %{tenant_id: tenant_id}}) do | |
case to_string(ch_tenant_id) == to_string(tenant_id) do | |
true -> {:ok, socket} | |
false -> {:error, %{}} | |
end | |
end | |
def join("api:t" <> _, _, _), do: {:error, %{}} | |
def handle_in("show", %{}, socket = %{assigns: %{tenant_id: tenant_id}}) do | |
{:reply, {:ok, api_response(tenant_id)}, socket} | |
end | |
# HN: State machine isn't documented here, but the states are idle, debouncing, called | |
def handle_out("api:show", _, socket = %{assigns: %{demo_show_debounce_state: :idle}}) do | |
{:noreply, handle_demo_show_call(socket)} | |
end | |
def handle_out("api:show", _, socket = %{assigns: %{demo_show_debounce_state: :debouncing}}) do | |
{:noreply, assign(socket, :demo_show_debounce_state, :called)} | |
end | |
def handle_out("api:show", _, socket = %{assigns: %{demo_show_debounce_state: :called}}) do | |
{:noreply, socket} | |
end | |
def handle_info("debounced_api:show", socket = %{assigns: %{demo_show_debounce_state: :debouncing}}) do | |
{:noreply, assign(socket, :demo_show_debounce_state, :idle)} | |
end | |
def handle_info("debounced_api:show", socket = %{assigns: %{demo_show_debounce_state: :called}}) do | |
{:noreply, handle_demo_show_call(socket)} | |
end | |
# HN: pushes to the socket and resets internal state machine information | |
defp handle_demo_show_call(socket = %{assigns: %{tenant_id: tenant_id}}) do | |
push socket, "show", api_response(tenant_id) | |
timer = Process.send_after(self(), "debounced_api:show", 3000) | |
socket | |
|> assign(:demo_show_debounce_state, :debouncing) | |
|> assign(:demo_show_debounce_timer, timer) | |
end | |
defp api_response(tenant_id) do | |
%{api_response: ["just", "demo", "response"]} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The state machine isn't documented here, but the goal is to send the initial response to the socket, then send the response every 3s after that. Notice that we can even do something like assign demo_show_debounce_timer a value, because the socket can contain complex data types.