defmodule Manifester do @moduledoc """ A simple tool for getting digested asset paths out of the cache manifest. See `README.md` to set up and `Manifester.get/1` for usage. """ use GenServer require Logger @name __MODULE__ @cache_manifest "static/cache_manifest.json" # # Client # def start_link(_args) do GenServer.start_link(__MODULE__, :ok, name: @name) end @doc """ Performs a search for an asset, for example: iex> Manifester.get("js/app.js") "js/app-53ddc50a336555354d6b3d18b76d8af6.js" """ @spec get(String.t) :: String.t def get(asset_path) do GenServer.call(@name, {:get, asset_path}) end # # Server # @doc """ Initialises the process, builds cache immediately afterwards. """ def init(:ok) do Logger.info("Manifester initialising") Process.send(self(), :build_cache, []) {:ok, []} end def handle_info(:build_cache, _cache) do otp_app = Application.fetch_env!(:manifester, :otp_app) priv_dir_path = to_string(:code.priv_dir(otp_app)) manifest_path = Path.join([priv_dir_path, @cache_manifest]) cache = if File.exists?(manifest_path) do # Cache manifest is only generated in prod builds. manifest_path |> File.read!() |> Jason.decode!() |> Map.get("latest") else %{} end {:noreply, cache} end def handle_call({:get, asset_path}, _from, cache) do # There are no leading slashes in the cache_manifest.json # file so we make sure we drop it if one is given. asset_path = if String.starts_with?(asset_path, "/") do String.replace_leading(asset_path, "/", "") else asset_path end result = Map.get(cache, asset_path) {:reply, result, cache} end end