/
middleware.clj
105 lines (90 loc) · 3.77 KB
/
middleware.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
(ns discljord.events.middleware
"Contains functions for constructing middleware, and some default middleware.
Middleware for discljord event handlers allow the modification and filtration
of events to be sent along to event handlers. Following is an example of an
identity middleware, and can be used as an example of what middleware in
discljord look like.
```clojure
(defn identity-middleware
\"Middleware that passes through events unchanged.\"
[handler]
(fn [event-type event-data & more]
(apply handler event-type event-data more)))
```"
(:require
[clojure.tools.logging :as log])
(:refer-clojure :rename {concat concat-seq
filter filter-seq
map map-seq
transduce transduce-seq}))
(defn concat
"Takes a handler function and creates a middleware which concats the handlers.
The events in the handler function passed are always run before the ones that
are given to the middleware when it is applied."
[handler]
(fn [hnd]
(fn [event-type event-data & more]
(apply handler event-type event-data more)
(apply hnd event-type event-data more))))
(defn log-when
"Takes a predicate and if it returns true, logs the event before passing it on.
The predicate must take the event-type and the event-data, and return a truthy
value if it should log. If the value is a valid level at which to log, that
logging level will be used."
[filter]
(fn [handler]
(fn [event-type event-data & more]
(when-let [logging-level (filter event-type event-data)]
(if (#{:trace :debug :info :warn :error :fatal} logging-level)
(log/log logging-level (pr-str event-type event-data))
(log/debug event-type event-data)))
(apply handler event-type event-data more))))
(defn filter
"Makes middleware that only calls the handler if `pred` returns truthy.
`pred` is a predicate expected to take the event-type and event-data."
[pred]
(fn [handler]
(fn [event-type event-data & more]
(when (pred event-type event-data)
(apply handler event-type event-data more)))))
(defn data-mapping
"Makes a transform function for use with [[map]] that operates on event-data.
The resulting function is from a vector of event-type and event-data to a
vector of event-type and event-data. The event-type is passed through without
change, and event-data is transformed by `f`."
[f]
(fn [[event-type event-data]]
[event-type (f event-data)]))
(defn map
"Makes a middleware which runs `f` over events before passing to the handler.
`f` is a function of a vector of event-type and event-data to a vector of
event-type and event-data which are then passed to the handler."
[f]
(fn [handler]
(fn [event-type event-data & more]
(let [[event-type event-data] (f [event-type event-data])]
(apply handler event-type event-data more)))))
(defn transduce
"Makes a middleware which takes a transducer and runs it over event-data."
[xf]
(let [reduced (volatile! false)
reducer (fn [send-event args]
(apply send-event args))
reducer (xf reducer)]
(fn [handler]
(fn [event-type event-data & more]
(when-not @reduced
(let [res (reducer handler (vec (concat-seq [event-type event-data] more)))]
(when (reduced? res)
(vreset! reduced true))
res))))))
;; =============================================================================
;; Default middleware
(def ignore-bot-messages
"Middleware which won't call the handler if the event is a message from a bot."
(filter
(fn [event-type event-data]
(if (#{:message-create :message-update} event-type)
(when-not (:bot (:author event-data))
true)
true))))