(ns burp-clj-montoya.nrepl (:require [burp-clj-montoya.state :as state] [cider.nrepl] [nrepl.server :as server] [taoensso.timbre :as log]) (:import [clojure.lang DynamicClassLoader RT])) (defmacro with-exception-default [value & body] `(try ~@body (catch Exception e# (do (log/error e#) ~value)))) (defmacro dyn-call [ns-sym] (let [ns (-> (namespace ns-sym) symbol) sym (-> (name ns-sym) symbol)] `(do (require '~ns) (ns-resolve '~ns '~sym)))) (def base-class-loader (DynamicClassLoader. (.getClassLoader clojure.lang.Compiler))) (defn ensure-dynamic-classloader "Ensure class can be dynamically loaded" [] (let [thread (Thread/currentThread) context-class-loader (.getContextClassLoader thread)] (when-not (instance? DynamicClassLoader context-class-loader) (prn "set new dynamic classloader for thread:" (.getName thread)) (.setContextClassLoader thread base-class-loader)))) (defn wrap-classloader [h] (fn [msg] (ensure-dynamic-classloader) (h msg))) (defn started? [] (-> (:nrepl-server @state/state) boolean)) (defn stop-nrepl [] (when-let [server (:nrepl-server @state/state)] ((dyn-call nrepl.server/stop-server) server) (swap! state/state dissoc :nrepl-server))) (defn start-nrepl [logging] (when-not (started?) (.logToOutput logging "Attempting to start nrepl") (let [cider-nrepl-handler (dyn-call cider.nrepl/cider-nrepl-handler) start-server (dyn-call nrepl.server/start-server) nrepl-server (start-server :bind "0.0.0.0" :port 6969 :handler (-> cider-nrepl-handler wrap-classloader))] (swap! state/state assoc :nrepl-server nrepl-server) (.logToOutput logging "nrepl started."))))