Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Chapter 16

programming-elixir-1.6/chapter-16.livemd

Chapter 16

Exercise: Nodes-2

Receiving a tick message causes the timeout to start over.

Exercise: Nodes-3

defmodule Ticker do
  @interval 2000
  @name :ticker

  def start do
    pid = spawn(__MODULE__, :generator, [[], 0])
    :global.register_name(@name, pid)
  end

  def register(client_pid) do
    send(:global.whereis_name(@name), {:register, client_pid})
  end

  def generator(clients, next) do
    receive do
      {:register, pid} ->
        IO.puts("registering #{inspect(pid)}")
        generator(clients ++ [pid], next)
    after
      @interval ->
        IO.puts("tick")

        if client = Enum.at(clients, next) do
          send(client, {:tick, next})
        end

        if length(clients) > next + 1 do
          generator(clients, next + 1)
        else
          generator(clients, 0)
        end
    end
  end
end

defmodule Client do
  def start do
    pid = spawn(__MODULE__, :receiver, [])
    Ticker.register(pid)
  end

  def receiver do
    receive do
      {:tick, number} ->
        IO.puts("tock in client ##{number}")
        receiver()
    end
  end
end

Exercise: Nodes-4

defmodule RingTicker do
  @name :ticker

  def start do
    pid = spawn(__MODULE__, :generator, [[]])
    :global.register_name(@name, pid)
  end

  def register(client_pid) do
    send(:global.whereis_name(@name), {:register, client_pid})
  end

  def generator(clients) do
    receive do
      {:register, pid} ->
        IO.puts("registering #{inspect(pid)}")

        if clients == [] do
          send(pid, {:tick})
        else
          send(pid, {:update, List.first(clients)})
          send(List.last(clients), {:update, pid})
        end

        generator(clients ++ [pid])
    end
  end
end

defmodule RingClient do
  @interval 2000

  def start do
    pid = spawn(__MODULE__, :receiver, [:infinity])
    RingTicker.register(pid)
  end

  def receiver(timeout, next \\ self()) do
    receive do
      {:tick} ->
        IO.puts("tock in client")
        receiver(@interval, next)

      {:update, pid} ->
        receiver(timeout, pid)
    after
      timeout ->
        IO.puts("tick")
        send(next, {:tick})
        receiver(:infinity, next)
    end
  end
end