Packages
upstream
1.4.1
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.0
1.8.2
1.8.1
1.7.2
1.7.1
1.7.0
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.12
1.5.11
1.5.11-dev-3
1.5.11-dev-2
1.5.11-dev-1
1.5.11-dev
1.5.10
1.5.9
1.5.8
1.5.7
1.5.6
1.5.5
1.5.2
1.5.1
1.5.0
1.4.12
1.4.9
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.7
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.3
1.2.1
Upstream is for integrating into projects that need to do large file uploads to B2 service. It integrates tightly with Backblaze B2 for now, with plans to support Amazon S3.
Current section
Files
Jump to
Current section
Files
lib/upstream/router.ex
defmodule Upstream.Router do
@moduledoc """
Provides the Endpoints for uploading
"""
import Upstream.Endpoint
use Plug.Router
alias Upstream.Uploader
alias Upstream.B2
plug(:match)
plug(
Plug.Parsers,
parsers: [:multipart],
pass: ["*/*"],
length: 100_000_000
)
plug(:dispatch)
get "/chunks/unfinished" do
case B2.LargeFile.unfinished() do
{:ok, unfinished} ->
render_json(conn, 200, unfinished)
{:error, reason} ->
render_json(conn, 422, reason)
end
end
get "/chunks/resume/:file_id" do
case B2.LargeFile.ListParts.call(body: file_id) do
{:ok, %B2.LargeFile.ListParts{parts: parts}} ->
shas = B2.LargeFile.ListParts.extract_shas(parts)
render_json(conn, 200, %{shas: shas})
{:error, reason} ->
render_json(conn, 422, reason)
end
end
get "/source/:prefix/*path" do
render_json(conn, 200, %{
sequences: [
%{
clips: [
%{
type: "source",
path: get_location(prefix, path)
}
]
}
]
})
end
defp get_location(prefix, path) do
{:ok, %{authorization_token: token}} = B2.Download.authorize(prefix, 3600)
["/" <> Upstream.config(:bucket_name), prefix, path, token]
|> List.flatten()
|> Enum.join("/")
end
post "/file" do
%{"file_name" => file_name} = conn.body_params
%{path: path, filename: _filename} = conn.body_params[Upstream.file_param()]
case Uploader.upload_file!(path, file_name, self()) do
{:ok, result} ->
render_json(conn, 200, Map.merge(%{success: true}, result))
{:error, reason} ->
render_json(conn, 422, Map.merge(%{success: false}, reason))
end
end
post "/chunks/start" do
%{"file_name" => file_name} = conn.body_params
case B2.LargeFile.start(file_name) do
{:ok, start} ->
render_json(conn, 201, start)
{:error, reason} ->
render_json(conn, 422, reason)
end
end
delete "/chunks/cancel/:file_id" do
case B2.LargeFile.cancel(file_id) do
{:ok, cancel} ->
render_json(conn, 200, cancel)
{:error, reason} ->
render_json(conn, 422, reason)
end
end
patch "/chunks/add" do
%{"file_id" => file_id, "part_number" => part_number, "chunk_size" => chunk_size} =
conn.body_params
%{path: path, filename: _filename} = conn.body_params[Upstream.file_param()]
upload_params = %{
file_id: file_id,
index: String.to_integer(part_number),
content_length: String.to_integer(chunk_size)
}
case Uploader.upload_chunk!(path, upload_params) do
{:ok, result} ->
render_json(conn, 200, Map.merge(%{success: true}, result))
{:error, reason} ->
render_json(conn, 422, Map.merge(%{success: false}, reason))
end
end
post "/chunks/finish" do
%{"file_id" => file_id, "shas" => shas} = conn.body_params
shas_list =
shas
|> Enum.sort_by(fn {k, _v} -> Integer.parse(k) end)
|> Enum.map(fn {_k, v} -> v end)
case B2.LargeFile.finish(file_id, shas_list) do
{:ok, result} ->
render_json(conn, 200, Map.merge(%{success: true}, result))
{:error, reason} ->
render_json(conn, 422, Map.merge(%{success: false}, reason))
end
end
end