From a30ff6ec3790143a85d27278ca98f1a8f92c45aa Mon Sep 17 00:00:00 2001 From: Thomas Crowley Date: Mon, 27 Jul 2020 23:01:43 +1000 Subject: [PATCH] [#371 #375] Add Jetty 9 server adapter (@wavejumper) --- README.md | 3 +- example-project/project.clj | 1 + example-project/src/example/server.clj | 13 +++-- project.clj | 3 +- src/taoensso/sente/server_adapters/jetty9.clj | 51 +++++++++++++++++++ 5 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/taoensso/sente/server_adapters/jetty9.clj diff --git a/README.md b/README.md index 6d232d01..f3b4614f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ * Standard **Ring security model**: auth as you like, HTTPS when available, CSRF support, etc. * **Fully documented, with examples** * **Small codebase**: ~1.5k lines for the entire client+server implementation - * **Supported servers**: [http-kit], [Immutant v2+], [nginx-clojure], node.js, [Aleph] + * **Supported servers**: [http-kit], [Immutant v2+], [nginx-clojure], node.js, [Aleph], [ring-jetty9-adapter] ### Capabilities @@ -422,6 +422,7 @@ Copyright © 2014-2016 [Peter Taoussanis]. [nginx-clojure]: https://github.com/nginx-clojure/nginx-clojure [Aleph]: https://github.com/ztellman/aleph [example projects]: #example-projects +[ring-jetty9-adapter]: https://github.com/sunng87/ring-jetty9-adapter [supported web servers]: https://github.com/ptaoussanis/sente/issues/102 diff --git a/example-project/project.clj b/example-project/project.clj index 184bc04a..79ee0cea 100644 --- a/example-project/project.clj +++ b/example-project/project.clj @@ -24,6 +24,7 @@ ;; :exclusions [ring/ring-core]] ;; [nginx-clojure/nginx-clojure-embed "0.4.4"] ; Needs v0.4.2+ ;; [aleph "0.4.1"] + ;; [info.sunng/ring-jetty9-adapter "0.13.0"] ;; ----------------------------------------------------------------------- [ring "1.8.1"] diff --git a/example-project/src/example/server.clj b/example-project/src/example/server.clj index 70bcc3fb..ff094176 100644 --- a/example-project/src/example/server.clj +++ b/example-project/src/example/server.clj @@ -17,15 +17,22 @@ ;;; TODO Choose (uncomment) a supported web server + adapter ------------- [org.httpkit.server :as http-kit] [taoensso.sente.server-adapters.http-kit :refer (get-sch-adapter)] - ;; + ;; [immutant.web :as immutant] ;; [taoensso.sente.server-adapters.immutant :refer (get-sch-adapter)] - ;; + ;; [nginx.clojure.embed :as nginx-clojure] ;; [taoensso.sente.server-adapters.nginx-clojure :refer (get-sch-adapter)] - ;; + ;; [aleph.http :as aleph] ;; [taoensso.sente.server-adapters.aleph :refer (get-sch-adapter)] + + ;; [ring.adapter.jetty9.websocket :as jetty9.websocket] + ;; [taoensso.sente.server-adapters.jetty9 :refer (get-sch-adapter)] + ;; + ;; See https://gist.github.com/wavejumper/40c4cbb21d67e4415e20685710b68ea0 + ;; for full example using Jetty 9 + ;; ----------------------------------------------------------------------- ;; Optional, for Transit encoding: diff --git a/project.clj b/project.clj index 3fa334bc..464feb8a 100644 --- a/project.clj +++ b/project.clj @@ -43,7 +43,8 @@ [nginx-clojure "0.5.1"] [aleph "0.4.6"] [macchiato/core "0.2.19"] - [luminus/ring-undertow-adapter "1.1.1"]]}]} + [luminus/ring-undertow-adapter "1.1.1"] + [info.sunng/ring-jetty9-adapter "0.13.0"]]}]} :cljsbuild {:test-commands {"node" ["node" :node-runner "target/main.js"] diff --git a/src/taoensso/sente/server_adapters/jetty9.clj b/src/taoensso/sente/server_adapters/jetty9.clj new file mode 100644 index 00000000..8243b41a --- /dev/null +++ b/src/taoensso/sente/server_adapters/jetty9.clj @@ -0,0 +1,51 @@ +(ns taoensso.sente.server-adapters.jetty9 + "Sente adapter for ring-jetty9-adapter, + (https://github.com/sunng87/ring-jetty9-adapter). + + Note that ring-jetty9-adapter defines WebSocket routes/handlers + separately from regular Ring routes/handlers [1,2]. + + This can make it tricky to set up stateful middleware correctly + (for example as you may want to do for CSRF protection). + + See [3] for a full example. + + [1] https://github.com/sunng87/ring-jetty9-adapter/blob/master/examples/rj9a/websocket.clj + [2] https://github.com/sunng87/ring-jetty9-adapter/issues/41#issuecomment-630206233 + [3] https://gist.github.com/wavejumper/40c4cbb21d67e4415e20685710b68ea0" + + {:author "Thomas Crowley (@wavejumper)"} + (:require [clojure.string :as str] + [ring.adapter.jetty9.websocket :as jetty9.websocket] + [taoensso.sente.interfaces :as i])) + +(defn- ajax-cbs [sch] + {:write-failed (fn [_throwable] (jetty9.websocket/close! sch)) + :write-success (fn [ ] (jetty9.websocket/close! sch))}) + +(extend-type org.eclipse.jetty.websocket.api.WebSocketAdapter + i/IServerChan + (sch-open? [sch] (jetty9.websocket/connected? sch)) + (sch-close! [sch] (jetty9.websocket/close! sch)) + (sch-send! [sch websocket? msg] + (if websocket? + (jetty9.websocket/send! sch msg) + (jetty9.websocket/send! sch msg (ajax-cbs sch))))) + +(defn- server-ch-resp + [websocket? {:keys [on-open on-close on-msg on-error]}] + {:on-connect (fn [sch ] (on-open sch websocket?)) + :on-text (fn [sch msg ] (on-msg sch websocket? msg)) + :on-error (fn [sch error ] (on-error sch websocket? error)) + :on-close (fn [sch status _] (on-close sch websocket? status))}) + +(defn- websocket-req? [ring-req] + (when-let [s (get-in ring-req [:headers "upgrade"])] + (= "websocket" (str/lower-case s)))) + +(deftype JettyServerChanAdapter [] + i/IServerChanAdapter + (ring-req->server-ch-resp [_ req callbacks-map] + (server-ch-resp (websocket-req? req) callbacks-map))) + +(defn get-sch-adapter [] (JettyServerChanAdapter.))