Skip to content

Commit 6e2c817

Browse files
author
dnolen
committed
CLJS-1137: :cljs/quit fails to actually quit in browser REPL
Massive hack to avoid changing REPL logic while supporting :cljs/quit in browser REPL. Move all browser REPL and browser REPL state (agents, atoms) into dynamic vars. Do not use futures, instead use explicit Threads with binding conveyance. Do not use global agent thread pools, use custom executor service which we can shut down separately.
1 parent 9e680c4 commit 6e2c817

File tree

2 files changed

+51
-32
lines changed

2 files changed

+51
-32
lines changed

src/clj/cljs/repl/browser.clj

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
[cljs.closure :as cljsc]
1818
[cljs.repl :as repl]
1919
[cljs.repl.server :as server])
20-
(:import [java.util.regex Pattern]))
20+
(:import [java.util.regex Pattern]
21+
[java.util.concurrent Executors]))
2122

22-
(defonce browser-state
23-
(atom {:return-value-fn nil
24-
:client-js nil}))
23+
(def ^:dynamic browser-state nil)
24+
(def ^:dynamic ordering nil)
25+
(def ^:dynamic es nil)
2526

2627
(defn- set-return-value-fn
2728
"Save the return value function which will be called when the next
@@ -116,10 +117,8 @@
116117

117118
(server/dispatch-on :post (constantly true) handle-post)
118119

119-
(def ordering (agent {:expecting nil :fns {}}))
120-
121120
(defmethod handle-post :ready [_ conn _]
122-
(send ordering (fn [_] {:expecting nil :fns {}}))
121+
(send-via es ordering (fn [_] {:expecting nil :fns {}}))
123122
(send-for-eval conn
124123
(cljsc/-compile
125124
'[(set! *print-fn* clojure.browser.repl/repl-print)
@@ -142,8 +141,8 @@
142141
"Elements to be printed in the REPL will arrive out of order. Ensure
143142
that they are printed in the correct order."
144143
[order f]
145-
(send-off ordering add-in-order order f)
146-
(send-off ordering run-in-order))
144+
(send-via es ordering add-in-order order f)
145+
(send-via es ordering run-in-order))
147146

148147
(defmethod handle-post :print [{:keys [content order]} conn _ ]
149148
(constrain-order order
@@ -483,15 +482,19 @@ goog.events.getProxy/f<@http://localhost:9000/out/goog/events/events.js:276:16"
483482
file))
484483

485484
(defn setup [{:keys [working-dir] :as repl-env} opts]
486-
(println "Compiling client js ...")
487-
(swap! browser-state
488-
(fn [old]
489-
(assoc old :client-js
490-
(create-client-js-file
491-
repl-env (io/file working-dir "client.js")))))
492-
(println "Waiting for browser to connect ...")
493-
opts
494-
(server/start repl-env))
485+
(binding [browser-state (:browser-state repl-env)
486+
ordering (:ordering repl-env)
487+
es (:es repl-env)
488+
server/state (:server-state repl-env)]
489+
(repl/err-out ((:print opts) "Compiling client js ..."))
490+
(swap! browser-state
491+
(fn [old]
492+
(assoc old :client-js
493+
(create-client-js-file
494+
repl-env (io/file working-dir "client.js")))))
495+
(repl/err-out ((:print opts) "Waiting for browser to connect ..."))
496+
opts
497+
(server/start repl-env)))
495498

496499
(defrecord BrowserEnv []
497500
repl/IJavaScriptEnv
@@ -513,13 +516,18 @@ goog.events.getProxy/f<@http://localhost:9000/out/goog/events/events.js:276:16"
513516
{:ua-product (clojure.browser.repl/get-ua-product)
514517
:value (str ~e)
515518
:stacktrace (.-stack ~e)})))))
516-
(-evaluate [_ _ _ js] (browser-eval js))
519+
(-evaluate [this _ _ js]
520+
(binding [browser-state (:browser-state this)
521+
ordering (:ordering this)
522+
es (:es this)
523+
server/state (:server-state this)]
524+
(browser-eval js)))
517525
(-load [this provides url]
518526
(load-javascript this provides url))
519-
(-tear-down [_]
520-
(server/stop)
521-
(reset! server/state {})
522-
(reset! browser-state {})))
527+
(-tear-down [this]
528+
(binding [server/state (:server-state this)]
529+
(server/stop))
530+
(.shutdown (:es this))))
523531

524532
(defn repl-env*
525533
[{:keys [output-dir] :as opts}]
@@ -531,7 +539,16 @@ goog.events.getProxy/f<@http://localhost:9000/out/goog/events/events.js:276:16"
531539
:static-dir (cond-> ["." "out/"] output-dir (conj output-dir))
532540
:preloaded-libs []
533541
:optimizations :simple
534-
:src "src/"}
542+
:src "src/"
543+
:browser-state (atom {:return-value-fn nil
544+
:client-js nil})
545+
:ordering (agent {:expecting nil :fns {}})
546+
:es (Executors/newFixedThreadPool 16)
547+
:server-state
548+
(atom
549+
{:socket nil
550+
:connection nil
551+
:promised-conn nil})}
535552
opts))
536553

537554
(defn repl-env

src/clj/cljs/repl/server.clj

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@
55
java.io.InputStreamReader
66
java.net.ServerSocket))
77

8-
(defonce state
9-
(atom
10-
{:socket nil
11-
:connection nil
12-
:promised-conn nil}))
8+
(def ^:dynamic state nil)
139

1410
(defn connection
1511
"Promise to return a connection when one is available. If a
@@ -160,16 +156,22 @@
160156

161157
(defn- server-loop
162158
[opts server-socket]
163-
(let [conn (.accept server-socket)]
159+
(when-let [conn (try (.accept server-socket) (catch Throwable _))]
164160
(.setKeepAlive conn true)
165-
(future (handle-connection opts conn))
161+
(.start
162+
(Thread.
163+
((ns-resolve 'clojure.core 'binding-conveyor-fn)
164+
(fn [] (handle-connection opts conn)))))
166165
(recur opts server-socket)))
167166

168167
(defn start
169168
"Start the server on the specified port."
170169
[opts]
171170
(let [ss (ServerSocket. (:port opts))]
172-
(future (server-loop opts ss))
171+
(.start
172+
(Thread.
173+
((ns-resolve 'clojure.core 'binding-conveyor-fn)
174+
(fn [] (server-loop opts ss)))))
173175
(swap! state (fn [old] (assoc old :socket ss :port (:port opts))))))
174176

175177
(defn stop []

0 commit comments

Comments
 (0)