-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.clj
111 lines (99 loc) · 3.32 KB
/
common.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
111
(ns monkey.ci.web.common
(:require [buddy.auth :as ba]
[camel-snake-kebab.core :as csk]
[cheshire.core :as json]
[clojure.java.io :as io]
[clojure.tools.logging :as log]
[manifold.deferred :as md]
[muuntaja.core :as mc]
[monkey.ci
[build :as b]
[runtime :as rt]]
[reitit.ring :as ring]
[reitit.ring.coercion :as rrc]
[reitit.ring.middleware
[exception :as rrme]
[muuntaja :as rrmm]
[parameters :as rrmp]]
[ring.util.response :as rur]))
;; Reitit rewrites records in the data to hashmaps, so wrap it in a type
(deftype RuntimeWrapper [runtime])
(defn req->rt
"Gets the runtime from the request"
[req]
(some-> (get-in req [:reitit.core/match :data ::runtime])
(.runtime)))
(defn from-rt
"Applies `f` to the request runtime"
[req f]
(f (req->rt req)))
(defn req->storage
"Retrieves storage object from the request context"
[req]
(from-rt req :storage))
(defn make-muuntaja
"Creates muuntaja instance with custom settings"
[]
(mc/create
(-> mc/default-options
(assoc-in
;; Convert keys to kebab-case
[:formats "application/json" :decoder-opts]
{:decode-key-fn csk/->kebab-case-keyword})
(assoc-in
[:formats "application/json" :encoder-opts]
{:encode-key-fn (comp csk/->camelCase name)}))))
(defn- exception-logger [h]
(fn [req]
(try
(h req)
(catch Exception ex
;; Log and rethrow
(log/error (str "Got error while handling request" (:uri req)) ex)
(throw ex)))))
(def exception-middleware
(rrme/create-exception-middleware
(merge rrme/default-handlers
{:auth/unauthorized (fn [e req]
(if (ba/authenticated? req)
{:status 403
:body (.getMessage e)}
{:status 401
:body "Unauthenticated"}))})))
(def default-middleware
[rrmp/parameters-middleware
rrmm/format-middleware
exception-middleware
exception-logger
rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware])
(defn make-app [router]
(ring/ring-handler
router
(ring/routes
(ring/redirect-trailing-slash-handler)
(ring/create-default-handler))))
(defn parse-json [s]
(if (string? s)
(json/parse-string s csk/->kebab-case-keyword)
(with-open [r (io/reader s)]
(json/parse-stream r csk/->kebab-case-keyword))))
(defn run-build-async
"Starts the build in a new thread"
[rt]
(let [runner (rt/runner rt)
report-error (fn [ex]
(log/error "Unable to start build:" ex)
(rt/post-events rt (b/build-completed-evt
(-> (rt/build rt)
(assoc :status :error
:message (ex-message ex))))))]
(md/future
(try
;; Catch both the deferred error, or the direct exception, because both
;; can be thrown here.
(-> (runner rt)
(md/catch report-error))
(catch Exception ex
(report-error ex))))))