Packages

Exfile backend for OpenStack Swift storage, based on ExSwift

Current section

Files

Jump to
exfile_swift lib exfile_swift.ex
Raw

lib/exfile_swift.ex

defmodule ExfileSwift do
use Exfile.Backend
alias Exfile.LocalFile
alias ExfileSwift.Sharder
@ex_swift_opts ~w[auth_url username password region]a
def init(opts) do
{ex_swift_opts, opts} = Keyword.split(opts, @ex_swift_opts)
container = Keyword.fetch!(opts, :container)
sharder = Keyword.get(opts, :sharder, Sharder.Hex)
shard_size = Keyword.get(opts, :shard_size)
{:ok, backend} = super(opts)
swift = ExSwift.Config.new(ex_swift_opts)
put_in(backend.meta, %{
swift: swift,
container: container,
sharder: sharder,
shard_size: shard_size
})
end
def open(%{meta: m} = backend, id) do
case ExSwift.get_object(m.swift, container(m, id), path(backend, id)) do
{:ok, response} ->
io = File.open!(response.body, [:ram, :binary])
{:ok, %LocalFile{io: io}}
{:error, error} ->
{:error, error}
end
end
def exists?(%{meta: m} = backend, id) do
case ExSwift.head_object(m.swift, container(m, id), path(backend, id)) do
{:ok, _} ->
true
_ ->
false
end
end
def size(%{meta: m} = backend, id) do
case ExSwift.head_object(m.swift, container(m, id), path(backend, id)) do
{:ok, response} ->
length = response |> ExSwift.Request.get_header("content-length") |> String.to_integer()
{:ok, length}
{:error, error} ->
{:error, error}
end
end
def delete(%{meta: m} = backend, id) do
case ExSwift.delete_object(m.swift, container(m, id), path(backend, id)) do
{:ok, _} -> :ok
{:error, error} -> {:error, error}
end
end
def upload(backend, %Exfile.File{} = other_file) do
case Exfile.File.open(other_file) do
{:ok, local_file} ->
upload(backend, local_file)
{:error, error} ->
{:error, error}
end
end
def upload(backend, %LocalFile{} = local_file) do
id = backend.hasher.hash(local_file)
case LocalFile.open(local_file) do
{:ok, io} ->
do_upload(backend, id, io)
{:error, error} ->
{:error, error}
end
end
defp do_upload(%{meta: m} = backend, id, io) do
with iodata when is_binary(iodata) <- IO.binread(io, :all) do
case ExSwift.put_object(m.swift, container(m, id), id, iodata) do
{:ok, _} -> {:ok, get(backend, id)}
{:error, error} -> {:error, error}
end
end
end
def path(%{directory: directory}, id) do
[directory, id]
|> Enum.reject(&is_empty?/1)
|> Enum.join("/")
end
defp container(%{shard_size: nil, container: container}, _id), do: container
defp container(%{container: base, sharder: sharder, shard_size: shard_size}, id) do
suffix = sharder.shard_id(id, shard_size)
"#{base}_#{suffix}"
end
defp is_empty?(elem) do
string = to_string(elem)
Regex.match?(~r/^\s*$/, string)
end
end