defmodule Cachex.Disk do
@moduledoc """
Module dedicated to basic filesystem iteractions.
This module contains the required interactions with a filesystem for serializing
terms directly to a given file path. This is mainly used by the backup/restore
feature of a cache in order to provide easy export functionality.
The behaviours in here are general enough that they can be used for various use
cases rather than just cache serialization, and compression can also be controlled.
"""
alias Cachex.Options
import Cachex.Errors
import Cachex.Spec
##############
# Public API #
##############
@doc """
Reads a file from a filesystem using the Erlang Term Format.
If there's an error reading the file, or the file is invalid ETF, an error will
be returned. Otherwise a Tuple containing the terms will be returned.
As we can't be certain what we're reading from the file, we make sure to load
it safely to avoid malicious content (although the chance of that is slim).
"""
@spec read(binary, Keyword.t()) :: {:ok, any} | {:error, atom}
def read(path, options \\ []) when is_binary(path) and is_list(options) do
trusted = Options.get(options, :trusted, &is_boolean/1, true)
path
|> File.read!()
|> :erlang.binary_to_term((trusted && []) || [:safe])
|> wrap(:ok)
rescue
_ -> error(:unreachable_file)
end
@doc """
Writes a value to a filesystem using the Erlang Term Format.
The compression can be controlled using the `:compression` option in order to
reduce the size of the output. By default this value will be set to level 1
compression. If set to 0, compression will be disabled but be aware storage
will increase dramatically.
"""
@spec write(any, binary, Keyword.t()) :: {:ok, true} | {:error, atom}
def write(value, path, options \\ [])
when is_binary(path) and is_list(options) do
compression =
Options.get(
options,
:compression,
fn val ->
is_integer(val) and val > -1 and val < 10
end,
1
)
insert =
:erlang.term_to_binary(value,
compressed: compression,
minor_version: 1
)
case File.write(path, insert) do
:ok -> {:ok, true}
_err -> error(:unreachable_file)
end
end
end