Skip to content

Cookbook: Simple file based cache

Tymon Tobolski edited this page Mar 26, 2018 · 1 revision
defmodule Tesla.Middleware.Cache do
  # requires tesla 0.x
  def call(env, run, [get: get, set: set]) do
    if env.method == :get do
      key = cache_key(env)

      case get.(key) do
        {:ok, value} ->
          value

        {:error, _} ->
          res = run.(env)
          set.(key, res)
          res
      end
    else
      run.(env)
    end
  end

  defp cache_key(env) do
    :crypto.hash(:sha256, [
      to_string(env.method),
      env.url
    ]) |> Base.encode16
  end
end
defmodule Tesla.Middleware.Cache.File do
  require Logger

  def call(env, run, [dir: dir]) do
    Tesla.Middleware.Cache.call(env, run,
      get: fn (key) -> get(dir, key) end,
      set: fn (key, val) -> set(dir, key, val) end
    )
  end

  def get(dir, key) do
    case File.read(path(dir, key)) do
      {:ok, data} ->
        Logger.debug "cache/get #{key} fresh"
        {:ok, decode(data)}

      err ->
        Logger.debug "cache/get #{key} miss"
        err
    end
  end

  def set(dir, key, value) do
    Logger.debug "cache/set #{key}"
    File.mkdir_p(dir)
    File.write!(path(dir, key), encode(value))
  end

  defp decode(data) do
    :erlang.binary_to_term(data)
  end

  defp encode(env) do
    :erlang.term_to_binary(env)
  end

  defp path(dir, key) do
    "#{dir}/#{key}"
  end
end