-
Notifications
You must be signed in to change notification settings - Fork 3
/
core.clj
144 lines (127 loc) · 3.65 KB
/
core.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
(ns json-rpc.core
(:refer-clojure :exclude [send])
(:require
[clojure.tools.logging :as log]
[json-rpc.http :as http]
[json-rpc.json :as json]
[json-rpc.unix :as unix]
[json-rpc.url :as url]
[json-rpc.ws :as ws]))
(def ^:const version
"JSON-RPC protocol version."
"2.0")
(defn uuid
[]
(.toString (java.util.UUID/randomUUID)))
(defn encode
"Encodes JSON-RPC method and params as a valid JSON-RPC request."
([method params id]
(json/write-str json/data-json {:jsonrpc version
:method method
:params params
:id id}))
([method params]
(encode method params (uuid))))
(defn decode
"Decodes result or error from JSON-RPC response."
[json]
(let [body (json/read-str json/data-json json)]
(select-keys body [:result :error :id])))
(defmulti connect
"Creates a JSON-RPC connection object."
url/scheme)
(defmethod connect
:http
[url]
{:scheme :http
:url url})
(defmethod connect
:https
[url]
{:scheme :http
:url url})
(defmethod connect
:ws
[url]
{:scheme :ws
:url url})
(defmethod connect
:wss
[url]
{:scheme :ws
:url url})
(defmethod connect
:unix
[url]
{:scheme :unix
:path (url/path url)})
(defmethod connect
:default
[url]
(throw (ex-info (format "Unsupported scheme: %s. Are you passing a valid URL?"
(url/scheme url))
{:url url})))
(defmulti send!
"Sends a JSON-RPC request to the server.
Connection can be over HTTP[S], WS[S] or UNIX sockets."
(fn [connection & _]
(:scheme connection)))
(defmethod send!
:http
;; Sends a JSON-RPC request to the server over HTTP[S].
http-send!
([{url :url} client method params]
(future
(let [request (encode method params)
response (->> request
(http/post! client url))]
(log/debugf "request => %s, response => %s" request response)
(decode response))))
([connection method params]
(send! connection http/clj-http method params)))
(defmethod send!
:ws
ws-send!
;; Sends a JSON-RPC request to the server over WS [S] .
([connection client method params]
(future
(let [id (uuid)
request (encode method params id)
response (->> request
(ws/write! client connection)
(decode))]
(if (not= id (:id response))
response
(throw (ex-info "Response ID did not match request ID!"
{:request request
:response response}))))))
([connection method params]
(send! connection ws/gniazdo method params)))
(defmethod send!
:unix
unix-send!
;; Sends a JSON-RPC request to the server over a UNIX socket.
([connection client method params]
(future
(let [id (uuid)
request (encode method params id)
response (->> request
(unix/write! client connection)
(decode))]
(if (not= id (:id response))
response
(throw (ex-info "Response ID did not match request ID!"
{:request request
:response response}))))))
([connection method params]
(send! connection unix/unix-client method params)))
(defmethod send!
:default
[& args]
(let [[connection & _] args]
(log/warnf "send! called with: %s. No such scheme: %s."
args (:scheme connection))))
(defn send!*
"Like [[send!]] but accepts a variable number of arguments."
[connection method & params]
(send! connection method params))