fp/apps/bright/lib/bright/cache.ex
2025-03-10 17:51:35 -08:00

179 lines
4.8 KiB
Elixir

defmodule Bright.Cache do
@moduledoc """
A simple caching module that saves files to the `/tmp` directory.
"""
require Logger
# def cache_dir do
# case Application.get_env(:bright, :cache_dir) do
# {:ok, dir} when is_binary(dir) and dir != "" ->
# Logger.debug("cache_dir is #{dir}")
# dir
# {:ok, nil} ->
# raise """
# Configuration :cache_dir for application :bright is set to nil.
# Please provide a valid directory path, e.g.:
# config :bright, cache_dir: "/path/to/cache"
# """
# {:ok, ""} ->
# raise """
# Configuration :cache_dir for application :bright is set to an empty string.
# Please provide a valid directory path, e.g.:
# config :bright, cache_dir: "/path/to/cache"
# """
# :error ->
# raise """
# Configuration :cache_dir for application :bright is not set.
# Please ensure it is defined in your config files, e.g.:
# config :bright, cache_dir: "/path/to/cache"
# """
# end
# end
def generate_basename(input) do
if is_nil(input), do: raise("generate_basename was called with nil argument")
prefix =
:crypto.strong_rand_bytes(6)
|> Base.encode64(padding: false)
|> String.replace(~r/[^a-zA-Z0-9]/, "")
base = Path.basename(input)
output = "#{prefix}/#{base}"
Logger.debug("generate_basename called with input=#{input} output=#{output}")
output
end
# @doc """
# get a filename in the cache directory.
# the path contains a sha256 hash of the file basename.
# thus for any given input, output filename will always be the same.
# """
# def deterministic_filename(input) do
# input
# |> Path.basename()
# |> sha256sum_truncate()
# end
def generate_basename(input, ext) do
if is_nil(input), do: raise("generate_basename was called with nil argument")
input
|> generate_basename
|> Path.rootname()
|> Kernel.<>(".#{ext}")
end
def generate_filename(input) do
Logger.debug("generate_filename called with input=#{input}, cache_dir=#{get_cache_dir()}")
filename = Path.join(get_cache_dir(), generate_basename(input))
File.mkdir_p!(Path.dirname(filename))
Logger.debug("generate_filename filename=#{filename}")
Logger.debug("generate_filename filename=#{filename}")
Logger.debug("generate_filename filename=#{filename}")
filename
end
def generate_filename(input, ext) do
filename = Path.join(get_cache_dir(), generate_basename(input, ext))
File.mkdir_p!(Path.dirname(filename))
filename
end
def get_cache_dir do
case Application.fetch_env(:bright, :cache_dir) do
{:ok, dir} when is_binary(dir) and dir != "" ->
Logger.debug("cache_dir is #{dir}")
dir
{:ok, ""} ->
raise """
Configuration :cache_dir for application :bright is set to an empty string.
Please provide a valid directory path, e.g.:
config :bright, cache_dir: "/path/to/cache"
"""
{:ok, nil} ->
raise """
Configuration :cache_dir for application :bright is set to nil.
Please provide a valid directory path, e.g.:
config :bright, cache_dir: "/path/to/cache"
"""
:error ->
raise """
Configuration :cache_dir for application :bright is not set.
Please ensure it is defined in your config files, e.g.:
config :bright, cache_dir: "/path/to/cache"
"""
end
end
# Ensure the cache directory exists
def ensure_cache_dir! do
unless File.exists?(get_cache_dir()) do
File.mkdir_p!(get_cache_dir())
end
end
@doc """
Delete a cached item by its key.
## Examples
iex> Bright.Cache.delete("example_key")
:ok
iex> Bright.Cache.delete("nonexistent_key")
:ok
"""
def delete(key) do
ensure_cache_dir!()
file_path = generate_filename(key)
case File.rm(file_path) do
:ok ->
Logger.debug("[Cache] Deleted key #{key} from #{file_path}")
:ok
{:error, :enoent} ->
Logger.debug("[Cache] Key #{key} not found for deletion")
:ok
{:error, reason} ->
Logger.error("[Cache] Failed to delete key #{key}: #{reason}")
{:error, reason}
end
end
# @doc """
# Generates a SHA-256 hash of the input string and truncates it to 10 characters.
# ## Parameters
# - `input`: A string to be hashed.
# ## Returns
# A string representing the first 10 characters of the SHA-256 hash in hexadecimal format.
# ## Examples
# iex> Cache.sha256sum_truncate("hello world")
# "2cf24dba5f"
# """
# defp sha256sum_truncate(input) do
# hash = :crypto.hash(:sha256, input) |> Base.encode16(case: :lower)
# String.slice(hash, 0..9)
# end
end