0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 07:29:08 -05:00

⬆️ Update bundled vertx.

This commit is contained in:
Andrey Antukh 2019-11-22 18:04:38 +01:00
parent b2d13a2493
commit 14f634f9ea
7 changed files with 192 additions and 245 deletions

View file

@ -208,8 +208,6 @@
(let [opts (DeploymentOptions.)] (let [opts (DeploymentOptions.)]
(when instances (.setInstances opts (int instances))) (when instances (.setInstances opts (int instances)))
(when worker (.setWorker opts worker)) (when worker (.setWorker opts worker))
;; (.setInstances opts 4)
;; (.setWorkerPoolSize opts 4)
opts)) opts))
(defn- opts->vertx-options (defn- opts->vertx-options

View file

@ -11,11 +11,15 @@
[promesa.core :as p] [promesa.core :as p]
[vertx.util :as vu]) [vertx.util :as vu])
(:import (:import
java.util.Map$Entry
clojure.lang.MapEntry
io.vertx.core.Vertx io.vertx.core.Vertx
io.vertx.core.Verticle io.vertx.core.Verticle
io.vertx.core.Handler io.vertx.core.Handler
io.vertx.core.Future io.vertx.core.Future
io.vertx.core.MultiMap
io.vertx.core.Context io.vertx.core.Context
io.vertx.core.buffer.Buffer
io.vertx.core.http.HttpServer io.vertx.core.http.HttpServer
io.vertx.core.http.HttpServerRequest io.vertx.core.http.HttpServerRequest
io.vertx.core.http.HttpServerResponse io.vertx.core.http.HttpServerResponse
@ -26,7 +30,38 @@
;; --- Public Api ;; --- Public Api
(s/def :vertx.http/handler fn?) (declare -handle-response)
(declare -handle-body)
(defn ->headers
[^HttpServerRequest request]
(let [headers (.headers request)
it (.iterator ^MultiMap headers)]
(loop [m (transient {})]
(if (.hasNext it)
(let [^Map$Entry me (.next it)
key (.toLowerCase (.getKey me))
val (.getValue me)]
(recur (assoc! m key val)))
(persistent! m)))))
(defn- ->request
[^HttpServerRequest request]
{:method (-> request .rawMethod .toLowerCase keyword)
:path (.path request)
:headers (->headers request)
::request request
::response (.response request)})
(defn handler
[vsm f]
(reify Handler
(handle [this request]
(let [ctx (->request request)]
(-handle-response (f ctx) ctx)))))
(s/def :vertx.http/handler
(s/or :fn fn? :handler #(instance? Handler %)))
(s/def :vertx.http/host string?) (s/def :vertx.http/host string?)
(s/def :vertx.http/port pos?) (s/def :vertx.http/port pos?)
(s/def ::server-options (s/def ::server-options
@ -54,21 +89,62 @@
(let [opts (HttpServerOptions.)] (let [opts (HttpServerOptions.)]
(.setReuseAddress opts true) (.setReuseAddress opts true)
(.setReusePort opts true) (.setReusePort opts true)
;; (.setTcpNoDelay opts true) (.setTcpNoDelay opts true)
;; (.setTcpFastOpen opts true) (.setTcpFastOpen opts true)
(when host (.setHost opts host)) (when host (.setHost opts host))
(when port (.setPort opts port)) (when port (.setPort opts port))
opts)) opts))
(defn- fn->handler
[f]
(reify Handler
(handle [_ request]
(f request))))
(defn- resolve-handler (defn- resolve-handler
[handler] [handler]
(cond (cond
(fn? handler) (fn->handler handler) (fn? handler) (vu/fn->handler handler)
(instance? Handler handler) handler (instance? Handler handler) handler
:else (throw (ex-info "invalid handler" {})))) :else (throw (ex-info "invalid handler" {}))))
(defn- assign-status-and-headers!
[^HttpServerResponse res response]
(let [headers (:headers response)
status (:status response 200)]
(when (map? headers)
(vu/doseq [[key val] headers]
(.putHeader res ^String (name key) ^String (str val))))
(.setStatusCode res status)))
(defprotocol IAsyncResponse
(-handle-response [_ _]))
(defprotocol IAsyncBody
(-handle-body [_ _]))
(extend-protocol IAsyncResponse
java.util.concurrent.CompletionStage
(-handle-response [data ctx]
(p/then' data #(-handle-response % ctx)))
clojure.lang.IPersistentMap
(-handle-response [data ctx]
(let [body (:body data)
res (::response ctx)]
(assign-status-and-headers! res data)
(-handle-body body res))))
(extend-protocol IAsyncBody
(Class/forName "[B")
(-handle-body [data res]
(.end ^HttpServerResponse res (Buffer/buffer data)))
Buffer
(-handle-body [data res]
(.end ^HttpServerResponse res ^Buffer data))
nil
(-handle-body [data res]
(.putHeader ^HttpServerResponse res "content-length" "0")
(.end ^HttpServerResponse res))
String
(-handle-body [data res]
(let [length (count data)]
(.putHeader ^HttpServerResponse res "content-length" (str length))
(.end ^HttpServerResponse res data))))

View file

@ -33,23 +33,3 @@
java.lang.AutoCloseable java.lang.AutoCloseable
(close [_] (close [_]
(.cancelTimer system timer-id))))) (.cancelTimer system timer-id)))))
(defn schedule-task!
[vsm ms f]
(let [^Vertx system (vu/resolve-system vsm)
tid* (atom nil)
task (fn wrapped-task []
(-> (p/do! (f))
(p/then (fn [_]
(let [tid (schedule-task! vsm ms wrapped-task)]
(reset! tid* tid)
nil)))))
tid (schedule-task! vsm ms task)]
(reset! tid* tid)
(reify
java.lang.AutoCloseable
(close [this]
(locking this
(when-let [timer-id (deref tid*)]
(.cancelTimer system timer-id)
(reset! tid* nil)))))))

View file

@ -5,6 +5,7 @@
;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2019 Andrey Antukh <niwi@niwi.nz>
(ns vertx.util (ns vertx.util
(:refer-clojure :exclude [doseq])
(:require [promesa.core :as p]) (:require [promesa.core :as p])
(:import io.vertx.core.Vertx (:import io.vertx.core.Vertx
io.vertx.core.Handler io.vertx.core.Handler
@ -38,3 +39,13 @@
(p/reject! d (.cause ar)) (p/reject! d (.cause ar))
(p/resolve! d (.result ar)))))) (p/resolve! d (.result ar))))))
(defmacro doseq
"A faster version of doseq."
[[bsym csym] & body]
`(let [it# (.iterator ~csym)]
(loop []
(when (.hasNext it#)
(let [~bsym (.next it#)]
~@body
(recur))))))

View file

@ -1,87 +0,0 @@
;; 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) 2019 Andrey Antukh <niwi@niwi.nz>
(ns vertx.util.transit
(:require [cognitect.transit :as t]
[clojure.java.io :as io])
(:import java.io.ByteArrayInputStream
java.io.ByteArrayOutputStream
java.time.Instant))
(def ^:private write-handler
(t/write-handler
(constantly "m")
(fn [v] (str (.toEpochMilli v)))))
(def ^:private read-handler
(t/read-handler
(fn [v] (-> (Long/parseLong v)
(Instant/ofEpochMilli)))))
(def +read-handlers+
{"m" read-handler})
(def +write-handlers+
{Instant write-handler})
(defmethod print-method Instant
[mv ^java.io.Writer writer]
(.write writer (str "#instant \"" (.toString mv) "\"")))
(defmethod print-dup Instant [o w]
(print-method o w))
;; --- Low-Level Api
(defn reader
([istream]
(reader istream nil))
([istream {:keys [type] :or {type :msgpack}}]
(t/reader istream type {:handlers +read-handlers+})))
(defn read!
"Read value from streamed transit reader."
[reader]
(t/read reader))
(defn writer
([ostream]
(writer ostream nil))
([ostream {:keys [type] :or {type :msgpack}}]
(t/writer ostream type {:handlers +write-handlers+})))
(defn write!
[writer data]
(t/write writer data))
;; --- High-Level Api
;; TODO: check performance of different options
(defn decode
([data]
(decode data nil))
([data opts]
(cond
(string? data)
(decode (.getBytes data "UTF-8") opts)
(bytes? data)
(with-open [input (ByteArrayInputStream. data)]
(read! (reader input opts)))
:else
(with-open [input (io/input-stream data)]
(read! (reader input opts))))))
(defn encode
(^bytes [data]
(encode data nil))
(^bytes [data opts]
(with-open [out (ByteArrayOutputStream.)]
(let [w (writer out opts)]
(write! w data)
(.toByteArray out)))))

View file

@ -6,36 +6,33 @@
(ns vertx.web (ns vertx.web
"High level api for http servers." "High level api for http servers."
(:require [clojure.spec.alpha :as s] (:require
[promesa.core :as p] [clojure.tools.logging :as log]
[sieppari.core :as sp] [clojure.spec.alpha :as s]
[reitit.core :as rt] [promesa.core :as p]
[vertx.http :as vxh] [sieppari.core :as sp]
[vertx.util :as vu]) [reitit.core :as rt]
[vertx.http :as vh]
[vertx.util :as vu])
(:import (:import
clojure.lang.Keyword
clojure.lang.IPersistentMap clojure.lang.IPersistentMap
io.vertx.core.Vertx clojure.lang.Keyword
io.vertx.core.Handler
io.vertx.core.Future io.vertx.core.Future
io.vertx.core.Handler
io.vertx.core.Vertx
io.vertx.core.buffer.Buffer io.vertx.core.buffer.Buffer
io.vertx.core.http.Cookie io.vertx.core.http.Cookie
io.vertx.core.http.HttpServer io.vertx.core.http.HttpServer
io.vertx.core.http.HttpServerOptions
io.vertx.core.http.HttpServerRequest io.vertx.core.http.HttpServerRequest
io.vertx.core.http.HttpServerResponse io.vertx.core.http.HttpServerResponse
io.vertx.core.http.HttpServerOptions
io.vertx.ext.web.Route io.vertx.ext.web.Route
io.vertx.ext.web.Router io.vertx.ext.web.Router
io.vertx.ext.web.RoutingContext io.vertx.ext.web.RoutingContext
io.vertx.ext.web.handler.BodyHandler io.vertx.ext.web.handler.BodyHandler
io.vertx.ext.web.handler.StaticHandler io.vertx.ext.web.handler.LoggerHandler
io.vertx.ext.web.handler.ResponseTimeHandler io.vertx.ext.web.handler.ResponseTimeHandler
io.vertx.ext.web.handler.LoggerHandler)) io.vertx.ext.web.handler.StaticHandler))
;; --- Constants & Declarations
(declare -handle-response)
(declare -handle-body)
;; --- Public Api ;; --- Public Api
@ -43,16 +40,17 @@
(s/or :fn fn? (s/or :fn fn?
:vec (s/every fn? :kind vector?))) :vec (s/every fn? :kind vector?)))
(defn- make-ctx (defn- ->request
[^RoutingContext routing-context] [^RoutingContext routing-context]
(let [^HttpServerRequest request (.request ^RoutingContext routing-context) (let [^HttpServerRequest request (.request ^RoutingContext routing-context)
^HttpServerResponse response (.response ^RoutingContext routing-context) ^HttpServerResponse response (.response ^RoutingContext routing-context)
^Vertx system (.vertx routing-context)] ^Vertx system (.vertx routing-context)]
{:body (.getBody routing-context) {:body (.getBody routing-context)
:path (.path request) :path (.path request)
:headers (vh/->headers request)
:method (-> request .rawMethod .toLowerCase keyword) :method (-> request .rawMethod .toLowerCase keyword)
::request request ::vh/request request
::response response ::vh/response response
::execution-context (.getContext system) ::execution-context (.getContext system)
::routing-context routing-context})) ::routing-context routing-context}))
@ -84,6 +82,12 @@
{:status 405} {:status 405}
{:status 404})) {:status 404}))
(defn- default-on-error
[err req]
(log/error err)
{:status 500
:body "Internal server error!\n"})
(defn- run-chain (defn- run-chain
[ctx chain handler] [ctx chain handler]
(let [d (p/deferred)] (let [d (p/deferred)]
@ -106,64 +110,47 @@
([routes] (router routes {})) ([routes] (router routes {}))
([routes {:keys [delete-uploads? ([routes {:keys [delete-uploads?
upload-dir upload-dir
on-error
log-requests? log-requests?
time-response?] time-response?]
:or {delete-uploads? true :or {delete-uploads? true
upload-dir "/tmp/vertx.uploads" upload-dir "/tmp/vertx.uploads"
on-error default-on-error
log-requests? false log-requests? false
time-response? true} time-response? true}
:as options}] :as options}]
(let [rtr (rt/router routes options) (let [rtr (rt/router routes options)
hdr #(router-handler rtr %)] f #(router-handler rtr %)]
(fn [^Router router] (fn [^Router router]
(let [^Route route (.route router)] (let [^Route route (.route router)]
(when time-response? (.handler route (ResponseTimeHandler/create))) (when time-response? (.handler route (ResponseTimeHandler/create)))
(when log-requests? (.handler route (LoggerHandler/create))) (when log-requests? (.handler route (LoggerHandler/create)))
(.handler route (doto (BodyHandler/create true) (doto route
(.setDeleteUploadedFilesOnEnd delete-uploads?) (.failureHandler
(.setUploadsDirectory upload-dir))) (reify Handler
(.handler route (reify Handler (handle [_ rc]
(handle [_ context] (let [err (.failure ^RoutingContext rc)
(let [ctx (make-ctx context)] req (.get ^RoutingContext rc "vertx$clj$req")]
(-> (p/do! (hdr ctx)) (-> (p/do! (on-error err req))
(p/then' #(-handle-response % ctx)) (vh/-handle-response req))))))
(p/catch #(do (prn %) (.fail (:context ctx) %)))))))))
router))))
;; --- Impl (.handler
(doto (BodyHandler/create true)
(.setDeleteUploadedFilesOnEnd delete-uploads?)
(.setUploadsDirectory upload-dir)))
(defprotocol IAsyncResponse
(-handle-response [_ _]))
(extend-protocol IAsyncResponse (.handler
clojure.lang.IPersistentMap (reify Handler
(-handle-response [data ctx] (handle [_ rc]
(let [status (or (:status data) 200) (let [req (->request rc)
body (:body data) efn (fn [err]
res (::response ctx)] (.put ^RoutingContext rc "vertx$clj$req" req)
(.setStatusCode ^HttpServerResponse res status) (.fail ^RoutingContext rc err))]
(-handle-body body res)))) (try
(-> (vh/-handle-response (f req) req)
(defprotocol IAsyncBody (p/catch' efn))
(-handle-body [_ _])) (catch Exception err
(efn err)))))))))
(extend-protocol IAsyncBody router))))
(Class/forName "[B")
(-handle-body [data res]
(.end ^HttpServerResponse res (Buffer/buffer data)))
Buffer
(-handle-body [data res]
(.end ^HttpServerResponse res ^Buffer data))
nil
(-handle-body [data res]
(.putHeader ^HttpServerResponse res "content-length" "0")
(.end ^HttpServerResponse res))
String
(-handle-body [data res]
(let [length (count data)]
(.putHeader ^HttpServerResponse res "content-length" (str length))
(.end ^HttpServerResponse res data))))

View file

@ -11,22 +11,25 @@
[clojure.string :as str] [clojure.string :as str]
[promesa.core :as p] [promesa.core :as p]
[reitit.core :as r] [reitit.core :as r]
[vertx.http :as vh]
[vertx.web :as vw] [vertx.web :as vw]
[vertx.util :as vu]
[sieppari.context :as spx] [sieppari.context :as spx]
[sieppari.core :as sp]) [sieppari.core :as sp])
(:import (:import
clojure.lang.Keyword clojure.lang.Keyword
clojure.lang.MapEntry clojure.lang.MapEntry
java.util.Map
java.util.Map$Entry
io.vertx.core.Vertx
io.vertx.core.Handler
io.vertx.core.Future io.vertx.core.Future
io.vertx.core.Handler
io.vertx.core.MultiMap
io.vertx.core.Vertx
io.vertx.core.http.Cookie io.vertx.core.http.Cookie
io.vertx.core.http.HttpServerRequest io.vertx.core.http.HttpServerRequest
io.vertx.core.http.HttpServerResponse io.vertx.core.http.HttpServerResponse
io.vertx.ext.web.FileUpload io.vertx.ext.web.FileUpload
io.vertx.ext.web.RoutingContext)) io.vertx.ext.web.RoutingContext
java.util.Map
java.util.Map$Entry))
;; --- Cookies ;; --- Cookies
@ -40,71 +43,50 @@
(defn cookies (defn cookies
[] []
{:enter (fn [data] {:enter
(let [^HttpServerRequest req (get-in data [:request ::vw/request]) (fn [data]
parse-cookie (fn [^Cookie item] [(.getName item) (.getValue item)]) (let [^HttpServerRequest req (get-in data [:request ::vh/request])
cookies (into {} (map parse-cookie) (vals (.cookieMap req)))] parse-cookie (fn [^Cookie item] [(.getName item) (.getValue item)])
(update data :request assoc :cookies cookies))) cookies (into {} (map parse-cookie) (vals (.cookieMap req)))]
:leave (fn [data] (update data :request assoc :cookies cookies)))
(let [cookies (get-in data [:response :cookies]) :leave
^HttpServerResponse res (get-in data [:request ::vw/response])] (fn [data]
(when (map? cookies) (let [cookies (get-in data [:response :cookies])
(reduce-kv #(.addCookie res (build-cookie %1 %2)) nil cookies)) ^HttpServerResponse res (get-in data [:request ::vh/response])]
data))}) (when (map? cookies)
;; --- Headers (vu/doseq [[key val] cookies]
(.addCookie res (build-cookie key val))))
(def ^:private lowercase-keys-t data))})
(map (fn [^Map$Entry entry]
(MapEntry. (.toLowerCase (.getKey entry)) (.getValue entry)))))
(defn- parse-headers
[req]
(let [^HttpServerRequest request (::vw/request req)]
(into {} lowercase-keys-t (.headers request))))
(defn headers
[]
{:enter (fn [data]
(update data :request assoc :headers (parse-headers (:request data))))
:leave (fn [data]
(let [^HttpServerResponse res (get-in data [:request ::vw/response])
headers (get-in data [:response :headers])]
(run! (fn [[key value]]
(.putHeader ^HttpServerResponse res
^String (name key)
^String (str value)))
headers)
data))})
;; --- Params ;; --- Params
(defn- parse-param-entry
[acc ^Map$Entry item]
(let [key (keyword (.toLowerCase (.getKey item)))
prv (get acc key ::default)]
(cond
(= prv ::default)
(assoc! acc key (.getValue item))
(vector? prv)
(assoc! acc key (conj prv (.getValue item)))
:else
(assoc! acc key [prv (.getValue item)]))))
(defn- parse-params (defn- parse-params
[req] [^HttpServerRequest request]
(let [request (::vw/request req)] (let [params (.params request)
(persistent! it (.iterator ^MultiMap params)]
(reduce parse-param-entry (loop [m (transient {})]
(transient {}) (if (.hasNext it)
(.params ^HttpServerResponse request))))) (let [^Map$Entry o (.next it)
key (keyword (.toLowerCase (.getKey o)))
prv (get m key ::default)
val (.getValue o)]
(cond
(= prv ::default)
(recur (assoc! m key val))
(vector? prv)
(recur (assoc! m key (conj prv val)))
:else
(recur (assoc! m key [prv val]))))
(persistent! m)))))
(defn params (defn params
([] (params nil)) ([] (params nil))
([{:keys [attr] :or {attr :params}}] ([{:keys [attr] :or {attr :params}}]
{:enter (fn [data] {:enter (fn [data]
(let [params (parse-params (:request data))] (let [request (get-in data [:request ::vh/request])
params (parse-params request)]
(update data :request assoc attr params)))})) (update data :request assoc attr params)))}))
;; --- Uploads ;; --- Uploads