defmodule Pullhub.RepoFetcher do
  require Logger

  use GenServer

  alias Pullhub.Repo
  alias Pullhub.User
  alias Pullhub.GithubApi
  alias Pullhub.Repository
  alias Pullhub.RepositoriesService

  def start_link(opts \\ []) do
    {:ok, pid} = GenServer.start_link(__MODULE__, [], opts)
  end

  def fetch(fetch_params) do
    GenServer.cast(:repo_fetcher, {:fetch, fetch_params})
  end

  def handle_cast({:fetch, fetch_params}, state) do
    {:noreply, fetch}
  end

  def init([]) do
    {:ok, []}
  end

  def fetch do
    Repo.all(User)
    |> Enum.filter(fn(u) -> u.github_token != nil end)
    |> Enum.map(&fetch_and_update_repositories/1)
  end

  def fetch_and_update_repositories(user) do
    user
    |> GithubApi.user_repositories
    |> Enum.each(&Repository.find_or_create/1)
  end
end

defmodule Pullhub.RepoFetcher do
  use GenServer

  alias Pullhub.GithubApi
  alias Pullhub.Repository

  def fetch(fetch_params) do
    GenServer.cast(:repo_fetcher, {:fetch_user_github_repositories, fetch_params})
  end

  def handle_cast({:fetch_user_github_repositories, fetch_params}, state) do
    %{user: user} = fetch_params
    {:noreply, fetch_and_update_repositories(user)}
  end

  def init([]) do
    {:ok, []}
  end

  def start_link(opts \\ []) do
    {:ok, pid} = GenServer.start_link(__MODULE__, [], opts)
  end

  defp fetch_and_update_repositories(user) do
    user
    |> GithubApi.user_repositories
    |> Enum.map(&Repository.find_or_create/1)
    |> Enum.map(&render_repository/1)
    |> broadcastChannelInfo(user)
  end

  defp broadcastChannelInfo(rendered_repositories, user) do
    Pullhub.Endpoint.broadcast(
      "repository:list:#{user.id}",
      "repositories_updated",
      %{data: rendered_repositories}
    )
  end

  defp render_repository(repository) do
    Phoenix.View.render(
      Pullhub.RepositoryView,
      "repository.html",
      repository: repository
    )
    |> Phoenix.HTML.safe_to_string
  end
end

Make RepoFetcher broadcast downloaded repositories
Make RepoFetcher broadcast downloaded repositories

Each user can now request to download repositories individually. The
fetcher broadcasts a list of rendered repository-rows for the client to
insert when finish fetching.

substancelab/pullhub,substancelab/pullhub,substancelab/pullhub