104 lines
2.7 KiB
Elixir
104 lines
2.7 KiB
Elixir
defmodule Microprints.MicroprintCache do
|
|
@moduledoc """
|
|
GenServer that caches microprint visualizations in ETS.
|
|
|
|
Subscribes to a PubSub topic and invalidates cache entries when files
|
|
change via LiveReload (or any other file watcher).
|
|
|
|
## Configuration
|
|
|
|
The PubSub module and topic can be configured via `Application` environment:
|
|
|
|
config :microprints,
|
|
pubsub: MyApp.PubSub,
|
|
pubsub_topic: "dev_tools_files"
|
|
|
|
Defaults to `Phoenix.PubSub` and `"dev_tools_files"`.
|
|
"""
|
|
|
|
use GenServer
|
|
|
|
alias Microprints.Microprint
|
|
|
|
@table_name :microprint_cache
|
|
@live_reload_topic "dev_tools_files"
|
|
|
|
# Client API
|
|
|
|
@doc """
|
|
Starts the MicroprintCache GenServer.
|
|
|
|
## Options
|
|
|
|
* `:pubsub` - The PubSub module to use (defaults to `Phoenix.PubSub`)
|
|
* `:pubsub_topic` - The PubSub topic to subscribe to (defaults to `"dev_tools_files"`)
|
|
"""
|
|
def start_link(opts \\ []) do
|
|
pubsub = opts[:pubsub] || Application.get_env(:microprints, :pubsub, Phoenix.PubSub)
|
|
pubsub_topic = opts[:pubsub_topic] || Application.get_env(:microprints, :pubsub_topic, @live_reload_topic)
|
|
|
|
GenServer.start_link(__MODULE__, %{pubsub: pubsub, pubsub_topic: pubsub_topic}, name: __MODULE__)
|
|
end
|
|
|
|
@doc """
|
|
Returns the microprint for the given file path.
|
|
|
|
Returns cached version if available, otherwise generates and caches it.
|
|
"""
|
|
@spec get_microprint(String.t()) :: {:ok, Microprint.microprint()} | {:error, term()}
|
|
def get_microprint(path) do
|
|
absolute_path = Path.expand(path)
|
|
|
|
case :ets.lookup(@table_name, absolute_path) do
|
|
[{^absolute_path, microprint}] ->
|
|
{:ok, microprint}
|
|
|
|
[] ->
|
|
case Microprint.generate(absolute_path) do
|
|
{:ok, microprint} ->
|
|
:ets.insert(@table_name, {absolute_path, microprint})
|
|
{:ok, microprint}
|
|
|
|
error ->
|
|
error
|
|
end
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Invalidates the cache entry for the given path.
|
|
"""
|
|
@spec invalidate(String.t()) :: true
|
|
def invalidate(path) do
|
|
absolute_path = Path.expand(path)
|
|
:ets.delete(@table_name, absolute_path)
|
|
end
|
|
|
|
@doc """
|
|
Clears all cached microprints.
|
|
"""
|
|
@spec clear_all() :: true
|
|
def clear_all do
|
|
:ets.delete_all_objects(@table_name)
|
|
end
|
|
|
|
# Server callbacks
|
|
|
|
@impl true
|
|
def init(%{pubsub: pubsub, pubsub_topic: pubsub_topic}) do
|
|
table = :ets.new(@table_name, [:named_table, :public, :set, read_concurrency: true])
|
|
Phoenix.PubSub.subscribe(pubsub, pubsub_topic)
|
|
{:ok, %{table: table, pubsub_topic: pubsub_topic}}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info({:phoenix_live_reload, _topic, path}, state) do
|
|
invalidate(path)
|
|
{:noreply, state}
|
|
end
|
|
|
|
def handle_info(_msg, state) do
|
|
{:noreply, state}
|
|
end
|
|
end
|