update jetty adapter to just use the jetty instance pulled in by ring

this also happens to be jetty 9, which is good as 7 and 8 are EOL
This commit is contained in:
Gered 2016-05-09 19:09:07 -04:00
parent 73bd151893
commit 579945fbda
5 changed files with 66 additions and 83 deletions

View file

@ -11,7 +11,7 @@
[clj-pebble "0.2.0"] [clj-pebble "0.2.0"]
[prismatic/dommy "1.1.0"] [prismatic/dommy "1.1.0"]
[gered/clj-browserchannel "0.3"] [gered/clj-browserchannel "0.3"]
[gered/clj-browserchannel-jetty-adapter "0.0.9"] [gered/clj-browserchannel-jetty-adapter "0.1.0"]
[gered/clj-browserchannel-immutant-adapter "0.0.1"] [gered/clj-browserchannel-immutant-adapter "0.0.1"]
[org.immutant/web "2.1.4"] [org.immutant/web "2.1.4"]
[environ "1.0.3"]] [environ "1.0.3"]]

View file

@ -44,7 +44,7 @@
(defn run-jetty [] (defn run-jetty []
(println "Using Jetty adapter") (println "Using Jetty adapter")
(jetty/run-jetty-async (jetty/run-jetty
#'handler #'handler
{:join? false {:join? false
:port 8080})) :port 8080}))
@ -58,7 +58,7 @@
(defn -main [& args] (defn -main [& args]
(if (env :dev) (pebble/set-options! :cache false)) (if (env :dev) (pebble/set-options! :cache false))
;(run-jetty) (run-jetty)
(run-immutant) ;(run-immutant)
) )

View file

@ -1,10 +1,17 @@
# clj-browserchannel-jetty-adapter # clj-browserchannel-jetty-adapter
Jetty async adapter for BrowserChannel Jetty async adapter for BrowserChannel. This now simply makes use of
whatever Jetty version that Ring's [ring-jetty-adapter][1] is using
and just adds the required async handling configuration on top of it.
[1]:https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter
See also: [clj-browserchannel][1] See also: [clj-browserchannel][1]
[1]:https://github.com/gered/clj-browserchannel [1]:https://github.com/gered/clj-browserchannel
## Leiningen
[gered/clj-browserchannel-jetty-adapter "0.1.0"]
## About ## About
Written by: Written by:

View file

@ -1,8 +1,8 @@
(defproject gered/clj-browserchannel-jetty-adapter "0.0.9" (defproject gered/clj-browserchannel-jetty-adapter "0.1.0"
:description "Jetty async adapter for BrowserChannel" :description "Jetty async adapter for BrowserChannel"
:dependencies [[ring/ring-core "1.4.0"] :dependencies [[ring/ring-core "1.4.0"]
[ring/ring-servlet "1.4.0"] [ring/ring-servlet "1.4.0"]
[org.eclipse.jetty/jetty-server "8.1.16.v20140903"];; includes ssl [ring/ring-jetty-adapter "1.4.0"]
[gered/clj-browserchannel "0.3"]] [gered/clj-browserchannel "0.3"]]
:profiles {:provided :profiles {:provided
{:dependencies {:dependencies

View file

@ -2,14 +2,11 @@
"BrowserChannel adapter for the Jetty webserver, with async HTTP." "BrowserChannel adapter for the Jetty webserver, with async HTTP."
(:import (:import
[org.eclipse.jetty.server.handler AbstractHandler] [org.eclipse.jetty.server.handler AbstractHandler]
[org.eclipse.jetty.server Server Request Response] [org.eclipse.jetty.server Server Request]
[org.eclipse.jetty.server.nio SelectChannelConnector] [javax.servlet AsyncContext AsyncListener AsyncEvent]
[org.eclipse.jetty.server.ssl SslSelectChannelConnector] [javax.servlet.http HttpServletRequest])
[org.eclipse.jetty.util.ssl SslContextFactory]
[org.eclipse.jetty.continuation Continuation ContinuationSupport ContinuationListener]
[javax.servlet.http HttpServletRequest]
[java.security KeyStore])
(:require (:require
[ring.adapter.jetty :as jetty]
[ring.util.servlet :as servlet] [ring.util.servlet :as servlet]
[net.thegeez.browserchannel.async-adapter :as async-adapter])) [net.thegeez.browserchannel.async-adapter :as async-adapter]))
@ -18,44 +15,26 @@
;; This has failed write support ;; This has failed write support
(deftype JettyAsyncResponse (deftype JettyAsyncResponse
[^Continuation continuation] [^AsyncContext async-context]
async-adapter/IAsyncAdapter async-adapter/IAsyncAdapter
(head [this status headers] (head [this status headers]
(doto (.getServletResponse continuation) (doto (.getResponse async-context)
(servlet/update-servlet-response {:status status :headers (assoc headers "Transfer-Encoding" "chunked")}) (servlet/update-servlet-response {:status status :headers (assoc headers "Transfer-Encoding" "chunked")})
(.flushBuffer))) (.flushBuffer)))
(write-chunk [this data] (write-chunk [this data]
(doto (.getWriter (.getServletResponse continuation)) (doto (.getWriter (.getResponse async-context))
(.write ^String data) (.write ^String data)
(.flush)) (.flush))
(when (.checkError (.getWriter (.getServletResponse continuation))) (when (.checkError (.getWriter (.getResponse async-context)))
(throw async-adapter/ConnectionClosedException))) (throw async-adapter/ConnectionClosedException)))
(close [this] (close [this]
(doto (.getWriter (.getServletResponse continuation)) (doto (.getWriter (.getResponse async-context))
(.write "") (.write "")
(.flush)) (.flush))
(.complete continuation))) (.complete async-context)))
(defn- add-ssl-connector!
"Add an SslSelectChannelConnector to a Jetty Server instance."
[^Server server options]
(let [ssl-context-factory (SslContextFactory.)]
(doto ssl-context-factory
(.setKeyStorePath (options :keystore))
(.setKeyStorePassword (options :key-password)))
(when (options :truststore)
(.setTrustStore ssl-context-factory ^KeyStore (options :truststore)))
(when (options :trust-password)
(.setTrustStorePassword ssl-context-factory (options :trust-password)))
(when (options :include-cipher-suites)
(.setIncludeCipherSuites ssl-context-factory (into-array (options :include-cipher-suites))))
(when (options :include-protocols)
(.setIncludeProtocols ssl-context-factory (into-array (options :include-protocols))))
(let [conn (SslSelectChannelConnector. ssl-context-factory)]
(.addConnector server (doto conn (.setPort (options :ssl-port 8443)))))))
(defn- proxy-handler (defn- proxy-handler
"Returns an Jetty Handler implementation for the given Ring handler." "Returns an Jetty Handler implementation for the given Ring handler."
@ -64,52 +43,49 @@
(handle [target ^Request base-request ^HttpServletRequest request response] (handle [target ^Request base-request ^HttpServletRequest request response]
(let [request-map (servlet/build-request-map request) (let [request-map (servlet/build-request-map request)
response-map (handler request-map)] response-map (handler request-map)]
(condp = (:async response-map) (when response-map
nil (condp = (:async response-map)
(do nil
(servlet/update-servlet-response response response-map) (do
(.setHandled base-request true)) (servlet/update-servlet-response response response-map)
:http (.setHandled base-request true))
(let [reactor (:reactor response-map)
continuation ^Continuation (.startAsync request) ;; continuation lives until written to!
emit (JettyAsyncResponse. continuation)]
(.addContinuationListener continuation
(proxy [ContinuationListener] []
(onComplete [c] nil)
(onTimeout [^Continuation c] (.complete c))))
;; 4 minutes is google default :http
(.setTimeout continuation (get options :response-timeout (* 4 60 1000))) (let [reactor (:reactor response-map)
(reactor emit))))))) async-context ^AsyncContext (.startAsync request) ;; continuation lives until written to!
emit (JettyAsyncResponse. async-context)]
(.addListener async-context
(proxy [AsyncListener] []
(onComplete [^AsyncEvent e]
nil)
(onTimeout [^AsyncEvent e]
(let [async-context ^AsyncContext (.getAsyncContext e)]
(.complete async-context)))))
(defn- create-server ;; 4 minutes is google default
"Construct a Jetty Server instance." (.setTimeout async-context (get options :response-timeout (* 4 60 1000)))
[options] (reactor emit))))))))
(let [connector (doto (SelectChannelConnector.)
(.setPort (options :port 80))
(.setHost (options :host)))
server (doto (Server.)
(.addConnector connector)
(.setSendDateHeader true))]
(when (or (options :ssl?) (options :ssl-port))
(add-ssl-connector! server options))
server))
(defn ^Server run-jetty-async (defn- configure-jetty-async!
"Serve the given handler according to the options. [^Server server handler options]
Options: (.setHandler server (proxy-handler handler options)))
:configurator - A function called with the Server instance.
:port (defn ^Server run-jetty
:host "Starts a Jetty webserver to serve the given handler with the
:join? - Block the caller: defaults to true. given options. This Jetty instance will have additional async
:response-timeout - Timeout after which the server will close the connection" support necessary for BrowserChannel sessions.
The available options are the same as those used by
ring.adapter.jetty/run-jetty, except for these additions:
:response-timeout - Timeout after which the server will close the connection.
Specified in milliseconds, default is 4 minutes which is
the timeout period Google uses."
[handler options] [handler options]
(let [^Server s (create-server (dissoc options :configurator))] (let [existing-configurator (:configurator options)
(when-let [configurator (:configurator options)] options (assoc options
(configurator s)) :configurator (fn [^Server server]
(doto s (if existing-configurator
(.setHandler (proxy-handler handler options)) (existing-configurator server))
(.start)) (configure-jetty-async! server handler options)))]
(when (:join? options true) (jetty/run-jetty handler options)))
(.join s))
s))