Last active
May 20, 2020 11:39
-
-
Save mszajna/7d5d7ed8924dd62f84a981c6fc18ed1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn async? [response] | |
(instance? java.util.concurrent.CompletionStage response)) | |
(defn- cs-handle [cs f] | |
(.handle ^java.util.concurrent.CompletionStage cs | |
(reify java.util.function.BiFunction | |
(apply [_ v t] (f v t))))) | |
(defn wrap-completable-future | |
"Adapts a 1-arity handler, returning either a response map or one wrapped | |
in CompletionStage, to a 3-arity handler." | |
[handler] | |
(fn [request respond raise] | |
(let [response (handler request)] | |
(if (async? response) | |
(cs-handle response | |
(fn [response-map ex] | |
(if ex (raise ex) (respond response-map)))) | |
(respond response))))) | |
(defn wrap-3arity | |
"Turns an asynchronous 3-arity handler into a CompletionStage based 1-arity | |
one." | |
[handler] | |
(fn [request] | |
(let [cf (new java.util.concurrent.CompletableFuture)] | |
; exposed to help catch callback exceptions | |
(handler (assoc request :completable-future cf) | |
(fn [response] (.complete cf response)) | |
(fn [ex] (.completeExceptionally cf ex))) | |
cf))) | |
(defn wrap-callback-exceptions | |
"Handles bubbling callback exceptions. Note that logically, this is inverse of | |
try-catch - it catches exceptions from middleware that was applied after this, | |
not before." | |
[handler on-callback-exception] | |
(fn [request respond raise] | |
(handler request | |
(fn [response] (try (respond response) | |
(catch Throwable t | |
(on-callback-exception t request)))) | |
(fn [ex] (try (raise ex) | |
(catch Throwable t | |
(on-callback-exception t request))))))) | |
(defn adapt | |
"Adapts the asynchronous 3-arity middleware to one that supports | |
CompletionStage, and applies it to the handler with args. | |
Exceptions thrown in middleware's callbacks propagate correctly." | |
[handler middleware & args] | |
(-> handler | |
wrap-completable-future | |
(wrap-callback-exceptions (fn [t req] | |
(when-let [cf (:completable-future req)] | |
(.completeExceptionally cf t)))) | |
(#(apply %2 %1 %3) middleware args) | |
wrap-3arity)) | |
(comment | |
(defn a-handler [request] | |
(java.util.concurrent.CompletableFuture/completedFuture | |
{:status 200 :body (get-in request [:query-params "q"])})) | |
(def app-handler | |
(-> a-handler ; 1-arity CF-returning handler | |
(adapt ring.middleware.head/wrap-head) ; adapt wrap-head to return a CF | |
ring.middleware.params/wrap-params ; use compatible 1-arity directly | |
wrap-completable-future)) ; adapt for use with ring-jetty | |
(app-handler {:query-string "q=test"} println println)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment