mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
♻️ Refactor exporter
- Migrate from puppeteer to playwright - Fix many lifecycle and resource usage issues - Add redis integration - Enable multiple exportation - Enable asynchronos exportation (with progress reporting)
This commit is contained in:
parent
f0a9889f33
commit
4a9e38a221
21 changed files with 1366 additions and 1017 deletions
|
@ -16,46 +16,34 @@
|
|||
[app.config :as cf]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
[lambdaisland.uri :as u]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn create-cookie
|
||||
[uri token]
|
||||
(let [domain (str (:host uri)
|
||||
(when (:port uri)
|
||||
(str ":" (:port uri))))]
|
||||
{:domain domain
|
||||
:key "auth-token"
|
||||
:value token}))
|
||||
|
||||
(defn screenshot-object
|
||||
[{:keys [file-id page-id object-id token scale type]}]
|
||||
(letfn [(handle [page]
|
||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (u/uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))
|
||||
cookie (create-cookie uri token)]
|
||||
(screenshot page (str uri) cookie)))
|
||||
|
||||
(screenshot [page uri cookie]
|
||||
(l/info :uri uri)
|
||||
(let [viewport {:width 1920
|
||||
:height 1080
|
||||
:scale scale}
|
||||
options {:viewport viewport
|
||||
:cookie cookie}]
|
||||
(p/do!
|
||||
(bw/configure-page! page options)
|
||||
(bw/navigate! page uri)
|
||||
(bw/eval! page (js* "() => document.body.style.background = 'transparent'"))
|
||||
(bw/wait-for page "#screenshot")
|
||||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(case type
|
||||
:png (bw/screenshot dom {:omit-background? true :type type})
|
||||
:jpeg (bw/screenshot dom {:omit-background? false :type type}))))))]
|
||||
|
||||
(bw/exec! handle)))
|
||||
[{:keys [file-id page-id object-id token scale type uri]}]
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))]
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:viewport #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:locale "en-US"
|
||||
:storageState #js {:cookies (bw/create-cookies uri {:token token})}
|
||||
:deviceScaleFactor scale
|
||||
:userAgent bw/default-user-agent}
|
||||
(fn [page]
|
||||
(l/info :uri uri)
|
||||
(p/do!
|
||||
(bw/nav! page (str uri))
|
||||
(p/let [node (bw/select page "#screenshot")]
|
||||
(bw/wait-for node)
|
||||
(bw/eval! page (js* "() => document.body.style.background = 'transparent'"))
|
||||
(bw/sleep page 2000) ; the good old fix with sleep
|
||||
(case type
|
||||
:png (bw/screenshot node {:omit-background? true :type type})
|
||||
:jpeg (bw/screenshot node {:omit-background? false :type type}))))))))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -65,25 +53,32 @@
|
|||
(s/def ::object-id ::us/uuid)
|
||||
(s/def ::scale ::us/number)
|
||||
(s/def ::token ::us/string)
|
||||
(s/def ::filename ::us/string)
|
||||
(s/def ::origin ::us/string)
|
||||
(s/def ::uri ::us/uri)
|
||||
|
||||
(s/def ::render-params
|
||||
(s/def ::params
|
||||
(s/keys :req-un [::name ::suffix ::type ::object-id ::page-id ::scale ::token ::file-id]
|
||||
:opt-un [::filename]))
|
||||
:opt-un [::origin ::uri]))
|
||||
|
||||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(p/let [content (screenshot-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
(case (:type params)
|
||||
:png ".png"
|
||||
:jpeg ".jpg")))
|
||||
:length (alength content)
|
||||
:mime-type (case (:type params)
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg")}))
|
||||
(us/verify ::params params)
|
||||
(when (and (:origin params)
|
||||
(not (contains? (cf/get :origin-white-list) (:origin params))))
|
||||
(ex/raise :type :validation
|
||||
:code :invalid-origin
|
||||
:hint "invalid origin"
|
||||
:origin (:origin params)))
|
||||
|
||||
(p/let [content (screenshot-object params)]
|
||||
{:data content
|
||||
:name (str (:name params)
|
||||
(:suffix params "")
|
||||
(case (:type params)
|
||||
:png ".png"
|
||||
:jpeg ".jpg"))
|
||||
:size (alength content)
|
||||
:mtype (case (:type params)
|
||||
:png "image/png"
|
||||
:jpeg "image/jpeg")}))
|
||||
|
||||
|
|
|
@ -13,46 +13,33 @@
|
|||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[cljs.spec.alpha :as s]
|
||||
[lambdaisland.uri :as u]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn create-cookie
|
||||
[uri token]
|
||||
(let [domain (str (:host uri)
|
||||
(when (:port uri)
|
||||
(str ":" (:port uri))))]
|
||||
{:domain domain
|
||||
:key "auth-token"
|
||||
:value token}))
|
||||
|
||||
(defn pdf-from-object
|
||||
[{:keys [file-id page-id object-id token scale type save-path]}]
|
||||
(letfn [(handle [page]
|
||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (u/uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :query "essential=t")
|
||||
(assoc :fragment path))
|
||||
|
||||
cookie (create-cookie uri token)]
|
||||
(pdf-from page (str uri) cookie)))
|
||||
|
||||
(pdf-from [page uri cookie]
|
||||
(l/info :uri uri)
|
||||
(p/let [options {:cookie cookie}]
|
||||
(bw/configure-page! page options)
|
||||
(bw/navigate! page uri)
|
||||
(bw/wait-for page "#screenshot")
|
||||
;; taking png screenshot before pdf, helps to make the
|
||||
;; pdf rendering works as expected.
|
||||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(bw/screenshot dom {:full-page? true}))
|
||||
|
||||
(if save-path
|
||||
(bw/pdf page {:save-path save-path})
|
||||
(bw/pdf page))))]
|
||||
|
||||
(bw/exec! handle)))
|
||||
[{:keys [file-id page-id object-id token scale type save-path uri] :as params}]
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))]
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:viewport #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:locale "en-US"
|
||||
:storageState #js {:cookies (bw/create-cookies uri {:token token})}
|
||||
:deviceScaleFactor scale
|
||||
:userAgent bw/default-user-agent}
|
||||
(fn [page]
|
||||
(l/info :uri uri)
|
||||
(p/do!
|
||||
(bw/nav! page uri)
|
||||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(bw/wait-for dom)
|
||||
(bw/screenshot dom {:full-page? true})
|
||||
(if save-path
|
||||
(bw/pdf page {:save-path save-path})
|
||||
(bw/pdf page))))))))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -61,22 +48,21 @@
|
|||
(s/def ::object-id ::us/uuid)
|
||||
(s/def ::scale ::us/number)
|
||||
(s/def ::token ::us/string)
|
||||
(s/def ::filename ::us/string)
|
||||
(s/def ::save-path ::us/string)
|
||||
(s/def ::uri ::us/uri)
|
||||
|
||||
(s/def ::render-params
|
||||
(s/keys :req-un [::name ::suffix ::object-id ::page-id ::scale ::token ::file-id]
|
||||
:opt-un [::filename ::save-path]))
|
||||
:opt-un [::save-path ::uri]))
|
||||
|
||||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(p/let [content (pdf-from-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".pdf"))
|
||||
:length (alength content)
|
||||
:mime-type "application/pdf"}))
|
||||
{:data content
|
||||
:name (str (:name params)
|
||||
(:suffix params "")
|
||||
".pdf")
|
||||
:size (alength content)
|
||||
:mtype "application/pdf"}))
|
||||
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
[app.common.pages :as cp]
|
||||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[app.renderer.bitmap :refer [create-cookie]]
|
||||
[app.util.shell :as sh]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.walk :as walk]
|
||||
[cuerdas.core :as str]
|
||||
[lambdaisland.uri :as u]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(l/set-level! :trace)
|
||||
|
@ -114,7 +112,7 @@
|
|||
|
||||
|
||||
(defn- render-object
|
||||
[{:keys [page-id file-id object-id token scale suffix type]}]
|
||||
[{:keys [page-id file-id object-id token scale suffix type uri]}]
|
||||
(letfn [(convert-to-ppm [pngpath]
|
||||
(l/trace :fn :convert-to-ppm)
|
||||
(let [basepath (path/dirname pngpath)
|
||||
|
@ -306,7 +304,7 @@
|
|||
(-> (bw/select-all page "#screenshot foreignObject")
|
||||
(p/then (fn [nodes] (p/all (map (partial process-text-node page) nodes))))))
|
||||
|
||||
(extract-svg [page]
|
||||
(extract [page]
|
||||
(p/let [dom (bw/select page "#screenshot")
|
||||
xmldata (bw/eval! dom (fn [elem] (.-outerHTML ^js elem)))
|
||||
nodes (process-text-nodes page)
|
||||
|
@ -322,35 +320,32 @@
|
|||
;; (cljs.pprint/pprint (xml->clj result))
|
||||
;; (println "-------")
|
||||
result))
|
||||
]
|
||||
|
||||
(render-in-page [page {:keys [uri cookie] :as rctx}]
|
||||
(let [viewport {:width 1920
|
||||
:height 1080
|
||||
:scale 4}
|
||||
options {:viewport viewport
|
||||
:timeout 15000
|
||||
:cookie cookie}]
|
||||
(p/do!
|
||||
(bw/configure-page! page options)
|
||||
(bw/navigate! page uri)
|
||||
(bw/wait-for page "#screenshot")
|
||||
(bw/sleep page 2000)
|
||||
;; (bw/eval! page (js* "() => document.body.style.background = 'transparent'"))
|
||||
page)))
|
||||
|
||||
(handle [rctx page]
|
||||
(p/let [page (render-in-page page rctx)]
|
||||
(extract-svg page)))]
|
||||
|
||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id "?render-texts=true")
|
||||
uri (-> (u/uri (cf/get :public-uri))
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id "?render-texts=true")
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))
|
||||
cookie (create-cookie uri token)
|
||||
rctx {:cookie cookie
|
||||
:uri (str uri)}]
|
||||
(l/info :uri (:uri rctx))
|
||||
(bw/exec! (partial handle rctx)))))
|
||||
(assoc :fragment path))]
|
||||
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:viewport #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
:locale "en-US"
|
||||
:storageState #js {:cookies (bw/create-cookies uri {:token token})}
|
||||
:deviceScaleFactor scale
|
||||
:userAgent bw/default-user-agent}
|
||||
(fn [page]
|
||||
(l/info :uri uri)
|
||||
(p/do!
|
||||
(bw/nav! page uri)
|
||||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(js/console.log "FFFF" dom)
|
||||
(bw/wait-for dom)
|
||||
(bw/sleep page 2000))
|
||||
|
||||
(extract page)))))))
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
|
@ -360,21 +355,20 @@
|
|||
(s/def ::object-id ::us/uuid)
|
||||
(s/def ::scale ::us/number)
|
||||
(s/def ::token ::us/string)
|
||||
(s/def ::filename ::us/string)
|
||||
(s/def ::uri ::us/uri)
|
||||
|
||||
(s/def ::render-params
|
||||
(s/def ::params
|
||||
(s/keys :req-un [::name ::suffix ::type ::object-id ::page-id ::file-id ::scale ::token]
|
||||
:opt-un [::filename]))
|
||||
:opt-un [::uri]))
|
||||
|
||||
(defn render
|
||||
[params]
|
||||
(us/assert ::render-params params)
|
||||
(us/assert ::params params)
|
||||
(p/let [content (render-object params)]
|
||||
{:content content
|
||||
:filename (or (:filename params)
|
||||
(str (:name params)
|
||||
(:suffix params "")
|
||||
".svg"))
|
||||
:length (alength content)
|
||||
:mime-type "image/svg+xml"}))
|
||||
{:data content
|
||||
:name (str (:name params)
|
||||
(:suffix params "")
|
||||
".svg")
|
||||
:size (alength content)
|
||||
:mtype "image/svg+xml"}))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue