Extracted from qwan-tracker
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
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
|
||||
Reference in New Issue
Block a user