forked from clj-commons/etaoin
/
client.clj
110 lines (93 loc) · 2.89 KB
/
client.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
(ns etaoin.client
(:require [cheshire.core :as cheshire :refer [parse-string]]
[clj-http.lite.client :as client]
[clojure.string :as str]
[clojure.tools.logging :as log]
[slingshot.slingshot :refer [throw+]]))
;;
;; defaults
;;
(def default-timeout
"HTTP timeout in seconds. The current value may seems to high,
but according to my experience with SPA application full of React
modules even 20 seconds could not be enough for a driver to process
your request."
60)
(defn read-timeout []
(if-let [t (System/getenv "ETAOIN_TIMEOUT")]
(Integer/parseInt t)
default-timeout))
(def timeout (read-timeout))
(def default-api-params
{:accept :json
:content-type :json
:socket-timeout (* 1000 timeout)
:conn-timeout (* 1000 timeout)
:debug false})
;;
;; helpers
;;
(defn- url-item-str [item]
(cond
(keyword? item) (name item)
(symbol? item) (name item)
(string? item) item
:else (str item)))
(defn- get-url-path [items]
(str/join "/" (map url-item-str items)))
(defn- status-selector [resp]
(-> resp :status integer?))
(defmacro with-pool [opt & body]
`(client/with-connection-pool ~opt
~@body))
(defn- parse-json [body]
(let [body* (str/replace body #"Invalid Command Method -" "")]
(try
(parse-string body* true)
(catch Throwable _ body))))
(defn- error-response [body]
(if (string? body)
(parse-json body)
body))
;;
;; client
;;
(defn call
[{driver-type :type :keys [host port] :as driver}
method path-args payload]
(let [path (get-url-path path-args)
url (format "http://%s:%s/%s" host port path)
params (merge default-api-params
{:url url
:method method
:body
;; when using get, :body must be absent in clj-http-lite
(when-not (identical? method :get)
(cheshire/generate-string (or payload {})))
:throw-exceptions false})
_ (log/debugf "%s %s:%s %6s %s %s"
(name driver-type)
host
port
(-> method name str/upper-case)
path
(-> payload (or "")))
resp (client/request params)
body (:body resp)
body (parse-json body)
error (delay {:type :etaoin/http-error
:status (:status resp)
:driver driver
:response (error-response body)
:host host
:port port
:method method
:path path
:payload payload})]
(cond
(-> resp :status (not= 200))
(throw+ @error)
(-> body :status (or 0) (> 0))
(throw+ @error)
:else
body)))