Skip to content

Instantly share code, notes, and snippets.

@ccapndave
Created February 7, 2019 14:33
Show Gist options
  • Save ccapndave/059ea5d3683901f4e0d9cd7464d2af5c to your computer and use it in GitHub Desktop.
Save ccapndave/059ea5d3683901f4e0d9cd7464d2af5c to your computer and use it in GitHub Desktop.
defmodule AlchemyWeb.LicenseChecker do
@moduledoc """
At a constant interval, confirm that all connected users have a license. If not then
send a message to their channel telling the client to kick them out.
"""
use GenServer
alias Alchemy.Licensing
# The interval between checks
@interval 1000
def start_link(opts) do
GenServer.start_link(__MODULE__, opts)
end
def init(_args) do
schedule_check_licenses()
{:ok, %{}}
end
defp schedule_check_licenses() do
self() |> Process.send_after(:check_licenses, @interval)
end
@doc """
Check the licenses for all connected users. If any users don't have a license slot, send a message to their channel
to tell them so.
"""
defp check_licenses() do
# Get all connected user channels
channel_pids_and_tokens = Registry.lookup(Registry.UserChannels, "users")
# Get the pids of all channels that no longer have a license
expired_channel_pids =
Enum.zip(
# PIDs
channel_pids_and_tokens |> Enum.map(&elem(&1, 0)),
# License details
channel_pids_and_tokens
|> Enum.map(&elem(&1, 1))
|> Licensing.acquire_license_slots()
)
|> Enum.filter(fn {_, %Licensing.LicenseDetails{has_license_slot: has_license_slot}} ->
has_license_slot === false
end)
|> Enum.map(&elem(&1, 0))
# Send a message to each expired channel so they can disconnect their clients
expired_channel_pids
|> Enum.each(&send(&1, :license_expired))
end
def handle_info(:check_licenses, state) do
check_licenses()
schedule_check_licenses()
{:noreply, state}
end
end
@elbow-jason
Copy link

elbow-jason commented Feb 7, 2019

DISREGARD THIS. IT IS INCORRECT

There is a lot of unnecessary iteration here.

The logic can be summarized as:

defp check_licenses() do
  # Get all connected user channels
  Registry.UserChannels
  |> Registry.lookup("users")
  |> Enum.each(fn {pid, token} -> notify_pid_if_expired(pid, token) end)
end

defp notify_pid_if_expired(pid, token) do
  token
  |> Licensing.acquire_license_slots()
  |> case do
    %Licensing.LicenseDetails{has_license_slot: false} ->
      send(pid, :license_expired)
    _ -> 
      :ok
  end
end

@ccapndave
Copy link
Author

defmodule AlchemyWeb.LicenseChecker do
  @moduledoc """
  At a constant interval, confirm that all connected users have a license.  If not then
  send a message to their channel telling the client to kick them out.
  """
  use GenServer
  alias Alchemy.Licensing

  # The interval between checks
  @interval 1000

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts)
  end

  def init(_args) do
    schedule_check_licenses()

    {:ok, %{}}
  end

  defp schedule_check_licenses() do
    self() |> Process.send_after(:check_licenses, @interval)
  end

  @doc """
  Check the licenses for all connected users.  If any users don't have a license slot, send a message to their channel
  to tell them so.
  """
  defp check_licenses() do
    Registry.UserChannels
    |> Registry.dispatch("users", fn channel_pids_and_tokens ->
      # Get the pids of all channels that no longer have a license
      expired_channel_pids =
        Enum.zip(
          # PIDs
          channel_pids_and_tokens |> Enum.map(&elem(&1, 0)),

          # License details
          channel_pids_and_tokens
          |> Enum.map(&elem(&1, 1))
          |> Licensing.acquire_license_slots()
        )
        |> Enum.filter(fn {_, %Licensing.LicenseDetails{has_license_slot: has_license_slot}} ->
          has_license_slot === false
        end)
        |> Enum.map(&elem(&1, 0))

      # Send a message to each expired channel so they can disconnect their clients
      expired_channel_pids
      |> Enum.each(&send(&1, :license_expired))
    end)
  end

  def handle_info(:check_licenses, state) do
    check_licenses()
    schedule_check_licenses()
    {:noreply, state}
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment