add clj-browserchannel-jetty-adapter
This commit is contained in:
parent
8fce5be473
commit
9142fd6486
10
clj-browserchannel-jetty-adapter/.gitignore
vendored
Normal file
10
clj-browserchannel-jetty-adapter/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/target
|
||||||
|
/lib
|
||||||
|
/classes
|
||||||
|
/checkouts
|
||||||
|
pom.xml
|
||||||
|
*.jar
|
||||||
|
*.class
|
||||||
|
.lein-deps-sum
|
||||||
|
.lein-failures
|
||||||
|
.lein-plugins
|
16
clj-browserchannel-jetty-adapter/README.md
Normal file
16
clj-browserchannel-jetty-adapter/README.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# clj-browserchannel-jetty-adapter
|
||||||
|
|
||||||
|
Jetty async adapter for BrowserChannel
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
Written by:
|
||||||
|
Gijs Stuurman / [@thegeez][twt] / [Blog][blog] / [GitHub][github]
|
||||||
|
|
||||||
|
[twt]: http://twitter.com/thegeez
|
||||||
|
[blog]: http://thegeez.github.com
|
||||||
|
[github]: https://github.com/thegeez
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
Copyright (c) 2012 Gijs Stuurman and released under an MIT license.
|
9
clj-browserchannel-jetty-adapter/project.clj
Normal file
9
clj-browserchannel-jetty-adapter/project.clj
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
(defproject net.thegeez/clj-browserchannel-jetty-adapter "0.0.1"
|
||||||
|
:description "Jetty async adapter for BrowserChannel"
|
||||||
|
:url ""
|
||||||
|
:dependencies [[org.clojure/clojure "1.3.0"]
|
||||||
|
[ring/ring-core "1.1.0-beta3"]
|
||||||
|
[ring/ring-servlet "1.1.0-beta3" :exclusions [javax.servlet/servlet-api]]
|
||||||
|
[org.eclipse.jetty/jetty-server "8.1.2.v20120308"];; includes ssl
|
||||||
|
[net.thegeez/clj-browserchannel-server "0.0.1"]
|
||||||
|
])
|
|
@ -0,0 +1,92 @@
|
||||||
|
(ns net.thegeez.jetty-async-adapter
|
||||||
|
"BrowserChannel adapter for the Jetty webserver, with async HTTP."
|
||||||
|
(:import (org.eclipse.jetty.server.handler AbstractHandler)
|
||||||
|
(org.eclipse.jetty.server Server Request Response)
|
||||||
|
(org.eclipse.jetty.server.nio SelectChannelConnector)
|
||||||
|
(org.eclipse.jetty.continuation Continuation ContinuationSupport ContinuationListener)
|
||||||
|
(org.eclipse.jetty.io EofException)
|
||||||
|
(javax.servlet.http HttpServletRequest))
|
||||||
|
(:require [ring.util.servlet :as servlet]
|
||||||
|
[net.thegeez.async-adapter :as async-adapter]))
|
||||||
|
|
||||||
|
;; Based on ring-jetty-async-adapter by Mark McGranaghan
|
||||||
|
;; (https://github.com/mmcgrana/ring/tree/jetty-async)
|
||||||
|
;; This has failed write support
|
||||||
|
|
||||||
|
(deftype JettyAsyncResponse [continuation]
|
||||||
|
async-adapter/IAsyncAdapter
|
||||||
|
(head [this status headers]
|
||||||
|
(doto (.getServletResponse continuation)
|
||||||
|
(servlet/set-status status)
|
||||||
|
(servlet/set-headers (assoc headers
|
||||||
|
"Transfer-Encoding" "chunked"))
|
||||||
|
(.flushBuffer)))
|
||||||
|
(write-chunk [this data]
|
||||||
|
(doto (.getWriter (.getServletResponse continuation))
|
||||||
|
(.write data)
|
||||||
|
(.flush))
|
||||||
|
(when (.checkError (.getWriter (.getServletResponse continuation)))
|
||||||
|
(throw async-adapter/ConnectionClosedException)))
|
||||||
|
(close [this]
|
||||||
|
(.complete continuation)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn- proxy-handler
|
||||||
|
"Returns an Jetty Handler implementation for the given Ring handler."
|
||||||
|
[handler options]
|
||||||
|
(proxy [AbstractHandler] []
|
||||||
|
(handle [target ^Request base-request ^HttpServletRequest request response]
|
||||||
|
(let [request-map (servlet/build-request-map request)
|
||||||
|
response-map (handler request-map)]
|
||||||
|
(condp = (:async response-map)
|
||||||
|
nil
|
||||||
|
(do
|
||||||
|
(servlet/update-servlet-response response response-map)
|
||||||
|
(.setHandled base-request true))
|
||||||
|
:http
|
||||||
|
(let [reactor (:reactor response-map)
|
||||||
|
;; continuation lives until written to!
|
||||||
|
continuation (.startAsync request)
|
||||||
|
emit (JettyAsyncResponse. continuation)]
|
||||||
|
(.addContinuationListener continuation
|
||||||
|
(proxy [ContinuationListener] []
|
||||||
|
(onComplete [c] nil)
|
||||||
|
(onTimeout [c]
|
||||||
|
(.complete c))))
|
||||||
|
|
||||||
|
;; 4 minutes is google default
|
||||||
|
(.setTimeout continuation (get options :response-timeout (* 4 60 1000)))
|
||||||
|
(reactor emit)
|
||||||
|
))))))
|
||||||
|
|
||||||
|
(defn- create-server
|
||||||
|
"Construct a Jetty Server instance."
|
||||||
|
[options]
|
||||||
|
(let [connector (doto (SelectChannelConnector.)
|
||||||
|
(.setPort (options :port 80))
|
||||||
|
(.setHost (options :host)))
|
||||||
|
server (doto (Server.)
|
||||||
|
(.addConnector connector)
|
||||||
|
(.setSendDateHeader true))]
|
||||||
|
server))
|
||||||
|
|
||||||
|
(defn ^Server run-jetty-async
|
||||||
|
"Serve the given handler according to the options.
|
||||||
|
Options:
|
||||||
|
:configurator - A function called with the Server instance.
|
||||||
|
:port
|
||||||
|
:host
|
||||||
|
:join? - Block the caller: defaults to true.
|
||||||
|
:response-timeout - Timeout after which the server will close the connection"
|
||||||
|
[handler options]
|
||||||
|
(let [^Server s (create-server (dissoc options :configurator))]
|
||||||
|
(when-let [configurator (:configurator options)]
|
||||||
|
(configurator s))
|
||||||
|
(doto s
|
||||||
|
(.setHandler (proxy-handler handler options))
|
||||||
|
(.start))
|
||||||
|
(when (:join? options true)
|
||||||
|
(.join s))
|
||||||
|
s))
|
Reference in a new issue