-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
ack.clj
52 lines (45 loc) · 1.72 KB
/
ack.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
(ns nrepl.ack
(:require
[nrepl.core :as nrepl]
[nrepl.transport :as t]))
;; could be a lot fancier, but it'll do for now
(def ^{:private true} ack-port-promise (atom nil))
(defn reset-ack-port!
[]
(reset! ack-port-promise (promise))
;; save people the misery of ever trying to deref the empty promise in their REPL
nil)
(defn wait-for-ack
"Waits for a presumably just-launched nREPL server to connect and
deliver its port number. Returns that number if it's delivered
within `timeout` ms, otherwise nil. Assumes that `ack`
middleware has been applied to the local nREPL server handler.
Expected usage:
(reset-ack-port!)
(start-server already-running-server-port)
=> (wait-for-ack)
59872 ; the port of the server started via start-server"
[timeout]
(let [f (future @@ack-port-promise)]
(deref f timeout nil)))
(defn handle-ack
[h]
(fn [{:keys [op port transport] :as msg}]
(if (not= op "ack")
(h msg)
(try
(deliver @ack-port-promise port)
(t/send transport {:status :done})
(catch Throwable _e)))))
;; TODO: could stand to have some better error handling around all of this
(defn send-ack
([my-port ack-port]
(send-ack my-port ack-port t/bencode))
([my-port ack-port transport-fn]
(with-open [^java.io.Closeable transport (nrepl/connect :transport-fn transport-fn
:port ack-port)]
(let [client (nrepl/client transport 1000)]
;; consume response from the server, solely to let that side
;; finish cleanly without (by default) spewing a SocketException when
;; the ack client goes away suddenly
(dorun (nrepl/message client {:op "ack" :port my-port}))))))