Skip to content

Commit 57bde4d

Browse files
committed
Use a multimethod for content-type dispatching
Make the content-type middleware that handles inlining of File/URL/Image extensible through a multimethod. This makes it possible for developers to add handling of custom types. Regular Clojure values can be given a `:type` metadata to make them distinguishable. Other types can dispatch on the class.
1 parent 6dc9654 commit 57bde4d

File tree

1 file changed

+43
-40
lines changed

1 file changed

+43
-40
lines changed

src/cider/nrepl/middleware/content_type.clj

+43-40
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
[2] https://github.com/technomancy/nrepl-discover/blob/master/src/nrepl/discover/samples.clj#L135
4242
[3] https://tools.ietf.org/html/rfc2045
4343
[4] https://tools.ietf.org/html/rfc2017"
44-
{:authors ["Reid 'arrdem' McKenzie <[email protected]>"]}
44+
{:authors ["Reid 'arrdem' McKenzie <[email protected]>"
45+
"Arne 'plexus' Brasseur <[email protected]>"]}
4546
(:require
4647
[cider.nrepl.middleware.slurp :refer [slurp-reply]])
4748
(:import
@@ -74,43 +75,45 @@
7475
(as-url [^URL u]
7576
u))
7677

77-
(defn response+content-type
78-
"Consumes an nREPL response, having a `:value`. If the `:value` is
79-
recognized as an AWT Image, a File, or a File URI, rewrite the
80-
response to have a `:content-type` being a MIME type of the content,
81-
and a `:body` to re-use the RFC term for the message payload."
82-
[{:keys [value] :as response}]
83-
(cond
84-
;; FIXME (arrdem 2018-04-03):
85-
;;
86-
;; This could be more generic in terms of tolerating more
87-
;; protocols / schemes
88-
89-
;; RFC-2017 external-body responses for UR[IL]s and things which are just wrappers thereof
90-
(or (and (instance? File value)
91-
(.exists ^File value))
92-
(instance? URI value)
93-
(instance? URL value))
94-
(assoc response
95-
:content-type ["message/external-body"
96-
{"access-type" "URL"
97-
"URL" (.toString ^URL (as-url value))}]
98-
:body "")
99-
100-
;; FIXME (arrdem 2018-04-03):
101-
;;
102-
;; This is super snowflakey in terms of only supporting base64
103-
;; coding this one kind of object. This could definitely be
104-
;; more generic / open to extension but hey at least it's
105-
;; re-using machinery.
106-
107-
(instance? java.awt.Image value)
108-
(with-open [bos (ByteArrayOutputStream.)]
109-
(merge response
110-
(when (ImageIO/write ^RenderedImage value "png" ^OutputStream bos)
111-
(slurp-reply "" ["image/png" {}] (.toByteArray bos)))))
112-
113-
:else response))
78+
(defn external-body-response
79+
"Partial response map having an external-body content-type referring to the given URL.
80+
81+
See RFC-2017: Definition of the URL MIME External-Body Access-Type."
82+
[value]
83+
{:content-type ["message/external-body"
84+
{"access-type" "URL"
85+
"URL" (.toString ^URL (as-url value))}]
86+
:body ""})
87+
88+
(defmulti content-type-response
89+
"Consumes an nREPL response, having a `:value`. If the `:value` is of a
90+
recognized type, then rewrite the response to have a `:content-type` being a
91+
MIME type of the content, and a `:body` to re-use the RFC term for the message
92+
payload.
93+
94+
Dispatches on the [[clojure.core/type]] of the value, i.e. the metadata
95+
`:type` value, or the class."
96+
(comp type :value))
97+
98+
(defmethod content-type-response :default [response]
99+
response)
100+
101+
(defmethod content-type-response URI [{:keys [value] :as response}]
102+
(merge response (external-body-response value)))
103+
104+
(defmethod content-type-response URL [{:keys [value] :as response}]
105+
(merge response (external-body-response value)))
106+
107+
(defmethod content-type-response File [{^File file :value :as response}]
108+
(if (.exists file)
109+
(merge response (external-body-response file))
110+
response))
111+
112+
(defmethod content-type-response java.awt.Image [{^java.awt.Image image :value :as response}]
113+
(with-open [bos (ByteArrayOutputStream.)]
114+
(ImageIO/write image "png" ^OutputStream bos)
115+
(merge response (when (ImageIO/write ^RenderedImage value "png" ^OutputStream bos)
116+
(slurp-reply "" ["image/png" {}] (.toByteArray bos))))))
114117

115118
(defn content-type-transport
116119
"Transport proxy which allows this middleware to intercept responses
@@ -123,8 +126,8 @@
123126
(recv [_this timeout]
124127
(.recv transport timeout))
125128

126-
(send [_this response]
127-
(.send transport (response+content-type response)))))
129+
(send [this response]
130+
(.send transport (content-type-response response)))))
128131

129132
(defn handle-content-type
130133
"Handler for inspecting the results of the `eval` op, attempting to

0 commit comments

Comments
 (0)