|
11 | 11 | [promesa.core :as p] |
12 | 12 | [vertx.util :as vu]) |
13 | 13 | (:import |
| 14 | + java.util.Map$Entry |
| 15 | + clojure.lang.MapEntry |
14 | 16 | io.vertx.core.Vertx |
15 | 17 | io.vertx.core.Verticle |
16 | 18 | io.vertx.core.Handler |
17 | 19 | io.vertx.core.Future |
| 20 | + io.vertx.core.MultiMap |
18 | 21 | io.vertx.core.Context |
| 22 | + io.vertx.core.buffer.Buffer |
19 | 23 | io.vertx.core.http.HttpServer |
20 | 24 | io.vertx.core.http.HttpServerRequest |
21 | 25 | io.vertx.core.http.HttpServerResponse |
|
26 | 30 |
|
27 | 31 | ;; --- Public Api |
28 | 32 |
|
| 33 | +(declare -handle-response) |
| 34 | +(declare -handle-body) |
| 35 | + |
| 36 | +(defn ->headers |
| 37 | + [^HttpServerRequest request] |
| 38 | + (let [headers (.headers request) |
| 39 | + it (.iterator ^MultiMap headers)] |
| 40 | + (loop [m (transient {})] |
| 41 | + (if (.hasNext it) |
| 42 | + (let [^Map$Entry me (.next it) |
| 43 | + key (.toLowerCase (.getKey me)) |
| 44 | + val (.getValue me)] |
| 45 | + (recur (assoc! m key val))) |
| 46 | + (persistent! m))))) |
| 47 | + |
| 48 | +(defn- ->request |
| 49 | + [^HttpServerRequest request] |
| 50 | + {:method (-> request .rawMethod .toLowerCase keyword) |
| 51 | + :path (.path request) |
| 52 | + :headers (->headers request) |
| 53 | + ::request request |
| 54 | + ::response (.response request)}) |
| 55 | + |
| 56 | +(defn handler |
| 57 | + [vsm f] |
| 58 | + (reify Handler |
| 59 | + (handle [this request] |
| 60 | + (let [ctx (->request request)] |
| 61 | + (-handle-response (f ctx) ctx))))) |
| 62 | + |
29 | 63 | (s/def :vertx.http/handler fn?) |
30 | 64 | (s/def :vertx.http/host string?) |
31 | 65 | (s/def :vertx.http/port pos?) |
|
60 | 94 | (when port (.setPort opts port)) |
61 | 95 | opts)) |
62 | 96 |
|
63 | | -(defn- fn->handler |
64 | | - [f] |
65 | | - (reify Handler |
66 | | - (handle [_ request] |
67 | | - (f request)))) |
68 | | - |
69 | 97 | (defn- resolve-handler |
70 | 98 | [handler] |
71 | 99 | (cond |
72 | | - (fn? handler) (fn->handler handler) |
| 100 | + (fn? handler) (vu/fn->handler handler) |
73 | 101 | (instance? Handler handler) handler |
74 | 102 | :else (throw (ex-info "invalid handler" {})))) |
| 103 | + |
| 104 | +(defprotocol IAsyncResponse |
| 105 | + (-handle-response [_ _])) |
| 106 | + |
| 107 | +(defprotocol IAsyncBody |
| 108 | + (-handle-body [_ _])) |
| 109 | + |
| 110 | +(extend-protocol IAsyncResponse |
| 111 | + java.util.concurrent.CompletionStage |
| 112 | + (-handle-response [data ctx] |
| 113 | + (p/then' data #(-handle-response % ctx))) |
| 114 | + |
| 115 | + clojure.lang.IPersistentMap |
| 116 | + (-handle-response [data ctx] |
| 117 | + (let [status (or (:status data) 200) |
| 118 | + body (:body data) |
| 119 | + res (::response ctx)] |
| 120 | + (.setStatusCode ^HttpServerResponse res status) |
| 121 | + (-handle-body body res)))) |
| 122 | + |
| 123 | +(extend-protocol IAsyncBody |
| 124 | + (Class/forName "[B") |
| 125 | + (-handle-body [data res] |
| 126 | + (.end ^HttpServerResponse res (Buffer/buffer data))) |
| 127 | + |
| 128 | + Buffer |
| 129 | + (-handle-body [data res] |
| 130 | + (.end ^HttpServerResponse res ^Buffer data)) |
| 131 | + |
| 132 | + nil |
| 133 | + (-handle-body [data res] |
| 134 | + (.putHeader ^HttpServerResponse res "content-length" "0") |
| 135 | + (.end ^HttpServerResponse res)) |
| 136 | + |
| 137 | + String |
| 138 | + (-handle-body [data res] |
| 139 | + (let [length (count data)] |
| 140 | + (.putHeader ^HttpServerResponse res "content-length" (str length)) |
| 141 | + (.end ^HttpServerResponse res data)))) |
0 commit comments