Serve asciicast files from Phoenix
This commit is contained in:
parent
51d6559b27
commit
867509a328
@ -28,6 +28,22 @@ config :phoenix, :template_engines,
|
||||
config :bugsnag, api_key: System.get_env("BUGSNAG_API_KEY")
|
||||
config :bugsnag, release_stage: Mix.env
|
||||
|
||||
if System.get_env("S3_BUCKET") do
|
||||
config :asciinema, :file_store, Asciinema.FileStore.S3
|
||||
|
||||
config :asciinema, Asciinema.FileStore.S3,
|
||||
region: System.get_env("S3_REGION"),
|
||||
bucket: System.get_env("S3_BUCKET"),
|
||||
path: "uploads/"
|
||||
|
||||
config :ex_aws,
|
||||
access_key_id: [{:system, "AWS_ACCESS_KEY_ID"}, :instance_role],
|
||||
secret_access_key: [{:system, "AWS_SECRET_ACCESS_KEY"}, :instance_role]
|
||||
else
|
||||
config :asciinema, :file_store, Asciinema.FileStore.Local
|
||||
config :asciinema, Asciinema.FileStore.Local, path: "uploads/"
|
||||
end
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
import_config "#{Mix.env}.exs"
|
||||
|
@ -17,3 +17,6 @@ config :asciinema, Asciinema.Repo,
|
||||
database: "asciinema_test",
|
||||
hostname: "localhost",
|
||||
pool: Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
config :asciinema, :file_store, Asciinema.FileStore.Local
|
||||
config :asciinema, Asciinema.FileStore.Local, path: "uploads/test/"
|
||||
|
@ -24,11 +24,11 @@ server {
|
||||
try_files /maintenance.html $uri/index.html $uri.html $uri @phoenix;
|
||||
}
|
||||
|
||||
location ~ ^/a/[^.]+\.(json|png)$ {
|
||||
location ~ ^/a/[^.]+\.png$ {
|
||||
try_files $uri $uri/index.html $uri.html @clj;
|
||||
}
|
||||
|
||||
location ~ ^/a/[^.]+\.gif$ {
|
||||
location ~ ^/a/[^.]+\.(json|gif)$ {
|
||||
try_files $uri $uri/index.html $uri.html @phoenix;
|
||||
}
|
||||
|
||||
|
4
lib/asciinema/file_store.ex
Normal file
4
lib/asciinema/file_store.ex
Normal file
@ -0,0 +1,4 @@
|
||||
defmodule Asciinema.FileStore do
|
||||
@doc "Serves file at given path in store"
|
||||
@callback serve_file(conn :: %Plug.Conn{}, path :: String.t, filename :: String.t) :: %Plug.Conn{}
|
||||
end
|
29
lib/asciinema/file_store/local.ex
Normal file
29
lib/asciinema/file_store/local.ex
Normal file
@ -0,0 +1,29 @@
|
||||
defmodule Asciinema.FileStore.Local do
|
||||
@behaviour Asciinema.FileStore
|
||||
import Plug.Conn
|
||||
alias Plug.MIME
|
||||
|
||||
def serve_file(conn, path, nil) do
|
||||
do_serve_file(conn, path)
|
||||
end
|
||||
def serve_file(conn, path, filename) do
|
||||
conn
|
||||
|> put_resp_header("content-disposition", "attachment; filename=#{filename}")
|
||||
|> do_serve_file(path)
|
||||
end
|
||||
|
||||
defp do_serve_file(conn, path) do
|
||||
conn
|
||||
|> put_resp_header("content-type", MIME.path(path))
|
||||
|> send_file(200, base_path() <> path)
|
||||
|> halt
|
||||
end
|
||||
|
||||
defp config do
|
||||
Application.get_env(:asciinema, Asciinema.FileStore.Local)
|
||||
end
|
||||
|
||||
defp base_path do
|
||||
Keyword.get(config(), :path)
|
||||
end
|
||||
end
|
36
lib/asciinema/file_store/s3.ex
Normal file
36
lib/asciinema/file_store/s3.ex
Normal file
@ -0,0 +1,36 @@
|
||||
defmodule Asciinema.FileStore.S3 do
|
||||
@behaviour Asciinema.FileStore
|
||||
import Phoenix.Controller, only: [redirect: 2]
|
||||
|
||||
def serve_file(conn, path, nil) do
|
||||
do_serve_file(conn, path)
|
||||
end
|
||||
def serve_file(conn, path, filename) do
|
||||
do_serve_file(conn, path, ["response-content-disposition": "attachment; filename=#{filename}"])
|
||||
end
|
||||
|
||||
defp do_serve_file(conn, path, query_params \\ []) do
|
||||
{:ok, url} =
|
||||
ExAws.Config.new(:s3, region: region())
|
||||
|> ExAws.S3.presigned_url(:get, bucket(), base_path() <> path, query_params: query_params)
|
||||
|
||||
conn
|
||||
|> redirect(external: url)
|
||||
end
|
||||
|
||||
defp config do
|
||||
Application.get_env(:asciinema, Asciinema.FileStore.S3)
|
||||
end
|
||||
|
||||
defp region do
|
||||
Keyword.get(config(), :region)
|
||||
end
|
||||
|
||||
defp bucket do
|
||||
Keyword.get(config(), :bucket)
|
||||
end
|
||||
|
||||
defp base_path do
|
||||
Keyword.get(config(), :path)
|
||||
end
|
||||
end
|
2
mix.exs
2
mix.exs
@ -21,6 +21,7 @@ defmodule Asciinema.Mixfile do
|
||||
applications: [
|
||||
:bugsnag,
|
||||
:cowboy,
|
||||
:ex_aws,
|
||||
:gettext,
|
||||
:logger,
|
||||
:phoenix,
|
||||
@ -42,6 +43,7 @@ defmodule Asciinema.Mixfile do
|
||||
defp deps do
|
||||
[
|
||||
{:cowboy, "~> 1.0"},
|
||||
{:ex_aws, "~> 1.0"},
|
||||
{:gettext, "~> 0.11"},
|
||||
{:phoenix, "~> 1.2.1"},
|
||||
{:phoenix_ecto, "~> 3.0"},
|
||||
|
1
mix.lock
1
mix.lock
@ -7,6 +7,7 @@
|
||||
"decimal": {:hex, :decimal, "1.1.2", "79a769d4657b2d537b51ef3c02d29ab7141d2b486b516c109642d453ee08e00c", [:mix], [], "hexpm"},
|
||||
"earmark": {:hex, :earmark, "1.2.2", "f718159d6b65068e8daeef709ccddae5f7fdc770707d82e7d126f584cd925b74", [:mix], [], "hexpm"},
|
||||
"ecto": {:hex, :ecto, "2.0.4", "03fd3b9aa508b1383eb38c00ac389953ed22af53811aa2e504975a3e814a8d97", [:mix], [{:db_connection, "~> 1.0-rc.2", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.7.7", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.11.2", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0-beta", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
|
||||
"ex_aws": {:hex, :ex_aws, "1.1.2", "b78416d0a84efe92c22e5df8ba7ca028d63b2b4228f95871a1ecf10324b6493b", [:mix], [{:configparser_ex, "~> 0.2.1", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.0.6", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
|
||||
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [:rebar], [], "hexpm"},
|
||||
"gettext": {:hex, :gettext, "0.11.0", "80c1dd42d270482418fa158ec5ba073d2980e3718bacad86f3d4ad71d5667679", [:mix], [], "hexpm"},
|
||||
"hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "4.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
|
23
web/controllers/asciicast_file_controller.ex
Normal file
23
web/controllers/asciicast_file_controller.ex
Normal file
@ -0,0 +1,23 @@
|
||||
defmodule Asciinema.AsciicastFileController do
|
||||
use Asciinema.Web, :controller
|
||||
alias Asciinema.{Repo, Asciicast}
|
||||
|
||||
def show(conn, %{"id" => id} = params) do
|
||||
asciicast = Repo.one!(Asciicast.by_id_or_secret_token(id))
|
||||
path = Asciicast.json_store_path(asciicast)
|
||||
filename = download_filename(asciicast, params)
|
||||
|
||||
file_store().serve_file(conn, path, filename)
|
||||
end
|
||||
|
||||
defp download_filename(%Asciicast{id: id}, %{"dl" => _}) do
|
||||
"asciicast-#{id}.json"
|
||||
end
|
||||
defp download_filename(_asciicast, _params) do
|
||||
nil
|
||||
end
|
||||
|
||||
defp file_store do
|
||||
Application.get_env(:asciinema, :file_store)
|
||||
end
|
||||
end
|
@ -6,6 +6,7 @@ defmodule Asciinema.Asciicast do
|
||||
field :file, :string
|
||||
field :stdout_data, :string
|
||||
field :stdout_timing, :string
|
||||
field :stdout_frames, :string
|
||||
field :private, :boolean
|
||||
field :secret_token, :string
|
||||
end
|
||||
@ -22,4 +23,11 @@ defmodule Asciinema.Asciicast do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def json_store_path(%__MODULE__{id: id, file: file}) when is_binary(file) do
|
||||
"asciicast/file/#{id}/#{file}"
|
||||
end
|
||||
def json_store_path(%__MODULE__{id: id, stdout_frames: stdout_frames}) when is_binary(stdout_frames) do
|
||||
"asciicast/stdout_frames/#{id}/#{stdout_frames}"
|
||||
end
|
||||
end
|
||||
|
@ -10,6 +10,17 @@ defmodule Asciinema.Router do
|
||||
plug Asciinema.Auth
|
||||
end
|
||||
|
||||
pipeline :asciicast_file do
|
||||
plug :accepts, ["json"]
|
||||
end
|
||||
|
||||
scope "/", Asciinema do
|
||||
pipe_through :asciicast_file
|
||||
|
||||
# rewritten by TrailingFormat from /a/123.json to /a/123/json
|
||||
get "/a/:id/json", AsciicastFileController, :show
|
||||
end
|
||||
|
||||
pipeline :asciicast_animation do
|
||||
plug :accepts, ["html"]
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user