mirror of
https://github.com/penpot/penpot.git
synced 2026-05-24 17:33:41 +00:00
This upgrade also includes complete elimination of use spec from the backend codebase, completing the long running migration to fully use malli for validation and decoding.
116 lines
3.5 KiB
Clojure
116 lines
3.5 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns app.storage.fs
|
|
(:require
|
|
[app.common.exceptions :as ex]
|
|
[app.common.schema :as sm]
|
|
[app.common.uri :as u]
|
|
[app.storage :as-alias sto]
|
|
[app.storage.impl :as impl]
|
|
[cuerdas.core :as str]
|
|
[datoteka.fs :as fs]
|
|
[datoteka.io :as io]
|
|
[integrant.core :as ig])
|
|
(:import
|
|
java.io.InputStream
|
|
java.io.OutputStream
|
|
java.nio.file.Files
|
|
java.nio.file.Path))
|
|
|
|
(set! *warn-on-reflection* true)
|
|
|
|
;; --- BACKEND INIT
|
|
|
|
(defmethod ig/assert-key ::backend
|
|
[_ params]
|
|
;; FIXME: path (?)
|
|
(assert (string? (::directory params))))
|
|
|
|
(defmethod ig/init-key ::backend
|
|
[_ cfg]
|
|
;; Return a valid backend data structure only if all optional
|
|
;; parameters are provided.
|
|
(when (string? (::directory cfg))
|
|
(let [dir (fs/normalize (::directory cfg))]
|
|
(assoc cfg
|
|
::sto/type :fs
|
|
::directory (str dir)
|
|
::uri (u/uri (str "file://" dir))))))
|
|
|
|
(def ^:private schema:backend
|
|
[:map {:title "fs-backend"}
|
|
[::directory :string]
|
|
[::uri ::sm/uri]
|
|
[::sto/type [:= :fs]]])
|
|
|
|
(sm/register! ::backend schema:backend)
|
|
|
|
(def ^:private valid-backend?
|
|
(sm/validator schema:backend))
|
|
|
|
;; --- API IMPL
|
|
|
|
(defmethod impl/put-object :fs
|
|
[backend {:keys [id] :as object} content]
|
|
(assert (valid-backend? backend) "expected a valid backend instance")
|
|
(let [base (fs/path (::directory backend))
|
|
path (fs/path (impl/id->path id))
|
|
full (fs/normalize (fs/join base path))]
|
|
|
|
(when-not (fs/exists? (fs/parent full))
|
|
(fs/create-dir (fs/parent full)))
|
|
|
|
(with-open [^InputStream src (io/input-stream content)]
|
|
(with-open [^OutputStream dst (io/output-stream full)]
|
|
(io/copy src dst)))
|
|
|
|
object))
|
|
|
|
(defmethod impl/get-object-data :fs
|
|
[backend {:keys [id] :as object}]
|
|
(assert (valid-backend? backend) "expected a valid backend instance")
|
|
(let [^Path base (fs/path (::directory backend))
|
|
^Path path (fs/path (impl/id->path id))
|
|
^Path full (fs/normalize (fs/join base path))]
|
|
(when-not (fs/exists? full)
|
|
(ex/raise :type :internal
|
|
:code :filesystem-object-does-not-exists
|
|
:path (str full)))
|
|
(io/input-stream full)))
|
|
|
|
(defmethod impl/get-object-bytes :fs
|
|
[backend object]
|
|
(with-open [^InputStream input (impl/get-object-data backend object)]
|
|
(io/read input)))
|
|
|
|
(defmethod impl/get-object-url :fs
|
|
[{:keys [::uri] :as backend} {:keys [id] :as object} _]
|
|
(assert (valid-backend? backend) "expected a valid backend instance")
|
|
(update uri :path
|
|
(fn [existing]
|
|
(if (str/ends-with? existing "/")
|
|
(str existing (impl/id->path id))
|
|
(str existing "/" (impl/id->path id))))))
|
|
|
|
(defmethod impl/del-object :fs
|
|
[backend {:keys [id] :as object}]
|
|
(assert (valid-backend? backend) "expected a valid backend instance")
|
|
(let [base (fs/path (::directory backend))
|
|
path (fs/path (impl/id->path id))
|
|
path (fs/join base path)]
|
|
(Files/deleteIfExists ^Path path)))
|
|
|
|
(defmethod impl/del-objects-in-bulk :fs
|
|
[backend ids]
|
|
(assert (valid-backend? backend) "expected a valid backend instance")
|
|
(let [base (fs/path (::directory backend))]
|
|
(doseq [id ids]
|
|
(let [path (fs/path (impl/id->path id))
|
|
path (fs/join base path)]
|
|
(Files/deleteIfExists ^Path path)))))
|
|
|