Skip to content

Commit

Permalink
Refactor runtime initialization system
Browse files Browse the repository at this point in the history
  • Loading branch information
jpmonettas committed Nov 28, 2024
1 parent e6d0c4f commit f9feb88
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 177 deletions.
3 changes: 2 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
:dev {:extra-paths ["src-dev" "classes"]

:extra-deps {
org.openjfx/javafx-swing {:mvn/version "21.0.4-ea+1"} ;; for scenic view to run
org.openjfx/javafx-swing {:mvn/version "21.0.4-ea+1"} ;; for scenic view to run
io.github.tonsky/clj-reload {:mvn/version "0.7.1"}
}
:jvm-opts ["-Dvisualvm.display.name=FlowStorm"
;; for the profilers
Expand Down
126 changes: 68 additions & 58 deletions src-dbg/flow_storm/debugger/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@
[]
(state-management/stop {}))

(defn debugger-config []
(let [theme-prop (System/getProperty "flowstorm.theme")
title-prop (System/getProperty "flowstorm.title")
styles-prop (System/getProperty "flowstorm.styles")]
(cond-> {}
theme-prop (assoc :theme (keyword theme-prop))
styles-prop (assoc :styles styles-prop)
title-prop (assoc :title title-prop))))

(defn start-debugger

"Run the debugger.
Expand All @@ -80,64 +89,65 @@
;; Initialize the JavaFX toolkit
(ui-utils/init-toolkit)

(if local?

;; start components for local debugging
(do
(state-management/start {:only local-debugger-state-vars
:config config})
(ui-main/setup-ui-from-runtime-config))

;; else, start components for remote debugging
(let [ws-connected? (promise)
repl-connected? (promise)
fully-started (atom false)
signal-ws-connected (fn [conn?]
(ui-main/set-conn-status-lbl :ws conn?)
(dbg-state/set-connection-status :ws conn?))
signal-repl-connected (fn [conn?]
(dbg-state/set-connection-status :repl conn?)
(ui-main/set-conn-status-lbl :repl conn?))]
(state-management/start {:only remote-debugger-state-vars
:config (assoc config
:on-ws-event events-queue/enqueue-event!
:on-ws-down (fn []
(utils/log "WebSocket connection went away")
(signal-ws-connected false)
(ui-main/clear-ui))
:on-ws-up (fn [_]
(signal-ws-connected true)
(deliver ws-connected? true)

;; This is kind of hacky but will handle the ClojureScript page reload situation.
;; After a page reload all the runtime part has been restarted, so
;; we can re-init it through the repl and also re-setup the ui with whatever the
;; runtime contains in terms of settings.
;; But we need to skip this the first time the ws connection comes up
;; since maybe the system ins't fully started yet, we maybe don't even have a UI
(when @fully-started
(when (dbg-state/repl-config)
(repl-core/init-repl (dbg-state/env-kind)))
(ui-main/setup-ui-from-runtime-config)))

:on-repl-down (fn []
(signal-repl-connected false))
:on-repl-up (fn []
(deliver repl-connected? true)
(signal-repl-connected true)))})

(reset! fully-started true)

;; if there is a repl config wait for the connection before moving on
(when (and (dbg-state/repl-config)
@repl-connected?)
(signal-repl-connected true))

;; once we have both the UI started and the runtime-connected
;; initialize the UI with the info retrieved from the runtime
(when @ws-connected?
(signal-ws-connected true)
(ui-main/setup-ui-from-runtime-config))))
(let [config (merge config (debugger-config))]
(if local?

;; start components for local debugging
(do
(state-management/start {:only local-debugger-state-vars
:config config})
(ui-main/setup-ui-from-runtime-config))

;; else, start components for remote debugging
(let [ws-connected? (promise)
repl-connected? (promise)
fully-started (atom false)
signal-ws-connected (fn [conn?]
(ui-main/set-conn-status-lbl :ws conn?)
(dbg-state/set-connection-status :ws conn?))
signal-repl-connected (fn [conn?]
(dbg-state/set-connection-status :repl conn?)
(ui-main/set-conn-status-lbl :repl conn?))]
(state-management/start {:only remote-debugger-state-vars
:config (assoc config
:on-ws-event events-queue/enqueue-event!
:on-ws-down (fn []
(utils/log "WebSocket connection went away")
(signal-ws-connected false)
(ui-main/clear-ui))
:on-ws-up (fn [_]
(signal-ws-connected true)
(deliver ws-connected? true)

;; This is kind of hacky but will handle the ClojureScript page reload situation.
;; After a page reload all the runtime part has been restarted, so
;; we can re-init it through the repl and also re-setup the ui with whatever the
;; runtime contains in terms of settings.
;; But we need to skip this the first time the ws connection comes up
;; since maybe the system ins't fully started yet, we maybe don't even have a UI
(when @fully-started
(when (dbg-state/repl-config)
(repl-core/init-repl (dbg-state/env-kind)))
(ui-main/setup-ui-from-runtime-config)))

:on-repl-down (fn []
(signal-repl-connected false))
:on-repl-up (fn []
(deliver repl-connected? true)
(signal-repl-connected true)))})

(reset! fully-started true)

;; if there is a repl config wait for the connection before moving on
(when (and (dbg-state/repl-config)
@repl-connected?)
(signal-repl-connected true))

;; once we have both the UI started and the runtime-connected
;; initialize the UI with the info retrieved from the runtime
(when @ws-connected?
(signal-ws-connected true)
(ui-main/setup-ui-from-runtime-config)))))

;; for both, local and remote

Expand Down
19 changes: 5 additions & 14 deletions src-dbg/flow_storm/debugger/ui/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@
:stop (fn [] (stop-ui)))

(defn clear-ui []
(outputs-screen/clear-outputs-ui)
(ui-utils/run-later
(outputs-screen/clear-outputs-ui)

(doseq [fid (dbg-state/all-flows-ids)]
(flows-screen/clear-debugger-flow fid)))
(doseq [fid (dbg-state/all-flows-ids)]
(flows-screen/clear-debugger-flow fid))))

(defn bottom-box []
(let [progress-box (ui/h-box :childs [])
Expand Down Expand Up @@ -374,18 +375,8 @@
(.setOnCloseRequest
(event-handler
[_]
;; call with skip-ui-stop? true since if we are here
;; we are already stopping the ui from closing the window
(binding [*killing-ui-from-window-close?* true]
(let [stop-config (when (utils/storm-env?)
{:skip-index-stop? true})]
(if-let [stop-all (resolve 'flow-storm.api/stop)]
;; if ui and runtime is running under the same jvm
;; we can stop all
(stop-all stop-config)

;; else stop just the debugger
((resolve 'flow-storm.debugger.main/stop-debugger))))))))
((resolve 'flow-storm.debugger.main/stop-debugger))))))

theme-listener (when (= :auto (:theme config))
(start-theme-listener
Expand Down
6 changes: 3 additions & 3 deletions src-dev/dev.clj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
(remove-watch dbg-state/state :spec-validator))

(defn start-local []
(fs-api/local-connect {:skip-index-start? (not (nil? index-api/flow-thread-registry))})
(fs-api/local-connect {})
(spec-instrument-state))

(defn start-shadow-remote [port build-id]
Expand All @@ -56,10 +56,10 @@
(spec-instrument-state))

(defn stop []
(fs-api/stop {:skip-index-stop? (utils/storm-env?)}))
(fs-api/stop))

(defn refresh []
(let [running? dbg-state/state]
(let [running? (boolean dbg-state/state)]
(log "Reloading system ...")
(when running?
(log "System is running, stopping it first ...")
Expand Down
70 changes: 38 additions & 32 deletions src-inst/flow_storm/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,63 @@
Provides functionality to start the debugger and instrument forms."

(:require [flow-storm.tracer :as tracer]
[flow-storm.runtime.outputs :as rt-outputs]
[flow-storm.utils :refer [log] :as utils]
[flow-storm.ns-reload-utils :as reload-utils]
[hansel.api :as hansel]
[hansel.instrument.utils :as inst-utils]
[flow-storm.runtime.debuggers-api :as dbg-api]
[flow-storm.runtime.events :as rt-events]
[flow-storm.runtime.values :as rt-values]
[flow-storm.jobs :as jobs]
[flow-storm.remote-websocket-client :as remote-websocket-client]
[flow-storm.runtime.indexes.api :as index-api]
[clojure.string :as str]
[clojure.stacktrace :as stacktrace]))

(defn stop
;; TODO: build script
;; Maybe we can figure out this ns names by scanning (all-ns) so
;; we don't need to list them here
;; Also maybe just finding main is enough, we can add to it a fn
;; that returns the rest of the functions we need
(def debugger-main-ns 'flow-storm.debugger.main)

"Stop the flow-storm runtime part gracefully.
If working in local mode will also stop the UI."
(defn start-debugger-ui

"Start the debugger UI when available on the classpath.
Returns true when available, false otherwise."

([] (stop {}))
([{:keys [skip-index-stop?]}]
(let [stop-debugger (try
(resolve (symbol (name dbg-api/debugger-main-ns) "stop-debugger"))
(catch Exception _ nil))]
[config]

;; NOTE: The order here is important until we replace this code with
;; better component state management
(if-let [start-debugger (requiring-resolve (symbol (name debugger-main-ns) "start-debugger"))]
(do
(start-debugger config)
true)
(do
(log "It looks like the debugger UI isn't present on the classpath.")
false)))

(when-not skip-index-stop?
(index-api/stop))
(defn stop-debugger-ui

;; if we are running in local mode and running a debugger stop it
(when stop-debugger
(stop-debugger))
"Stop the debugger UI if it has been started."

[]
(if-let [stop-debugger (requiring-resolve (symbol (name debugger-main-ns) "stop-debugger"))]
(stop-debugger)
(log "It looks like the debugger UI isn't present on the classpath.")))

(rt-events/clear-dispatch-fn!)
(rt-events/clear-pending-events!)

(rt-outputs/remove-tap!)
(defn stop

(dbg-api/interrupt-all-tasks)
"Stop the flow-storm runtime part gracefully.
If working in local mode will also stop the UI."

(rt-values/clear-vals-ref-registry)
[]

(jobs/stop-jobs)
(rt-events/clear-dispatch-fn!)

;; stop remote websocket client if needed
(remote-websocket-client/stop-remote-websocket-client)
;; if we are running in local mode and running a debugger stop it
(stop-debugger-ui)

(tracer/clear-breakpoints!)
(dbg-api/stop-runtime)

(log "System stopped"))))
(log "System fully stopped"))

(defn local-connect

Expand All @@ -79,11 +83,13 @@
([config]

(let [enqueue-event! (requiring-resolve 'flow-storm.debugger.events-queue/enqueue-event!)
config (assoc config
:local? true)]
config (assoc config :local? true)]

(dbg-api/start-runtime)

(dbg-api/start-runtime enqueue-event! false config))))
(start-debugger-ui config)

(rt-events/set-dispatch-fn enqueue-event!))))


(def jump-to-last-expression dbg-api/jump-to-last-expression-in-this-thread)
Expand Down
2 changes: 1 addition & 1 deletion src-inst/flow_storm/preload.cljs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns flow-storm.preload
(:require [flow-storm.runtime.debuggers-api :as dbg-api]))

(dbg-api/setup-runtime)
(dbg-api/start-runtime)
(dbg-api/remote-connect {})
2 changes: 1 addition & 1 deletion src-inst/flow_storm/remote_websocket_client.clj
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
(onClose [code reason remote?]
(log (format "Connection with %s closed. code=%s reson=%s remote?=%s"
uri-str code reason remote?))
((requiring-resolve 'flow-storm.api/stop)))
((requiring-resolve 'flow-storm.runtime.debuggers-api/stop-runtime)))

(onError [^Exception e]
(log-error (format "WebSocket error connection %s" uri-str) e)))]
Expand Down
Loading

0 comments on commit f9feb88

Please sign in to comment.