Current section
Files
Jump to
Current section
Files
lib/tus_client/patch.ex
defmodule TusClient.Patch do
@moduledoc false
alias TusClient.Utils
require Logger
def request(url, offset, path, headers \\ [], opts \\ []) do
path
|> seek(offset)
|> do_read(opts)
|> do_request(url, offset, headers, opts)
end
defp do_request({:ok, data}, url, offset, headers, opts) do
hdrs =
[
{"content-length", IO.iodata_length(data)},
{"upload-offset", to_string(offset)}
]
|> Utils.add_version_hdr()
|> Utils.add_tus_content_type()
|> add_custom_headers(headers)
|> Enum.uniq()
url
|> HTTPoison.patch(data, hdrs, Utils.httpoison_opts([], opts))
|> Utils.maybe_follow_redirect(
&parse/1,
&do_request({:ok, data}, &1, offset, headers, opts)
)
end
defp do_request({:error, _} = err, _url, _offset, _headers, _opts), do: err
defp parse({:ok, %{status_code: 204, headers: headers}}) do
case Utils.get_header(headers, "upload-offset") do
v when is_binary(v) -> {:ok, String.to_integer(v)}
_ -> {:error, :protocol}
end
end
defp parse({:ok, resp}) do
Logger.error("PATCH response not handled: #{inspect(resp)}")
{:error, :generic}
end
defp parse({:error, err}) do
Logger.error("PATCH request failed: #{inspect(err)}")
{:error, :transport}
end
defp do_read({:error, _} = err, _opts), do: err
defp do_read({:ok, io_device}, opts) do
data =
case :file.read(io_device, get_read_len(opts)) do
:eof -> {:error, :eof}
res -> res
end
File.close(io_device)
data
end
defp seek(path, offset) when is_binary(path) do
path
|> File.open([:read])
|> seek(offset)
end
defp seek({:ok, io_device}, offset) do
case :file.position(io_device, offset) do
{:ok, _newpos} ->
{:ok, io_device}
err ->
File.close(io_device)
err
end
end
defp seek({:error, err}, _offset) do
Logger.error("Cannot open file for reading: #{inspect(err)}")
{:error, :file_error}
end
defp get_read_len(opts) do
opts
|> Keyword.get(:chunk_len, 4_194_304)
end
defp add_custom_headers(hdrs1, hdrs2) do
hdrs1 ++ hdrs2
end
end