From f8904146de3883dacd0b6809d41cb78245cd4f9d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 20 Jun 2014 19:34:30 -0400 Subject: [PATCH 1/4] First work on weasel.repl.qml. --- project.clj | 5 ++- src/cljs/weasel/repl/qml.cljs | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/cljs/weasel/repl/qml.cljs diff --git a/project.clj b/project.clj index 985ded8..6252910 100644 --- a/project.clj +++ b/project.clj @@ -6,8 +6,9 @@ :distribution :repo} :dependencies [[org.clojure/clojure "1.5.1"] - [org.clojure/clojurescript "0.0-2202" :scope "provided"] - [org.clojure/google-closure-library "0.0-20140226-71326067" :scope "provided"] + [org.clojure/clojurescript "0.0-2234" :scope "provided"] + ;;[org.clojure/google-closure-library "0.0-20140226-71326067" :scope "provided"] + ;;[org.clojure/google-closure-library "0.0-20130212-95c19e7f0f5f"] [http-kit "2.1.18"]] :profiles {:dev {:dependencies [[com.cemerick/piggieback "0.1.3"]]}} diff --git a/src/cljs/weasel/repl/qml.cljs b/src/cljs/weasel/repl/qml.cljs new file mode 100644 index 0000000..5d13578 --- /dev/null +++ b/src/cljs/weasel/repl/qml.cljs @@ -0,0 +1,80 @@ +(ns weasel.repl.qml + (:require + [cljs.reader :as reader :refer [read-string]])) + +(def ^:private ws-connection (atom nil)) + +(defn alive? [] + "Returns truthy value if the REPL is attempting to connect or is + connected, or falsy value otherwise." + (not (nil? @ws-connection))) + +(defmulti process-message :op) + +(defmethod process-message + :error + [message] + (.error js/console (str "Websocket REPL error " (:type message)))) + +(defmethod process-message + :eval-js + [message] + (let [code (:code message)] + {:op :result + :value (try + {:status :success, :value (str (js* "eval(~{code})"))} + (catch js/Error e + {:status :exception + :value (pr-str e) + :stacktrace (if (.hasOwnProperty e "stack") + (.-stack e) + "No stacktrace available.")}) + (catch :default e + {:status :exception + :value (pr-str e) + :stacktrace "No stacktrace available."}))})) + +(defn repl-print + [x] + (if-let [conn @ws-connection] + (.sendTextMessage @ws-connection (pr-str {:op :print :value (pr-str x)})))) + +(def ws-status + {0 :Connecting + 1 :Open + 2 :Closing + 3 :Closed + 4 :Error}) + +(defn create-ws [parent] + (let [ws + (.createQmlObject + js/Qt + "import Qt.WebSockets 1.0; WebSocket {url: \"ws://localhost:9001\"}" + ;;"import Qt.WebSockets 1.0; WebSocket {}" + parent + "weasel.repl.qml.websocket")] + (.log js/console (ws-status (.-status ws))) + (.log js/console (ws-status (.-active ws))) + (.log js/console (.-url ws)) + (.connect (.-onStatusChanged ws) + (fn [status] + (let [status (ws-status status)] + (.log js/console (str "Status: " status)) + (cond + (= status :Open) + (.sendTextMessage ws (pr-str {:op :ready})) + + (= status :Closed) + (set! (.-active ws) true) + + (= status :Error) + (.error js/console "WebSocket error" (.-errorString ws)))))) + (.connect (.-onTextMessageReceived ws) + (fn [msg] + (.log js/console (str "Received: " msg)) + (let [{:keys [op] :as message} (read-string msg) + response (-> message process-message pr-str)] + (.sendTextMessage ws response)))) + (set! (.-active ws) true) + ws)) From a748e9888394b13d7245792f629ce1596e5bcae3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 3 Jul 2014 20:07:18 -0400 Subject: [PATCH 2/4] Updated Clojure and Clojurescript. --- project.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project.clj b/project.clj index 6252910..3111a20 100644 --- a/project.clj +++ b/project.clj @@ -5,8 +5,8 @@ :url "http://unlicense.org/UNLICENSE" :distribution :repo} - :dependencies [[org.clojure/clojure "1.5.1"] - [org.clojure/clojurescript "0.0-2234" :scope "provided"] + :dependencies [[org.clojure/clojure "1.6.0"] + [org.clojure/clojurescript "0.0-2261" :scope "provided"] ;;[org.clojure/google-closure-library "0.0-20140226-71326067" :scope "provided"] ;;[org.clojure/google-closure-library "0.0-20130212-95c19e7f0f5f"] [http-kit "2.1.18"]] From 27fd4bba2d91ffa208f9d5a8533cc166ee3c0d89 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 3 Jul 2014 20:54:02 -0400 Subject: [PATCH 3/4] Made a proper connect function (that mirrors Weasel) with the addition of a required qml-parent argument (the Websocket needs a partent object). --- src/cljs/weasel/repl/qml.cljs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/cljs/weasel/repl/qml.cljs b/src/cljs/weasel/repl/qml.cljs index 5d13578..62341a8 100644 --- a/src/cljs/weasel/repl/qml.cljs +++ b/src/cljs/weasel/repl/qml.cljs @@ -46,35 +46,42 @@ 3 :Closed 4 :Error}) -(defn create-ws [parent] +(defn ^:export connect [qml-parent repl-server-url & {:keys [verbose on-open on-error on-close]}] (let [ws (.createQmlObject js/Qt - "import Qt.WebSockets 1.0; WebSocket {url: \"ws://localhost:9001\"}" + (str "import Qt.WebSockets 1.0; WebSocket {url: \"" repl-server-url "\"}") ;;"import Qt.WebSockets 1.0; WebSocket {}" - parent + qml-parent "weasel.repl.qml.websocket")] - (.log js/console (ws-status (.-status ws))) - (.log js/console (ws-status (.-active ws))) - (.log js/console (.-url ws)) + (reset! ws-connection ws) (.connect (.-onStatusChanged ws) (fn [status] (let [status (ws-status status)] - (.log js/console (str "Status: " status)) (cond (= status :Open) - (.sendTextMessage ws (pr-str {:op :ready})) + (do + (.sendTextMessage ws (pr-str {:op :ready})) + (when verbose (.info js/console "Opened Websocket REPL connection")) + (when (fn? on-open) on-open ) + ) (= status :Closed) - (set! (.-active ws) true) + (do + (reset! ws-connection nil) + (when verbose (.info js/console "Closed Websocket REPL connection")) + (when (fn? on-close) (on-close))) (= status :Error) - (.error js/console "WebSocket error" (.-errorString ws)))))) + (do + (.error js/console "WebSocket error" (.-errorString ws)) + (when (fn? on-error) (on-error (.-errorString ws)))))))) (.connect (.-onTextMessageReceived ws) (fn [msg] - (.log js/console (str "Received: " msg)) + (when verbose (.log js/console (str "Received: " msg))) (let [{:keys [op] :as message} (read-string msg) response (-> message process-message pr-str)] + (when verbose (.log js/console (str "Sending: " response))) (.sendTextMessage ws response)))) (set! (.-active ws) true) ws)) From 6d5b7584a578f53419a8318b9cf0235770fd8a00 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 3 Jul 2014 21:52:06 -0400 Subject: [PATCH 4/4] Got repl-print working. --- src/clj/weasel/repl/websocket.clj | 2 +- src/cljs/weasel/impls/print.cljs | 3 +++ src/cljs/weasel/repl.cljs | 4 +++- src/cljs/weasel/repl/qml.cljs | 32 +++++++++++++++++-------------- 4 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 src/cljs/weasel/impls/print.cljs diff --git a/src/clj/weasel/repl/websocket.clj b/src/clj/weasel/repl/websocket.clj index 3d2c53c..8f9f574 100644 --- a/src/clj/weasel/repl/websocket.clj +++ b/src/clj/weasel/repl/websocket.clj @@ -81,7 +81,7 @@ (binding [*out* (or @repl-out *out*)] (send-for-eval! (cljsc/compile-form-seq '[(ns cljs.user) - (set-print-fn! weasel.repl/repl-print)]))))) + (set-print-fn! @weasel.impls.print/print-fn)]))))) (defn- websocket-setup-env [this] diff --git a/src/cljs/weasel/impls/print.cljs b/src/cljs/weasel/impls/print.cljs new file mode 100644 index 0000000..261defc --- /dev/null +++ b/src/cljs/weasel/impls/print.cljs @@ -0,0 +1,3 @@ +(ns weasel.impls.print) + +(def print-fn (atom (constantly nil))) diff --git a/src/cljs/weasel/repl.cljs b/src/cljs/weasel/repl.cljs index a7fc01c..c79e571 100644 --- a/src/cljs/weasel/repl.cljs +++ b/src/cljs/weasel/repl.cljs @@ -2,7 +2,8 @@ (:require [clojure.browser.event :as event :refer [event-types]] [clojure.browser.net :as net] [cljs.reader :as reader :refer [read-string]] - [weasel.impls.websocket :as ws])) + [weasel.impls.websocket :as ws] + [weasel.impls.print :as wp])) (def ^:private ws-connection (atom nil)) @@ -45,6 +46,7 @@ [repl-server-url & {:keys [verbose on-open on-error on-close]}] (let [repl-connection (ws/websocket-connection)] (swap! ws-connection (constantly repl-connection)) + (swap! wp/print-fn (constantly repl-print)) (event/listen repl-connection :opened (fn [evt] diff --git a/src/cljs/weasel/repl/qml.cljs b/src/cljs/weasel/repl/qml.cljs index 62341a8..25ff028 100644 --- a/src/cljs/weasel/repl/qml.cljs +++ b/src/cljs/weasel/repl/qml.cljs @@ -1,6 +1,7 @@ (ns weasel.repl.qml (:require - [cljs.reader :as reader :refer [read-string]])) + [cljs.reader :as reader :refer [read-string]] + [weasel.impls.print :as wp])) (def ^:private ws-connection (atom nil)) @@ -46,25 +47,28 @@ 3 :Closed 4 :Error}) -(defn ^:export connect [qml-parent repl-server-url & {:keys [verbose on-open on-error on-close]}] - (let [ws +(defn connect [qml-parent repl-server-url & {:keys [verbose on-open on-error on-close]}] + "Connects to a Weasel REPL socket at the provided repl-server-url. The underlying implementation +depends on Qt.WebSockets (found in Qt 5.3 or higher). Because this is a Qml object it requires +a non-nil parent object passed in as qml-parent." + (let [repl-connection (.createQmlObject js/Qt (str "import Qt.WebSockets 1.0; WebSocket {url: \"" repl-server-url "\"}") ;;"import Qt.WebSockets 1.0; WebSocket {}" qml-parent "weasel.repl.qml.websocket")] - (reset! ws-connection ws) - (.connect (.-onStatusChanged ws) + (swap! ws-connection (constantly repl-connection)) + (swap! wp/print-fn (constantly repl-print)) + (.connect (.-onStatusChanged repl-connection) (fn [status] (let [status (ws-status status)] (cond (= status :Open) (do - (.sendTextMessage ws (pr-str {:op :ready})) + (.sendTextMessage repl-connection (pr-str {:op :ready})) (when verbose (.info js/console "Opened Websocket REPL connection")) - (when (fn? on-open) on-open ) - ) + (when (fn? on-open) (on-open))) (= status :Closed) (do @@ -74,14 +78,14 @@ (= status :Error) (do - (.error js/console "WebSocket error" (.-errorString ws)) - (when (fn? on-error) (on-error (.-errorString ws)))))))) - (.connect (.-onTextMessageReceived ws) + (.error js/console "WebSocket error" (.-errorString repl-connection)) + (when (fn? on-error) (on-error (.-errorString repl-connection)))))))) + (.connect (.-onTextMessageReceived repl-connection) (fn [msg] (when verbose (.log js/console (str "Received: " msg))) (let [{:keys [op] :as message} (read-string msg) response (-> message process-message pr-str)] (when verbose (.log js/console (str "Sending: " response))) - (.sendTextMessage ws response)))) - (set! (.-active ws) true) - ws)) + (.sendTextMessage repl-connection response)))) + (set! (.-active repl-connection) true) + repl-connection))