defmodule ShootingEventPhxWeb.EventsController do use ShootingEventPhxWeb, :controller alias ShootingEventPhx.Events def stream(conn, _params) do conn = conn |> put_resp_header("content-type", "text/event-stream") |> put_resp_header("cache-control", "no-cache, no-transform") |> put_resp_header("connection", "keep-alive") |> put_resp_header("x-accel-buffering", "no") |> send_chunked(200) now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() {:ok, conn} = chunk(conn, "event: ready\ndata: {\"ts\":\"#{now}\"}\n\n") :ok = Events.subscribe() loop_stream(conn) end defp loop_stream(conn) do receive do {:state, ts} -> case chunk(conn, "event: state\ndata: {\"ts\":\"#{ts}\"}\n\n") do {:ok, conn} -> loop_stream(conn) {:error, :closed} -> conn {:error, _} -> conn end after 20_000 -> now_unix = DateTime.utc_now() |> DateTime.to_unix() case chunk(conn, ": ping #{now_unix}\n\n") do {:ok, conn} -> loop_stream(conn) {:error, :closed} -> conn {:error, _} -> conn end end end end