Unify FileStore and FileServer

next
Marcin Kulik 7 years ago
parent 6943bcecca
commit 2e0cb5c3eb

@ -1,8 +1,5 @@
{:components {:components
{:file-store #var asciinema.component.local-file-store/local-file-store {:file-store #var asciinema.component.local-file-store/local-file-store}
:file-server #var asciinema.component.local-file-server/local-file-server}
:dependencies
{:file-server [:file-store]}
:config :config
{:app {:app
{:middleware {:middleware

@ -9,10 +9,10 @@
[duct.util.repl :refer [setup test cljs-repl migrate rollback]] [duct.util.repl :refer [setup test cljs-repl migrate rollback]]
[duct.util.system :refer [load-system]] [duct.util.system :refer [load-system]]
[reloaded.repl :refer [system init start stop go reset]] [reloaded.repl :refer [system init start stop go reset]]
[asciinema.boundary.file-server :as file-server]
[asciinema.boundary.file-store :as file-store] [asciinema.boundary.file-store :as file-store]
[asciinema.boundary.asciicast-database :as asciicast-database]
[asciinema.component.local-file-store :refer [->LocalFileStore]] [asciinema.component.local-file-store :refer [->LocalFileStore]]
[asciinema.component.local-file-server :refer [->LocalFileServer]])) [asciinema.component.s3-file-store :refer [->S3FileStore]]))
(defn new-system [] (defn new-system []
(load-system (keep io/resource ["asciinema/system.edn" "dev.edn" "local.edn"]))) (load-system (keep io/resource ["asciinema/system.edn" "dev.edn" "local.edn"])))

@ -3,15 +3,14 @@
:http #var asciinema.component.aleph/aleph-server :http #var asciinema.component.aleph/aleph-server
:db #var asciinema.component.db/hikaricp :db #var asciinema.component.db/hikaricp
:ragtime #var duct.component.ragtime/ragtime :ragtime #var duct.component.ragtime/ragtime
:file-store #var asciinema.component.s3-file-store/s3-file-store :file-store #var asciinema.component.s3-file-store/s3-file-store}
:file-server #var asciinema.component.s3-file-server/s3-file-server}
:endpoints :endpoints
{:asciicasts #var asciinema.endpoint.asciicasts/asciicasts-endpoint} {:asciicasts #var asciinema.endpoint.asciicasts/asciicasts-endpoint}
:dependencies :dependencies
{:http [:app] {:http [:app]
:app [:asciicasts] :app [:asciicasts]
:ragtime [:db] :ragtime [:db]
:asciicasts [:db :file-server]} :asciicasts [:db :file-store]}
:config :config
{:app {:app
{:middleware {:middleware
@ -58,11 +57,6 @@
:ragtime :ragtime
{:resource-path "asciinema/migrations"} {:resource-path "asciinema/migrations"}
:file-store :file-store
{:cred {:access-key s3-access-key
:secret-key s3-secret-key}
:bucket s3-bucket
:path-prefix "uploads/"}
:file-server
{:cred {:access-key s3-access-key {:cred {:access-key s3-access-key
:secret-key s3-secret-key} :secret-key s3-secret-key}
:bucket s3-bucket :bucket s3-bucket

@ -1,4 +0,0 @@
(ns asciinema.boundary.file-server)
(defprotocol FileServer
(serve [this path] [this path opts]))

@ -4,4 +4,5 @@
(put-file [this file path] [this file path size]) (put-file [this file path] [this file path size])
(input-stream [this path]) (input-stream [this path])
(move-file [this old-path new-path]) (move-file [this old-path new-path])
(delete-file [this path])) (delete-file [this path])
(serve-file [this path opts]))

@ -1,18 +0,0 @@
(ns asciinema.component.local-file-server
(:require [asciinema.boundary
[file-server :as file-server]
[file-store :as file-store]]
[ring.util.http-response :as response]))
(defrecord LocalFileServer [file-store]
file-server/FileServer
(serve [this path]
(file-server/serve this path {}))
(serve [this path {:keys [filename]}]
(let [resp (response/ok (file-store/input-stream file-store path))]
(if filename
(response/header resp "Content-Disposition" (str "attachment; filename=" filename))
resp))))
(defn local-file-server [{:keys [file-store]}]
(->LocalFileServer file-store))

@ -1,25 +1,37 @@
(ns asciinema.component.local-file-store (ns asciinema.component.local-file-store
(:require [asciinema.boundary.file-store :as file-store] (:require [asciinema.boundary.file-store :as file-store]
[clojure.java.io :as io])) [clojure.java.io :as io]
[ring.util.http-response :as response]))
(defrecord LocalFileStore [base-path] (defrecord LocalFileStore [base-path]
file-store/FileStore file-store/FileStore
(put-file [this file path] (put-file [this file path]
(let [path (str base-path path)] (let [path (str base-path path)]
(io/make-parents path) (io/make-parents path)
(io/copy file (io/file path)))) (io/copy file (io/file path))))
(put-file [this file path size] (put-file [this file path size]
(file-store/put-file this file path)) (file-store/put-file this file path))
(input-stream [this path] (input-stream [this path]
(let [path (str base-path path)] (let [path (str base-path path)]
(io/input-stream path))) (io/input-stream path)))
(move-file [this old-path new-path] (move-file [this old-path new-path]
(let [old-path (str base-path old-path) (let [old-path (str base-path old-path)
new-path (str base-path new-path)] new-path (str base-path new-path)]
(.renameTo (io/file old-path) (io/file new-path)))) (.renameTo (io/file old-path) (io/file new-path))))
(delete-file [this path] (delete-file [this path]
(let [path (str base-path path)] (let [path (str base-path path)]
(io/delete-file path)))) (io/delete-file path)))
(serve-file [this path {:keys [filename]}]
(let [resp (response/ok (file-store/input-stream this path))]
(if filename
(response/header resp "Content-Disposition" (str "attachment; filename=" filename))
resp))))
(defn local-file-store [{:keys [path]}] (defn local-file-store [{:keys [path]}]
(->LocalFileStore path)) (->LocalFileStore path))

@ -1,37 +0,0 @@
(ns asciinema.component.s3-file-server
(:require [asciinema.boundary.file-server :as file-server]
[clj-time
[coerce :as timec]
[core :as time]]
[ring.util.http-response :as response])
(:import com.amazonaws.auth.BasicAWSCredentials
com.amazonaws.services.s3.AmazonS3Client
[com.amazonaws.services.s3.model GeneratePresignedUrlRequest ResponseHeaderOverrides]))
(defn- s3-client* [cred]
(let [credentials (BasicAWSCredentials. (:access-key cred) (:secret-key cred))]
(AmazonS3Client. credentials)))
(def ^:private s3-client (memoize s3-client*))
(defn- generate-presigned-url [cred bucket path {:keys [expires filename]
:or {expires (-> 1 time/days time/from-now)}}]
(let [client (s3-client cred)
request (GeneratePresignedUrlRequest. bucket path)]
(.setExpiration request (timec/to-date expires))
(when filename
(let [header-overrides (doto (ResponseHeaderOverrides.)
(.setContentDisposition (str "attachment; filename=" filename)))]
(.setResponseHeaders request header-overrides)))
(.toString (.generatePresignedUrl client request))))
(defrecord S3FileServer [cred bucket path-prefix]
file-server/FileServer
(serve [this path]
(file-server/serve this path {}))
(serve [this path opts]
(let [path (str path-prefix path)]
(response/found (generate-presigned-url cred bucket path opts)))))
(defn s3-file-server [{:keys [cred bucket path-prefix]}]
(->S3FileServer cred bucket path-prefix))

@ -1,25 +1,58 @@
(ns asciinema.component.s3-file-store (ns asciinema.component.s3-file-store
(:require [asciinema.boundary.file-store :as file-store] (:require [asciinema.boundary.file-store :as file-store]
[aws.sdk.s3 :as s3])) [aws.sdk.s3 :as s3]
[clj-time
[coerce :as timec]
[core :as time]]
[ring.util.http-response :as response])
(:import com.amazonaws.auth.BasicAWSCredentials
com.amazonaws.services.s3.AmazonS3Client
[com.amazonaws.services.s3.model GeneratePresignedUrlRequest ResponseHeaderOverrides]))
(defn- s3-client* [cred]
(let [credentials (BasicAWSCredentials. (:access-key cred) (:secret-key cred))]
(AmazonS3Client. credentials)))
(def ^:private s3-client (memoize s3-client*))
(defn- generate-presigned-url [cred bucket path {:keys [expires filename]
:or {expires (-> 1 time/days time/from-now)}}]
(let [client (s3-client cred)
request (GeneratePresignedUrlRequest. bucket path)]
(.setExpiration request (timec/to-date expires))
(when filename
(let [header-overrides (doto (ResponseHeaderOverrides.)
(.setContentDisposition (str "attachment; filename=" filename)))]
(.setResponseHeaders request header-overrides)))
(.toString (.generatePresignedUrl client request))))
(defrecord S3FileStore [cred bucket path-prefix] (defrecord S3FileStore [cred bucket path-prefix]
file-store/FileStore file-store/FileStore
(put-file [this file path] (put-file [this file path]
(file-store/put-file this file path nil)) (file-store/put-file this file path nil))
(put-file [this file path size] (put-file [this file path size]
(let [path (str path-prefix path)] (let [path (str path-prefix path)]
(s3/put-object cred bucket path file {:content-length size}))) (s3/put-object cred bucket path file {:content-length size})))
(input-stream [this path] (input-stream [this path]
(let [path (str path-prefix path)] (let [path (str path-prefix path)]
(:content (s3/get-object cred bucket path)))) (:content (s3/get-object cred bucket path))))
(move-file [this old-path new-path] (move-file [this old-path new-path]
(let [old-path (str path-prefix old-path) (let [old-path (str path-prefix old-path)
new-path (str path-prefix new-path)] new-path (str path-prefix new-path)]
(s3/copy-object cred bucket old-path new-path) (s3/copy-object cred bucket old-path new-path)
(s3/delete-object cred bucket old-path))) (s3/delete-object cred bucket old-path)))
(delete-file [this path] (delete-file [this path]
(let [path (str path-prefix path)] (let [path (str path-prefix path)]
(s3/delete-object cred bucket path)))) (s3/delete-object cred bucket path)))
(serve-file [this path opts]
(let [path (str path-prefix path)]
(response/found (generate-presigned-url cred bucket path opts)))))
(defn s3-file-store [{:keys [cred bucket path-prefix]}] (defn s3-file-store [{:keys [cred bucket path-prefix]}]
(->S3FileStore cred bucket path-prefix)) (->S3FileStore cred bucket path-prefix))

@ -1,7 +1,7 @@
(ns asciinema.endpoint.asciicasts (ns asciinema.endpoint.asciicasts
(:require [asciinema.boundary (:require [asciinema.boundary
[asciicast-database :as adb] [asciicast-database :as adb]
[file-server :as fserver]] [file-store :as fstore]]
[asciinema.model.asciicast :as asciicast] [asciinema.model.asciicast :as asciicast]
[compojure.api.sweet :refer :all] [compojure.api.sweet :refer :all]
[ring.util.http-response :as response] [ring.util.http-response :as response]
@ -10,7 +10,7 @@
(defn exception-handler [^Exception e data request] (defn exception-handler [^Exception e data request]
(throw e)) (throw e))
(defn asciicasts-endpoint [{:keys [db file-server]}] (defn asciicasts-endpoint [{:keys [db file-store]}]
(api (api
{:exceptions {:handlers {:compojure.api.exception/default exception-handler}}} {:exceptions {:handlers {:compojure.api.exception/default exception-handler}}}
(context (context
@ -21,5 +21,5 @@
(if-let [asciicast (adb/get-asciicast-by-token db token)] (if-let [asciicast (adb/get-asciicast-by-token db token)]
(let [path (asciicast/json-store-path asciicast) (let [path (asciicast/json-store-path asciicast)
filename (str "asciicast-" (:id asciicast) ".json")] filename (str "asciicast-" (:id asciicast) ".json")]
(fserver/serve file-server path (when dl {:filename filename}))) (fstore/serve-file file-store path (when dl {:filename filename})))
(response/not-found)))))) (response/not-found))))))

@ -1,7 +0,0 @@
(ns asciinema.boundary.file-server-test
(:require [clojure.test :refer :all]
[asciinema.boundary.file-server :as file-server]))
(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))
Loading…
Cancel
Save