diff --git a/backend/deps.edn b/backend/deps.edn index a88402829..f3c958720 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -21,8 +21,8 @@ java-http-clj/java-http-clj {:mvn/version "0.4.3"} funcool/yetti - {:git/tag "v10.0" - :git/sha "520613f" + {:git/tag "v11.4" + :git/sha "ce50d42" :git/url "https://github.com/funcool/yetti.git" :exclusions [org.slf4j/slf4j-api]} diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 049b95c17..735beb4af 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -35,8 +35,8 @@ [clojure.spec.alpha :as s] [cuerdas.core :as str] [integrant.core :as ig] - [ring.request :as rreq] - [ring.response :as-alias rres])) + [yetti.request :as yreq] + [yetti.response :as-alias yres])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HELPERS @@ -492,8 +492,8 @@ (defn- redirect-response [uri] - {::rres/status 302 - ::rres/headers {"location" (str uri)}}) + {::yres/status 302 + ::yres/headers {"location" (str uri)}}) (defn- redirect-with-error ([error] (redirect-with-error error nil)) @@ -598,7 +598,7 @@ (defn- get-external-session-id [request] - (let [session-id (rreq/get-header request "x-external-session-id")] + (let [session-id (yreq/get-header request "x-external-session-id")] (when (string? session-id) (if (or (> (count session-id) 256) (= session-id "null") @@ -618,8 +618,8 @@ state (tokens/generate (::setup/props cfg) (d/without-nils params)) uri (build-auth-uri cfg state)] - {::rres/status 200 - ::rres/body {:redirect-uri uri}})) + {::yres/status 200 + ::yres/body {:redirect-uri uri}})) (defn- callback-handler [{:keys [::provider] :as cfg} request] diff --git a/backend/src/app/http.clj b/backend/src/app/http.clj index 672d1ec60..45972db2e 100644 --- a/backend/src/app/http.clj +++ b/backend/src/app/http.clj @@ -29,9 +29,9 @@ [promesa.exec :as px] [reitit.core :as r] [reitit.middleware :as rr] - [ring.request :as rreq] - [ring.response :as-alias rres] - [yetti.adapter :as yt])) + [yetti.adapter :as yt] + [yetti.request :as yreq] + [yetti.response :as-alias yres])) (declare router-handler) @@ -100,12 +100,12 @@ (defn- not-found-handler [_] - {::rres/status 404}) + {::yres/status 404}) (defn- router-handler [router] (letfn [(resolve-handler [request] - (if-let [match (r/match-by-path router (rreq/path request))] + (if-let [match (r/match-by-path router (yreq/path request))] (let [params (:path-params match) result (:result match) handler (or (:handler result) not-found-handler) @@ -114,11 +114,11 @@ (partial not-found-handler request))) (on-error [cause request] - (let [{:keys [::rres/body] :as response} (errors/handle cause request)] + (let [{:keys [::yres/body] :as response} (errors/handle cause request)] (cond-> response (map? body) - (-> (update ::rres/headers assoc "content-type" "application/transit+json") - (assoc ::rres/body (t/encode-str body {:type :json-verbose}))))))] + (-> (update ::yres/headers assoc "content-type" "application/transit+json") + (assoc ::yres/body (t/encode-str body {:type :json-verbose}))))))] (fn [request] (let [handler (resolve-handler request)] diff --git a/backend/src/app/http/access_token.clj b/backend/src/app/http/access_token.clj index 0d1865f10..d49800564 100644 --- a/backend/src/app/http/access_token.clj +++ b/backend/src/app/http/access_token.clj @@ -12,13 +12,13 @@ [app.main :as-alias main] [app.setup :as-alias setup] [app.tokens :as tokens] - [ring.request :as rreq])) + [yetti.request :as yreq])) (def header-re #"^Token\s+(.*)") (defn- get-token [request] - (some->> (rreq/get-header request "authorization") + (some->> (yreq/get-header request "authorization") (re-matches header-re) (second))) diff --git a/backend/src/app/http/assets.clj b/backend/src/app/http/assets.clj index 9a8e69dbf..45c4ab315 100644 --- a/backend/src/app/http/assets.clj +++ b/backend/src/app/http/assets.clj @@ -16,7 +16,7 @@ [app.util.time :as dt] [clojure.spec.alpha :as s] [integrant.core :as ig] - [ring.response :as-alias rres])) + [yetti.response :as-alias yres])) (def ^:private cache-max-age (dt/duration {:hours 24})) @@ -37,8 +37,8 @@ (defn- serve-object-from-s3 [{:keys [::sto/storage] :as cfg} obj] (let [{:keys [host port] :as url} (sto/get-object-url storage obj {:max-age signature-max-age})] - {::rres/status 307 - ::rres/headers {"location" (str url) + {::yres/status 307 + ::yres/headers {"location" (str url) "x-host" (cond-> host port (str ":" port)) "x-mtype" (-> obj meta :content-type) "cache-control" (str "max-age=" (inst-ms cache-max-age))}})) @@ -51,8 +51,8 @@ headers {"x-accel-redirect" (:path purl) "content-type" (:content-type mdata) "cache-control" (str "max-age=" (inst-ms cache-max-age))}] - {::rres/status 204 - ::rres/headers headers})) + {::yres/status 204 + ::yres/headers headers})) (defn- serve-object "Helper function that returns the appropriate response depending on @@ -69,7 +69,7 @@ obj (sto/get-object storage id)] (if obj (serve-object cfg obj) - {::rres/status 404}))) + {::yres/status 404}))) (defn- generic-handler "A generic handler helper/common code for file-media based handlers." @@ -80,7 +80,7 @@ sobj (sto/get-object storage (kf mobj))] (if sobj (serve-object cfg sobj) - {::rres/status 404}))) + {::yres/status 404}))) (defn file-objects-handler "Handler that serves storage objects by file media id." diff --git a/backend/src/app/http/awsns.clj b/backend/src/app/http/awsns.clj index 77ae6c5d6..117d702bc 100644 --- a/backend/src/app/http/awsns.clj +++ b/backend/src/app/http/awsns.clj @@ -22,8 +22,8 @@ [cuerdas.core :as str] [integrant.core :as ig] [promesa.exec :as px] - [ring.request :as rreq] - [ring.response :as-alias rres])) + [yetti.request :as yreq] + [yetti.response :as-alias yres])) (declare parse-json) (declare handle-request) @@ -38,9 +38,9 @@ (defmethod ig/init-key ::routes [_ cfg] (letfn [(handler [request] - (let [data (-> request rreq/body slurp)] + (let [data (-> request yreq/body slurp)] (px/run! :vthread (partial handle-request cfg data))) - {::rres/status 200})] + {::yres/status 200})] ["/sns" {:handler handler :allowed-methods #{:post}}])) diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj index cf7abb77e..8b999d638 100644 --- a/backend/src/app/http/debug.clj +++ b/backend/src/app/http/debug.clj @@ -33,8 +33,8 @@ [integrant.core :as ig] [markdown.core :as md] [markdown.transformers :as mdt] - [ring.request :as rreq] - [ring.response :as rres])) + [yetti.request :as yreq] + [yetti.response :as yres])) ;; (selmer.parser/cache-off!) @@ -44,9 +44,9 @@ (defn index-handler [_cfg _request] - {::rres/status 200 - ::rres/headers {"content-type" "text/html"} - ::rres/body (-> (io/resource "app/templates/debug.tmpl") + {::yres/status 200 + ::yres/headers {"content-type" "text/html"} + ::yres/body (-> (io/resource "app/templates/debug.tmpl") (tmpl/render {}))}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -56,17 +56,17 @@ (defn prepare-response [body] (let [headers {"content-type" "application/transit+json"}] - {::rres/status 200 - ::rres/body body - ::rres/headers headers})) + {::yres/status 200 + ::yres/body body + ::yres/headers headers})) (defn prepare-download-response [body filename] (let [headers {"content-disposition" (str "attachment; filename=" filename) "content-type" "application/octet-stream"}] - {::rres/status 200 - ::rres/body body - ::rres/headers headers})) + {::yres/status 200 + ::yres/body body + ::yres/headers headers})) (def sql:retrieve-range-of-changes "select revn, changes from file_change where file_id=? and revn >= ? and revn <= ? order by revn") @@ -108,8 +108,8 @@ (db/update! conn :file {:data data} {:id file-id}) - {::rres/status 201 - ::rres/body "OK CREATED"}))) + {::yres/status 201 + ::yres/body "OK CREATED"}))) :else (prepare-response (blob/decode data)))))) @@ -138,8 +138,8 @@ {:data data :deleted-at nil} {:id file-id}) - {::rres/status 200 - ::rres/body "OK UPDATED"}) + {::yres/status 200 + ::yres/body "OK UPDATED"}) (db/run! pool (fn [{:keys [::db/conn] :as cfg}] (create-file cfg {:id file-id @@ -149,15 +149,15 @@ (db/update! conn :file {:data data} {:id file-id}) - {::rres/status 201 - ::rres/body "OK CREATED"})))) + {::yres/status 201 + ::yres/body "OK CREATED"})))) - {::rres/status 500 - ::rres/body "ERROR"}))) + {::yres/status 500 + ::yres/body "ERROR"}))) (defn file-data-handler [cfg request] - (case (rreq/method request) + (case (yreq/method request) :get (retrieve-file-data cfg request) :post (upload-file-data cfg request) (ex/raise :type :http @@ -238,12 +238,12 @@ 1 (render-template-v1 report) 2 (render-template-v2 report) 3 (render-template-v3 report))] - {::rres/status 200 - ::rres/body result - ::rres/headers {"content-type" "text/html; charset=utf-8" + {::yres/status 200 + ::yres/body result + ::yres/headers {"content-type" "text/html; charset=utf-8" "x-robots-tag" "noindex"}}) - {::rres/status 404 - ::rres/body "not found"}))) + {::yres/status 404 + ::yres/body "not found"}))) (def sql:error-reports "SELECT id, created_at, @@ -256,10 +256,10 @@ [{:keys [::db/pool]} _request] (let [items (->> (db/exec! pool [sql:error-reports]) (map #(update % :created-at dt/format-instant :rfc1123)))] - {::rres/status 200 - ::rres/body (-> (io/resource "app/templates/error-list.tmpl") + {::yres/status 200 + ::yres/body (-> (io/resource "app/templates/error-list.tmpl") (tmpl/render {:items items})) - ::rres/headers {"content-type" "text/html; charset=utf-8" + ::yres/headers {"content-type" "text/html; charset=utf-8" "x-robots-tag" "noindex"}})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -298,13 +298,13 @@ ::bf.v1/project-id project-id ::bf.v1/input path)] (bf.v1/import-files! cfg) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body "OK CLONED"}) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body "OK CLONED"}) - {::rres/status 200 - ::rres/body (io/input-stream path) - ::rres/headers {"content-type" "application/octet-stream" + {::yres/status 200 + ::yres/body (io/input-stream path) + ::yres/headers {"content-type" "application/octet-stream" "content-disposition" (str "attachmen; filename=" (first file-ids) ".penpot")}})))) @@ -333,9 +333,9 @@ ::bf.v1/project-id project-id ::bf.v1/input path)] (bf.v1/import-files! cfg) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body "OK"}))) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body "OK"}))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ACTIONS @@ -365,34 +365,34 @@ (db/update! conn :profile {:is-blocked true} {:id (:id profile)}) (db/delete! conn :http-session {:profile-id (:id profile)}) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))}) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))}) (contains? params :unblock) (do (db/update! conn :profile {:is-blocked false} {:id (:id profile)}) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))}) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))}) (contains? params :resend) (if (:is-blocked profile) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body "PROFILE ALREADY BLOCKED"} + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body "PROFILE ALREADY BLOCKED"} (do (#'auth/send-email-verification! cfg profile) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body (str/ffmt "RESENDED FOR '%'" (:email profile))})) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body (str/ffmt "RESENDED FOR '%'" (:email profile))})) :else (do (db/update! conn :profile {:is-active true} {:id (:id profile)}) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))})))))) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))})))))) (defn- reset-file-version @@ -417,9 +417,9 @@ (db/tx-run! cfg srepl/process-file! file-id #(assoc % :version version)) - {::rres/status 200 - ::rres/headers {"content-type" "text/plain"} - ::rres/body "OK"})) + {::yres/status 200 + ::yres/headers {"content-type" "text/plain"} + ::yres/body "OK"})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -431,13 +431,13 @@ [{:keys [::db/pool]} _] (try (db/exec-one! pool ["select count(*) as count from server_prop;"]) - {::rres/status 200 - ::rres/body "OK"} + {::yres/status 200 + ::yres/body "OK"} (catch Throwable cause (l/warn :hint "unable to execute query on health handler" :cause cause) - {::rres/status 503 - ::rres/body "KO"}))) + {::yres/status 503 + ::yres/body "KO"}))) (defn changelog-handler [_ _] @@ -446,11 +446,11 @@ (md->html [text] (md/md-to-html-string text :replacement-transformers (into [transform-emoji] mdt/transformer-vector)))] (if-let [clog (io/resource "changelog.md")] - {::rres/status 200 - ::rres/headers {"content-type" "text/html; charset=utf-8"} - ::rres/body (-> clog slurp md->html)} - {::rres/status 404 - ::rres/body "NOT FOUND"}))) + {::yres/status 200 + ::yres/headers {"content-type" "text/html; charset=utf-8"} + ::yres/body (-> clog slurp md->html)} + {::yres/status 404 + ::yres/body "NOT FOUND"}))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; INIT diff --git a/backend/src/app/http/errors.clj b/backend/src/app/http/errors.clj index d486e7107..45fe6690d 100644 --- a/backend/src/app/http/errors.clj +++ b/backend/src/app/http/errors.clj @@ -16,8 +16,8 @@ [app.http.session :as-alias session] [app.util.inet :as inet] [clojure.spec.alpha :as s] - [ring.request :as rreq] - [ring.response :as rres])) + [yetti.request :as yreq] + [yetti.response :as yres])) (defn request->context "Extracts error report relevant context data from request." @@ -29,10 +29,10 @@ {:request/path (:path request) :request/method (:method request) :request/params (:params request) - :request/user-agent (rreq/get-header request "user-agent") + :request/user-agent (yreq/get-header request "user-agent") :request/ip-addr (inet/parse-request request) :request/profile-id (:uid claims) - :version/frontend (or (rreq/get-header request "x-frontend-version") "unknown") + :version/frontend (or (yreq/get-header request "x-frontend-version") "unknown") :version/backend (:full cf/version)})) @@ -46,34 +46,34 @@ (defmethod handle-error :authentication [err _ _] - {::rres/status 401 - ::rres/body (ex-data err)}) + {::yres/status 401 + ::yres/body (ex-data err)}) (defmethod handle-error :authorization [err _ _] - {::rres/status 403 - ::rres/body (ex-data err)}) + {::yres/status 403 + ::yres/body (ex-data err)}) (defmethod handle-error :restriction [err _ _] (let [{:keys [code] :as data} (ex-data err)] (if (= code :method-not-allowed) - {::rres/status 405 - ::rres/body data} - {::rres/status 400 - ::rres/body data}))) + {::yres/status 405 + ::yres/body data} + {::yres/status 400 + ::yres/body data}))) (defmethod handle-error :rate-limit [err _ _] (let [headers (-> err ex-data ::http/headers)] - {::rres/status 429 - ::rres/headers headers})) + {::yres/status 429 + ::yres/headers headers})) (defmethod handle-error :concurrency-limit [err _ _] (let [headers (-> err ex-data ::http/headers)] - {::rres/status 429 - ::rres/headers headers})) + {::yres/status 429 + ::yres/headers headers})) (defmethod handle-error :validation [err request parent-cause] @@ -84,22 +84,22 @@ (= code :schema-validation) (= code :data-validation)) (let [explain (ex/explain data)] - {::rres/status 400 - ::rres/body (-> data + {::yres/status 400 + ::yres/body (-> data (dissoc ::s/problems ::s/value ::s/spec ::sm/explain) (cond-> explain (assoc :explain explain)))}) (= code :request-body-too-large) - {::rres/status 413 ::rres/body data} + {::yres/status 413 ::yres/body data} (= code :invalid-image) (binding [l/*context* (request->context request)] (let [cause (or parent-cause err)] (l/warn :hint "unexpected error on processing image" :cause cause) - {::rres/status 400 ::rres/body data})) + {::yres/status 400 ::yres/body data})) :else - {::rres/status 400 ::rres/body data}))) + {::yres/status 400 ::yres/body data}))) (defmethod handle-error :assertion [error request parent-cause] @@ -110,8 +110,8 @@ (= code :data-validation) (let [explain (ex/explain data)] (l/error :hint "data assertion error" :cause cause) - {::rres/status 500 - ::rres/body (-> data + {::yres/status 500 + ::yres/body (-> data (dissoc ::sm/explain) (cond-> explain (assoc :explain explain)) (assoc :type :server-error) @@ -120,8 +120,8 @@ (= code :spec-validation) (let [explain (ex/explain data)] (l/error :hint "spec assertion error" :cause cause) - {::rres/status 500 - ::rres/body (-> data + {::yres/status 500 + ::yres/body (-> data (dissoc ::s/problems ::s/value ::s/spec) (cond-> explain (assoc :explain explain)) (assoc :type :server-error) @@ -130,15 +130,15 @@ :else (do (l/error :hint "assertion error" :cause cause) - {::rres/status 500 - ::rres/body (-> data + {::yres/status 500 + ::yres/body (-> data (assoc :type :server-error) (assoc :code :assertion))}))))) (defmethod handle-error :not-found [err _ _] - {::rres/status 404 - ::rres/body (ex-data err)}) + {::yres/status 404 + ::yres/body (ex-data err)}) (defmethod handle-error :internal [error request parent-cause] @@ -146,8 +146,8 @@ (let [cause (or parent-cause error) data (ex-data error)] (l/error :hint "internal error" :cause cause) - {::rres/status 500 - ::rres/body (-> data + {::yres/status 500 + ::yres/body (-> data (assoc :type :server-error) (update :code #(or % :unhandled)) (assoc :hint (ex-message error)))}))) @@ -174,20 +174,20 @@ :cause cause) (cond (= state "57014") - {::rres/status 504 - ::rres/body {:type :server-error + {::yres/status 504 + ::yres/body {:type :server-error :code :statement-timeout :hint (ex-message error)}} (= state "25P03") - {::rres/status 504 - ::rres/body {:type :server-error + {::yres/status 504 + ::yres/body {:type :server-error :code :idle-in-transaction-timeout :hint (ex-message error)}} :else - {::rres/status 500 - ::rres/body {:type :server-error + {::yres/status 500 + ::yres/body {:type :server-error :code :unexpected :hint (ex-message error) :state state}})))) @@ -201,16 +201,16 @@ (nil? edata) (binding [l/*context* (request->context request)] (l/error :hint "unexpected error" :cause cause) - {::rres/status 500 - ::rres/body {:type :server-error + {::yres/status 500 + ::yres/body {:type :server-error :code :unexpected :hint (ex-message error)}}) :else (binding [l/*context* (request->context request)] (l/error :hint "unhandled error" :cause cause) - {::rres/status 500 - ::rres/body (-> edata + {::yres/status 500 + ::yres/body (-> edata (assoc :type :server-error) (update :code #(or % :unhandled)) (assoc :hint (ex-message error)))})))) @@ -218,8 +218,8 @@ (defmethod handle-exception java.io.IOException [cause _ _] (l/wrn :hint "io exception" :cause cause) - {::rres/status 500 - ::rres/body {:type :server-error + {::yres/status 500 + ::yres/body {:type :server-error :code :io-exception :hint (ex-message cause)}}) @@ -245,4 +245,4 @@ (defn handle' [cause request] - (::rres/body (handle cause request))) + (::yres/body (handle cause request))) diff --git a/backend/src/app/http/middleware.clj b/backend/src/app/http/middleware.clj index de098ad10..af49f9b09 100644 --- a/backend/src/app/http/middleware.clj +++ b/backend/src/app/http/middleware.clj @@ -15,10 +15,10 @@ [app.http.errors :as errors] [app.util.pointer-map :as pmap] [cuerdas.core :as str] - [ring.request :as rreq] - [ring.response :as rres] [yetti.adapter :as yt] - [yetti.middleware :as ymw]) + [yetti.middleware :as ymw] + [yetti.request :as yreq] + [yetti.response :as yres]) (:import io.undertow.server.RequestTooBigException java.io.InputStream @@ -37,17 +37,17 @@ (defn- get-reader ^java.io.BufferedReader [request] - (let [^InputStream body (rreq/body request)] + (let [^InputStream body (yreq/body request)] (java.io.BufferedReader. (java.io.InputStreamReader. body)))) (defn wrap-parse-request [handler] (letfn [(process-request [request] - (let [header (rreq/get-header request "content-type")] + (let [header (yreq/get-header request "content-type")] (cond (str/starts-with? header "application/transit+json") - (with-open [^InputStream is (rreq/body request)] + (with-open [^InputStream is (yreq/body request)] (let [params (t/read! (t/reader is))] (-> request (assoc :body-params params) @@ -85,7 +85,7 @@ (errors/handle cause request)))] (fn [request] - (if (= (rreq/method request) :post) + (if (= (yreq/method request) :post) (try (-> request process-request handler) (catch Throwable cause @@ -113,57 +113,53 @@ (defn wrap-format-response [handler] - (letfn [(transit-streamable-body [data opts] - (reify rres/StreamableResponseBody - (-write-body-to-stream [_ _ output-stream] - (try - (with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)] - (let [tw (t/writer bos opts)] - (t/write! tw data))) - (catch java.io.IOException _) - (catch Throwable cause - (binding [l/*context* {:value data}] - (l/error :hint "unexpected error on encoding response" - :cause cause))) - (finally - (.close ^OutputStream output-stream)))))) + (letfn [(transit-streamable-body [data opts _ output-stream] + (try + (with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)] + (let [tw (t/writer bos opts)] + (t/write! tw data))) + (catch java.io.IOException _) + (catch Throwable cause + (binding [l/*context* {:value data}] + (l/error :hint "unexpected error on encoding response" + :cause cause))) + (finally + (.close ^OutputStream output-stream)))) - (json-streamable-body [data] - (reify rres/StreamableResponseBody - (-write-body-to-stream [_ _ output-stream] - (try - (let [encode (or (-> data meta :encode/json) identity) - data (encode data)] - (with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)] - (with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)] - (json/write writer data :key-fn json/write-camel-key :value-fn write-json-value)))) - (catch java.io.IOException _) - (catch Throwable cause - (binding [l/*context* {:value data}] - (l/error :hint "unexpected error on encoding response" - :cause cause))) - (finally - (.close ^OutputStream output-stream)))))) + (json-streamable-body [data _ output-stream] + (try + (let [encode (or (-> data meta :encode/json) identity) + data (encode data)] + (with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)] + (with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)] + (json/write writer data :key-fn json/write-camel-key :value-fn write-json-value)))) + (catch java.io.IOException _) + (catch Throwable cause + (binding [l/*context* {:value data}] + (l/error :hint "unexpected error on encoding response" + :cause cause))) + (finally + (.close ^OutputStream output-stream)))) (format-response-with-json [response _] - (let [body (::rres/body response)] + (let [body (::yres/body response)] (if (or (boolean? body) (coll? body)) (-> response - (update ::rres/headers assoc "content-type" "application/json") - (assoc ::rres/body (json-streamable-body body))) + (update ::yres/headers assoc "content-type" "application/json") + (assoc ::yres/body (yres/stream-body (partial json-streamable-body body)))) response))) (format-response-with-transit [response request] - (let [body (::rres/body response)] + (let [body (::yres/body response)] (if (or (boolean? body) (coll? body)) - (let [qs (rreq/query request) + (let [qs (yreq/query request) opts (if (or (contains? cf/flags :transit-readable-response) (str/includes? qs "transit_verbose")) {:type :json-verbose} {:type :json})] (-> response - (update ::rres/headers assoc "content-type" "application/transit+json") - (assoc ::rres/body (transit-streamable-body body opts)))) + (update ::yres/headers assoc "content-type" "application/transit+json") + (assoc ::yres/body (yres/stream-body (partial transit-streamable-body body opts))))) response))) (format-from-params [{:keys [query-params] :as request}] @@ -172,7 +168,7 @@ (format-response [response request] (let [accept (or (format-from-params request) - (rreq/get-header request "accept"))] + (yreq/get-header request "accept"))] (cond (or (= accept "application/transit+json") (str/includes? accept "application/transit+json")) @@ -221,11 +217,11 @@ (defn wrap-cors [handler] (fn [request] - (let [response (if (= (rreq/method request) :options) - {::rres/status 200} + (let [response (if (= (yreq/method request) :options) + {::yres/status 200} (handler request)) - origin (rreq/get-header request "origin")] - (update response ::rres/headers with-cors-headers origin)))) + origin (yreq/get-header request "origin")] + (update response ::yres/headers with-cors-headers origin)))) (def cors {:name ::cors @@ -240,7 +236,7 @@ (when-let [allowed (:allowed-methods data)] (fn [handler] (fn [request] - (let [method (rreq/method request)] + (let [method (yreq/method request)] (if (contains? allowed method) (handler request) - {::rres/status 405}))))))}) + {::yres/status 405}))))))}) diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index bf8fea2dc..3c379bb1c 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -22,8 +22,7 @@ [clojure.spec.alpha :as s] [cuerdas.core :as str] [integrant.core :as ig] - [ring.request :as rreq] - [yetti.request :as yrq])) + [yetti.request :as yreq])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DEFAULTS @@ -145,7 +144,7 @@ (us/assert! ::us/uuid profile-id) (fn [request response] - (let [uagent (rreq/get-header request "user-agent") + (let [uagent (yreq/get-header request "user-agent") params {:profile-id profile-id :user-agent uagent :created-at (dt/now)} @@ -161,7 +160,7 @@ (us/assert! ::manager manager) (fn [request response] (let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name) - cookie (yrq/get-cookie request cname)] + cookie (yreq/get-cookie request cname)] (l/trace :hint "delete" :profile-id (:profile-id request)) (some->> (:value cookie) (delete! manager)) (-> response @@ -183,7 +182,7 @@ (defn- get-token [request] (let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name) - cookie (some-> (yrq/get-cookie request cname) :value)] + cookie (some-> (yreq/get-cookie request cname) :value)] (when-not (str/empty? cookie) cookie))) diff --git a/backend/src/app/http/sse.clj b/backend/src/app/http/sse.clj index e3f1bebc3..fb7f75e2d 100644 --- a/backend/src/app/http/sse.clj +++ b/backend/src/app/http/sse.clj @@ -16,7 +16,7 @@ [promesa.exec :as px] [promesa.exec.csp :as sp] [promesa.util :as pu] - [ring.response :as rres]) + [yetti.response :as yres]) (:import java.io.OutputStream)) @@ -49,24 +49,24 @@ (defn response [handler & {:keys [buf] :or {buf 32} :as opts}] (fn [request] - {::rres/headers default-headers - ::rres/status 200 - ::rres/body (reify rres/StreamableResponseBody - (-write-body-to-stream [_ _ output] - (binding [events/*channel* (sp/chan :buf buf :xf (keep encode))] - (let [listener (events/start-listener - (partial write! output) - (partial pu/close! output))] - (try - (let [result (handler)] - (events/tap :end result)) + {::yres/headers default-headers + ::yres/status 200 + ::yres/body (yres/stream-body + (fn [_ output] + (binding [events/*channel* (sp/chan :buf buf :xf (keep encode))] + (let [listener (events/start-listener + (partial write! output) + (partial pu/close! output))] + (try + (let [result (handler)] + (events/tap :end result)) - (catch java.io.EOFException cause - (events/tap :error (errors/handle' cause request))) - (catch Throwable cause - (l/err :hint "unexpected error on processing sse response" - :cause cause) - (events/tap :error (errors/handle' cause request))) - (finally - (sp/close! events/*channel*) - (px/await! listener)))))))})) + (catch java.io.EOFException cause + (events/tap :error (errors/handle' cause request))) + (catch Throwable cause + (l/err :hint "unexpected error on processing sse response" + :cause cause) + (events/tap :error (errors/handle' cause request))) + (finally + (sp/close! events/*channel*) + (px/await! listener)))))))})) diff --git a/backend/src/app/http/websocket.clj b/backend/src/app/http/websocket.clj index bac7eecf6..84b4389d8 100644 --- a/backend/src/app/http/websocket.clj +++ b/backend/src/app/http/websocket.clj @@ -21,7 +21,6 @@ [clojure.spec.alpha :as s] [integrant.core :as ig] [promesa.exec.csp :as sp] - [ring.websocket :as rws] [yetti.websocket :as yws])) (def recv-labels @@ -303,7 +302,7 @@ :else (do (l/trace :hint "websocket request" :profile-id profile-id :session-id session-id) - {::rws/listener (ws/listener request + {::yws/listener (ws/listener request ::ws/on-rcv-message (partial on-rcv-message cfg) ::ws/on-snd-message (partial on-snd-message cfg) ::ws/on-connect (partial on-connect cfg) diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 444cf4352..5bd604711 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -36,8 +36,8 @@ [cuerdas.core :as str] [integrant.core :as ig] [promesa.core :as p] - [ring.request :as rreq] - [ring.response :as rres])) + [yetti.request :as yreq] + [yetti.response :as yres])) (s/def ::profile-id ::us/uuid) @@ -64,16 +64,16 @@ response (if (fn? result) (result request) (let [result (rph/unwrap result)] - {::rres/status (::http/status mdata 200) - ::rres/headers (::http/headers mdata {}) - ::rres/body result}))] + {::yres/status (::http/status mdata 200) + ::yres/headers (::http/headers mdata {}) + ::yres/body result}))] (-> response (handle-response-transformation request mdata) (handle-before-comple-hook mdata)))) (defn get-external-session-id [request] - (when-let [session-id (rreq/get-header request "x-external-session-id")] + (when-let [session-id (yreq/get-header request "x-external-session-id")] (when-not (or (> (count session-id) 256) (= session-id "null") (str/blank? session-id)) @@ -81,7 +81,7 @@ (defn- get-external-event-origin [request] - (when-let [origin (rreq/get-header request "x-event-origin")] + (when-let [origin (yreq/get-header request "x-event-origin")] (when-not (or (> (count origin) 256) (= origin "null") (str/blank? origin)) @@ -92,7 +92,7 @@ internal async flow into ring async flow." [methods {:keys [params path-params method] :as request}] (let [handler-name (:type path-params) - etag (rreq/get-header request "if-none-match") + etag (yreq/get-header request "if-none-match") profile-id (or (::session/profile-id request) (::actoken/profile-id request)) diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index 810609c90..c0434c82d 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -25,7 +25,7 @@ [app.util.time :as dt] [app.worker :as-alias wrk] [promesa.exec :as px] - [ring.response :as rres])) + [yetti.response :as yres])) (set! *warn-on-reflection* true) @@ -42,33 +42,33 @@ (defn stream-export-v1 [cfg {:keys [file-id include-libraries embed-assets] :as params}] - (reify rres/StreamableResponseBody - (-write-body-to-stream [_ _ output-stream] - (try - (-> cfg - (assoc ::bf.v1/ids #{file-id}) - (assoc ::bf.v1/embed-assets embed-assets) - (assoc ::bf.v1/include-libraries include-libraries) - (bf.v1/export-files! output-stream)) - (catch Throwable cause - (l/err :hint "exception on exporting file" - :file-id (str file-id) - :cause cause)))))) + (yres/stream-body + (fn [_ output-stream] + (try + (-> cfg + (assoc ::bf.v1/ids #{file-id}) + (assoc ::bf.v1/embed-assets embed-assets) + (assoc ::bf.v1/include-libraries include-libraries) + (bf.v1/export-files! output-stream)) + (catch Throwable cause + (l/err :hint "exception on exporting file" + :file-id (str file-id) + :cause cause)))))) (defn stream-export-v3 [cfg {:keys [file-id include-libraries embed-assets] :as params}] - (reify rres/StreamableResponseBody - (-write-body-to-stream [_ _ output-stream] - (try - (-> cfg - (assoc ::bf.v3/ids #{file-id}) - (assoc ::bf.v3/embed-assets embed-assets) - (assoc ::bf.v3/include-libraries include-libraries) - (bf.v3/export-files! output-stream)) - (catch Throwable cause - (l/err :hint "exception on exporting file" - :file-id (str file-id) - :cause cause)))))) + (yres/stream-body + (fn [_ output-stream] + (try + (-> cfg + (assoc ::bf.v3/ids #{file-id}) + (assoc ::bf.v3/embed-assets embed-assets) + (assoc ::bf.v3/include-libraries include-libraries) + (bf.v3/export-files! output-stream)) + (catch Throwable cause + (l/err :hint "exception on exporting file" + :file-id (str file-id) + :cause cause)))))) (sv/defmethod ::export-binfile "Export a penpot file in a binary format." @@ -84,9 +84,25 @@ 2 (throw (ex-info "not-implemented" {})) 3 (stream-export-v3 cfg params))] - {::rres/status 200 - ::rres/headers {"content-type" "application/octet-stream"} - ::rres/body body}))) + {::yres/status 200 + ::yres/headers {"content-type" "application/octet-stream"} + ::yres/body body}))) + + + ;; {::yres/status 200 + ;; ::yres/headers {"content-type" "application/octet-stream"} + ;; ::yres/body (yres/stream-body + ;; (fn [_ output-stream] + ;; (try + ;; (-> cfg + ;; (assoc ::bf.v1/ids #{file-id}) + ;; (assoc ::bf.v1/embed-assets embed-assets) + ;; (assoc ::bf.v1/include-libraries include-libraries) + ;; (bf.v1/export-files! output-stream)) + ;; (catch Throwable cause + ;; (l/err :hint "exception on exporting file" + ;; :file-id (str file-id) + ;; :cause cause)))))})) ;; --- Command: import-binfile diff --git a/backend/src/app/rpc/cond.clj b/backend/src/app/rpc/cond.clj index 2c79d8f66..168b7f0c8 100644 --- a/backend/src/app/rpc/cond.clj +++ b/backend/src/app/rpc/cond.clj @@ -29,7 +29,7 @@ [app.util.services :as-alias sv] [buddy.core.codecs :as bc] [buddy.core.hash :as bh] - [ring.response :as-alias rres])) + [yetti.response :as-alias yres])) (def ^{:dynamic true @@ -59,7 +59,7 @@ key' (when (some? object) (->> object (key-fn params) (fmt-key)))] (if (and (some? key) (= key key')) - (fn [_] {::rres/status 304}) + (fn [_] {::yres/status 304}) (let [params (if (some? object) (assoc params ::object object) params) diff --git a/backend/src/app/rpc/doc.clj b/backend/src/app/rpc/doc.clj index ea973ff7a..a4021102f 100644 --- a/backend/src/app/rpc/doc.clj +++ b/backend/src/app/rpc/doc.clj @@ -27,7 +27,7 @@ [cuerdas.core :as str] [integrant.core :as ig] [pretty-spec.core :as ps] - [ring.response :as-alias rres])) + [yetti.response :as-alias yres])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DOC (human readable) @@ -87,11 +87,11 @@ (let [params (:query-params request) pstyle (:type params "js") context (assoc context :param-style pstyle)] - {::rres/status 200 - ::rres/body (-> (io/resource "app/templates/api-doc.tmpl") + {::yres/status 200 + ::yres/body (-> (io/resource "app/templates/api-doc.tmpl") (tmpl/render context))})) (fn [_] - {::rres/status 404}))) + {::yres/status 404}))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; OPENAPI / SWAGGER (v3.1) @@ -175,12 +175,12 @@ [context] (if (contains? cf/flags :backend-openapi-doc) (fn [_] - {::rres/status 200 - ::rres/headers {"content-type" "application/json; charset=utf-8"} - ::rres/body (json/encode context)}) + {::yres/status 200 + ::yres/headers {"content-type" "application/json; charset=utf-8"} + ::yres/body (json/encode context)}) (fn [_] - {::rres/status 404}))) + {::yres/status 404}))) (defn openapi-handler [] @@ -191,12 +191,12 @@ context {:public-uri (cf/get :public-uri) :swagger-js swagger-js :swagger-css swagger-cs}] - {::rres/status 200 - ::rres/headers {"content-type" "text/html"} - ::rres/body (-> (io/resource "app/templates/openapi.tmpl") + {::yres/status 200 + ::yres/headers {"content-type" "text/html"} + ::yres/body (-> (io/resource "app/templates/openapi.tmpl") (tmpl/render context))})) (fn [_] - {::rres/status 404}))) + {::yres/status 404}))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MODULE INIT diff --git a/backend/src/app/rpc/helpers.clj b/backend/src/app/rpc/helpers.clj index 87b91f545..a424b1f8f 100644 --- a/backend/src/app/rpc/helpers.clj +++ b/backend/src/app/rpc/helpers.clj @@ -11,7 +11,7 @@ [app.common.data.macros :as dm] [app.http :as-alias http] [app.rpc :as-alias rpc] - [ring.response :as-alias rres])) + [yetti.response :as-alias yres])) ;; A utilty wrapper object for wrap service responses that does not ;; implements the IObj interface that make possible attach metadata to @@ -77,4 +77,4 @@ (fn [_ response] (let [exp (if (integer? max-age) max-age (inst-ms max-age)) val (dm/fmt "max-age=%" (int (/ exp 1000.0)))] - (update response ::rres/headers assoc "cache-control" val))))) + (update response ::yres/headers assoc "cache-control" val))))) diff --git a/backend/src/app/util/inet.clj b/backend/src/app/util/inet.clj index 9e3fca606..9f0b096c3 100644 --- a/backend/src/app/util/inet.clj +++ b/backend/src/app/util/inet.clj @@ -8,7 +8,7 @@ "INET addr parsing and validation helpers" (:require [cuerdas.core :as str] - [ring.request :as rreq]) + [yetti.request :as yreq]) (:import com.google.common.net.InetAddresses java.net.InetAddress)) @@ -27,11 +27,11 @@ (defn parse-request [request] - (or (some-> (rreq/get-header request "x-real-ip") + (or (some-> (yreq/get-header request "x-real-ip") (normalize)) - (some-> (rreq/get-header request "x-forwarded-for") + (some-> (yreq/get-header request "x-forwarded-for") (str/split #"\s*,\s*") (first) (normalize)) - (some-> (rreq/remote-addr request) + (some-> (yreq/remote-addr request) (normalize)))) diff --git a/backend/src/app/util/websocket.clj b/backend/src/app/util/websocket.clj index b468c0e28..c8c38ab79 100644 --- a/backend/src/app/util/websocket.clj +++ b/backend/src/app/util/websocket.clj @@ -16,8 +16,7 @@ [promesa.exec :as px] [promesa.exec.csp :as sp] [promesa.util :as pu] - [ring.request :as rreq] - [ring.websocket :as rws] + [yetti.request :as yreq] [yetti.websocket :as yws]) (:import java.nio.ByteBuffer)) @@ -85,7 +84,7 @@ hbeat-ch (sp/chan :buf (sp/sliding-buffer 6)) close-ch (sp/chan) ip-addr (inet/parse-request request) - uagent (rreq/get-header request "user-agent") + uagent (yreq/get-header request "user-agent") id (uuid/next) state (atom {}) beats (atom #{}) @@ -138,7 +137,7 @@ (defn- handle-ping! [{:keys [::id ::beats ::channel] :as wsp} beat-id] (l/trc :hint "send ping" :beat beat-id :conn-id (str id)) - (rws/ping channel (encode-beat beat-id)) + (yws/ping channel (encode-beat beat-id)) (let [issued (swap! beats conj (long beat-id))] (not (>= (count issued) max-missed-heartbeats)))) @@ -151,14 +150,14 @@ (loop [i 0] (let [ping-ch (sp/timeout-chan heartbeat-interval) [msg p] (sp/alts! [close-ch input-ch output-ch heartbeat-ch ping-ch])] - (when (rws/open? channel) + (when (yws/open? channel) (cond (identical? p ping-ch) (if (handle-ping! wsp i) (recur (inc i)) (do (l/trc :hint "closing" :reason "missing to many pings") - (rws/close channel 8802 "missing to many pings"))) + (yws/close channel 8802 "missing to many pings"))) (or (identical? p close-ch) (nil? msg)) (do :nothing) @@ -183,7 +182,7 @@ (identical? p output-ch) (let [message (on-snd-message msg) message (t/encode-str message {:type :json-verbose})] - (rws/send channel message) + (yws/send channel message) (recur i)))))) (catch InterruptedException _cause @@ -202,13 +201,13 @@ (try (handler wsp {:type :close}) - (when (rws/open? channel) + (when (yws/open? channel) ;; NOTE: we need to ignore all exceptions here because ;; there can be a race condition that first returns that ;; channel is connected but on closing, will raise that ;; channel is already closed. (ex/ignoring - (rws/close channel 8899 "terminated"))) + (yws/close channel 8899 "terminated"))) (when-let [on-disconnect (::on-disconnect wsp)] (on-disconnect)) diff --git a/backend/test/backend_tests/helpers.clj b/backend/test/backend_tests/helpers.clj index 92d1d4edb..8e83c4474 100644 --- a/backend/test/backend_tests/helpers.clj +++ b/backend/test/backend_tests/helpers.clj @@ -47,8 +47,9 @@ [mockery.core :as mk] [promesa.core :as p] [promesa.exec :as px] - [ring.response :as rres] - [yetti.request :as yrq]) + [ring.core.protocols :as rcp] + [yetti.request :as yrq] + [yetti.response :as yres]) (:import java.io.PipedInputStream java.io.PipedOutputStream @@ -548,12 +549,12 @@ (defn consume-sse [callback] - (let [{:keys [::rres/status ::rres/body ::rres/headers] :as response} (callback {}) + (let [{:keys [::yres/status ::yres/body ::yres/headers] :as response} (callback {}) output (PipedOutputStream.) input (PipedInputStream. output)] (try - (px/exec! :virtual #(rres/-write-body-to-stream body nil output)) + (px/exec! :virtual #(rcp/write-body-to-stream body nil output)) (into [] (map (fn [event] (let [[item1 item2] (re-seq #"(.*): (.*)\n?" event)] diff --git a/backend/test/backend_tests/rpc_audit_test.clj b/backend/test/backend_tests/rpc_audit_test.clj index 14bff7ea6..fe5353e12 100644 --- a/backend/test/backend_tests/rpc_audit_test.clj +++ b/backend/test/backend_tests/rpc_audit_test.clj @@ -12,7 +12,8 @@ [app.rpc :as-alias rpc] [app.util.time :as dt] [backend-tests.helpers :as th] - [clojure.test :as t])) + [clojure.test :as t] + [yetti.request])) (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) @@ -25,7 +26,7 @@ (def http-request (reify - ring.request/Request + yetti.request/IRequest (get-header [_ name] (case name "x-forwarded-for" "127.0.0.44" diff --git a/backend/test/backend_tests/rpc_cond_middleware_test.clj b/backend/test/backend_tests/rpc_cond_middleware_test.clj index e737fc5f5..257b189cd 100644 --- a/backend/test/backend_tests/rpc_cond_middleware_test.clj +++ b/backend/test/backend_tests/rpc_cond_middleware_test.clj @@ -44,5 +44,5 @@ {:keys [error result]} (th/command! (assoc params ::cond/key etag))] (t/is (nil? error)) (t/is (fn? result)) - (t/is (= 304 (-> (result nil) :ring.response/status)))))))) + (t/is (= 304 (-> (result nil) :yetti.response/status)))))))) diff --git a/common/deps.edn b/common/deps.edn index 57379fc35..5a61ab42e 100644 --- a/common/deps.edn +++ b/common/deps.edn @@ -53,8 +53,8 @@ fipp/fipp {:mvn/version "0.6.26"} io.github.eerohele/pp - {:git/tag "2024-01-04.60" - :git/sha "e8a9773"} + {:git/tag "2024-09-09.69" + :git/sha "de4b20f"} io.aviso/pretty {:mvn/version "1.4.4"} environ/environ {:mvn/version "1.2.0"}}