Skip to main content

lib/miosa/sandbox/events.ex

defmodule Miosa.Sandbox.Events do
  @moduledoc """
  SSE event streams for a sandbox.

    * `GET /sandboxes/:id/events`             — stream/3
    * `GET /sandboxes/:id/files/watch?path=…` — watch_dir/4
  """

  alias Miosa.Client

  @doc """
  Stream live sandbox events via SSE (GET `/sandboxes/:sandbox_id/events`).

  `callback` is called for each event map with keys `type` and `data`.
  Returns `:ok` when the stream closes or `{:error, reason}` on failure.
  """
  @spec stream(Client.t(), String.t(), function()) :: :ok | {:error, Miosa.Error.t()}
  def stream(%Client{} = client, sandbox_id, callback)
      when is_binary(sandbox_id) and is_function(callback, 1) do
    Client.stream_sse(client, "/sandboxes/#{sandbox_id}/events", callback)
  end

  @doc """
  Watch a directory for filesystem changes via SSE
  (GET `/sandboxes/:sandbox_id/files/watch?path=…`).

  `callback` is called for each event map with keys `type` and `data`.
  Returns `:ok` when the stream closes or `{:error, reason}` on failure.

  ## Options

    * `:recursive` — When `true`, watch the directory tree recursively. Defaults to `false`.
  """
  @spec watch_dir(Client.t(), String.t(), String.t(), function(), keyword()) ::
          :ok | {:error, Miosa.Error.t()}
  def watch_dir(%Client{} = client, sandbox_id, path, callback, opts \\ [])
      when is_binary(sandbox_id) and is_binary(path) and is_function(callback, 1) do
    params =
      [{"path", path}]
      |> maybe_put_param(:recursive, Keyword.get(opts, :recursive))

    query = URI.encode_query(params)

    Client.stream_sse(client, "/sandboxes/#{sandbox_id}/files/watch?#{query}", callback)
  end

  # ---------------------------------------------------------------------------
  # Private
  # ---------------------------------------------------------------------------

  defp maybe_put_param(params, _key, nil), do: params
  defp maybe_put_param(params, key, value), do: params ++ [{to_string(key), to_string(value)}]
end