2

I'm using ExTwitter Stream to track tweets in realtime and broadcast them via channel endpoint. I would like to create one process per event and assign to it one twitter stream listener, then when new subscriber join to the same event get previous stream state and also receive and broadcast new tweets.

How to create GenServer process from:

stream = ExTwitter.stream_filter(track: hashtags)
pid = spawn(fn ->
  for tweet <- stream do
    IO.puts tweet.text
    MyApp.Endpoint.broadcast! "stream", "tweet", %{tweet: tweet.text}
  end
end)

and assign it by event_id as child in following module:

defmodule MyApp.TwitterStream.Monitor do
  require IEx
  @moduledoc """
  Store twitter stream per event_id
  """
  use GenServer

  def create(event_id, hashtags, coords) do
    case GenServer.whereis(ref(event_id)) do
      nil ->
        Supervisor.start_child(MyApp.TwitterStream.Supervisor, [event_id, hashtags, coords])
      _twitter_stream ->
        IEx.pry
        # return previous ExTwitter stream state and broadcast new tweets
        {:error, :twitter_stream_already_exists}
    end
  end

  def start_link(event_id, hashtags, coords) do
    # stream = ExTwitter.stream_filter(track: hashtags)
    # pid = spawn(fn ->
    #   for tweet <- stream do
    #     IO.puts tweet.text
    #     MyApp.Endpoint.broadcast! "stream", "tweet", %{tweet: tweet.text}
    #   end
    # end)
    GenServer.start_link(__MODULE__, %{hashtags: hashtags, coords: coords}, name: ref(event_id))
  end

  def stop(event_id) do
    try_call(event_id, :stop)
  end

  def info(event_id) do
    try_call(event_id, :info)
  end

  def handle_call(:stop, _from, state) do
    # ExTwitter.stream_control(pid, :stop)
    {:stop, :normal, :ok, state}
  end

  def handle_call(:info, _from, state) do
    {:reply, state, state}
  end

  defp try_call(event_id, call_function) do
    case GenServer.whereis(ref(event_id)) do
      nil ->
        {:error, :invalid_twitter_stream}
      twitter_stream ->
        GenServer.call(twitter_stream, call_function)
    end
  end

  defp ref(event_id) do
    {:global, {:twitter_stream, event_id}}
  end
end

How to receive new tweets or eventually stop twitter stream outside the event Monitor?

Supervisor:

defmodule MyApp.TwitterStream.Supervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    children = [
      worker(MyApp.TwitterStream.Monitor, [], restart: :temporary)
    ]

    supervise(children, strategy: :simple_one_for_one)
  end
end
Afshin Moazami
  • 2,092
  • 5
  • 33
  • 55
luzny
  • 2,380
  • 7
  • 30
  • 64

0 Answers0