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