web3 promise not resolving in clojurescript - clojurescript

I have the following cljs code where I want to deploy a contract:
(go (let [web3
(Web3. (.-givenProvider Web3))
ego
(-> (<p! (.. web3 -eth (getAccounts)))
(nth 0))
contract
(new (.. web3 -eth -Contract)
(.-abi (js/JSON.parse contract-json))
nil
(clj->js {:transactionConfirmationBlocks 3}))
contract-deploy
(.. contract
(deploy (clj->js
{:arguments [ipfs]
:data (.-bytecode (js/JSON.parse contract-json))})))]
;;(prn "ego is " ego)
(let [contract-send
(.. contract-deploy
(send (clj->js {:from ego})
(fn [err tx-hash]
(prn "err is " err
"tx hash is " tx-hash))))
contract-instance
(try
(<p!
(.. contract-send
(on "error" (fn [obj] (js/console.log "error " obj)))
(on "sending" (fn [obj] (prn "sending " obj)))
(on "receipt" (fn [receipt]
(prn "contract address is")
(.-contractAddress receipt)))
(on "confirmation" (fn [confirmation-number receipt]
(dispatch [:stop-loading])
(prn "confirmation number"
confirmation-number)
(prn "receipt"
receipt)))))
(catch js/Object e
(.log js/console "contract error " e)))]
(dispatch [:issue-nfts contract-instance
contract-json ego]))))
and for some reason, contract-instance isn't resolving, which means that the dispatch after it isn't being called. I don't know why it isn't resolving. It was working before and has suddenly stopped working. How to fix this? The contract is confirmed on metamask but the promise isn't resolving in web3. I'm using web3 version 1.5.2

Related

How to return a promise from a go block?

The question is how to send to a nodejs app the result of a go block
i found a solution with callback
but i need a solution with promise
Promise solution?
Clojurescript app
(defn foo []
(go 1))
;;how to change foo,wrap to promise?, so node app can await to get the 1
;;i used 1 for simplicity in my code i have something like
;;(go (let [x (<! ...)] x))
Node app
async function nodefoo() {
var x = await foo();
console.log(x); // i want to see 1
}
Callback solution (the one that works now)
So far i only found a way to pass a cb function, so this 1 goes back to node.js app
Clojurescript app
(defn foo1 [cb]
(take! (go 1)
(fn [r] (cb r))))
Node app
var cb=function () {....};
foo1(cb); //this way node defined cb function will be called with argument 1
But i dont want to pass a callback function, i want node.js to wait and get the value.
I want to return a promise.
This function takes a channel and returns a Javascript Promise that resolves with the first value the channel emits:
(defn wrap-as-promise
[chanl]
(new js/Promise (fn [resolve _]
(go (resolve (<! chanl))))))
Then to show usage:
(def chanl (chan 1))
(def p (wrap-as-promise chanl))
(go
(>! chanl "hello")
(.then p (fn [val] (println val))))
If you compile that and run it in your browser (assuming you called enable-console-print!) you'll see "hello".
It is also possible to extend the ManyToManyChannel type with extend-type.
Here's a naif implementation using a similar wrap-as-promise function
(require '[clojure.core.async.impl.channels :refer [ManyToManyChannel]])
(defn is-error? [val] (instance? js/Error val))
(defn wrap-as-promise
[channel callback]
(new js/Promise
(fn [resolve reject]
(go
(let [v (<! channel)]
(if (is-error? v)
(reject v)
(resolve (callback v))))))))
(extend-type ManyToManyChannel
Object
(then
[this f]
(wrap-as-promise this f)))
(def test-chan (chan 1))
(put! test-chan (new js/Error "ihihi"))
(put! test-chan :A)
(defn put-and-close! [port val]
(put! port val)
(async/close! port))
(-> test-chan
(.then (fn [value] (js/console.log "value:" value)))
(.catch (fn [e] (js/console.log "error" e)))
(.finally #(js/console.log "finally clause.")))

form-3 component not rerendering anything even though :component-did-update is called

I have the following code to test out form-3 components:
(defn inner [data]
(reagent/create-class
{:display-name "Counter"
:component-did-mount (fn []
(js/console.log "Initialized")
[:h1 "Initialized! " data])
:component-did-update (fn [this _]
(let [[_ data] (reagent/argv this)]
(js/console.log (str "Updated " data))
[:div (str "My clicks " data)]))
:reagent-render (fn [] [:div (str "My clicks " data)])}))
I am able to successfully trigger both the :component-did-mount and the :component-did-update as there is the expected output in the console log. However, neither of the two functions actually change anything on the page. It just shows the initial state of [:div (str "My clicks " data)] the whole time.
What am I doing wrong? Ps. I have read the reagent docs and the purelyfunctional guide.
You have to repeat the parameters in the :reagent-render function:
(fn [data] [:div (str "My clicks " data)])

How to get query parameters in clojurescript?

I'm using secretary and reagent. This is my code :
(def view (atom nil))
(defn layout [view]
[:div #view])
(reagent/render-component [layout view] (.getElementById js/document "message"))
(secretary/set-config! :prefix "")
(secretary/defroute home-path "/" [query-params]
(timbre/info "Path : /, query params : " query-params)
(let [warning (:warning query-params)
success (:success query-params)
login-failed (:login_failed query-params)]
(when warning
(timbre/info "Warning found : " warning)
(reset! view [:h4 [:span.label.label-warning warning]]))
(when success
(timbre/info "Success found : " success)
(reset! view [:h4 [:span.label.label-info success]]))
(when login-failed
(timbre/info "Login failed")
(reset! view [:h4 [:span.label.label-warning "Login Failed."]]))))
(let [h (History.)]
(goog.events/listen h EventType.NAVIGATE #(secretary/dispatch! (.-token %)))
(doto h
(.setEnabled true)))
Disregarding the :prefix value (I tried "", "#" and also not setting the :prefix at all) this code only works with routes like :
http://localhost:8080/login#/?success=SuccessMessage
But it doesn't work with routes like :
http://localhost:8080/login?success=SuccessMessage
What I'm actually trying to achieve is to parse the login failure from friend, which in case of failure redirects me to
http://localhost:8080/login?&login_failed=Y&username=someUser
and display login failed message to the user. I don't need to use secretary for this, anything that works to parse the query-parameters would be ok for me.
The hard way would be to parse the query string which I can get with:
(-> js/window .-location .-search)
I believe that this is already done well in some library.
I found it. Using https://github.com/cemerick/url (works for both clojure and clojurescript), one can do :
(require '[cemerick.url :as url])
(:query (url/url (-> js/window .-location .-href)))
From the docs:
If a URI contains a query string it will automatically be extracted to :query-params for string route matchers and to the last element for regular expression matchers.
(defroute "/users/:id" [id query-params]
(js/console.log (str "User: " id))
(js/console.log (pr-str query-params)))
(defroute #"/users/(\d+)" [id {:keys [query-params]}]
(js/console.log (str "User: " id))
(js/console.log (pr-str query-params)))
;; In both instances...
(secretary/dispatch! "/users/10?action=delete")
;; ... will log
;; User: 10
;; "{:action \"delete\"}"

No state info with Chrome React.js tools

I have the following ClojureScript code that uses the om library as a wrapper to React.js
(defn list-view [app owner]
(reify
om/IInitState
(init-state [_]
{:filter nil
:selected-domain nil})
om/IWillMount
(will-mount [_]
(th/poll filter-chan (fn[data]
(om/set-state! owner :filter data))))
om/IRenderState
(render-state [this state]
(let [list-data (sort (list-data (:list app) (:filter state)))]
(if (> (count list-data) 0)
(dom/div #js {:className "sidebar-module sidebar-module-inset"}
(dom/div #js {:className "bs-example well"}
(apply dom/ul #js {:className "list-group"}
(map (fn [text] (domain-list-item text (:selected-domain state) owner))
list-data))))
(dom/span nil))))))
This are the helper functions used in the code above
(defn list-data [alist filter-text ]
(filter (fn [x] (cond (empty? filter-text) false
(nil? filter-text) false
(= filter-text "*") true
:else (> (.indexOf (.toLowerCase x) filter-text) -1))) alist))
(defn domain-list-item [text selected owner]
(let [class-name (str "list-group-item" (if (= text selected) " isSelected" ""))]
(dom/li #js {:className class-name}
(dom/a #js
{:href "#"
:onClick (fn [event] (select-domain owner text))} text))))
Everything works as expected. The only thing that bothers me Is that I do not see any state info when I analyze the page with the React.js tools in Chrome.
It seems as if sometimes the state is directly visible in the state area (e.g. for an input element) and sometimes it is hidden inside the __om_state object.
I find that I often have to click on another component and then back on the component I'm interested in to see the state in the state area. Perhaps that's the issue here?

What is the advantage of core.async in clojurescript?

Everybody is talking about how great core.async is, and how it will improve event handling in clojurescript. I've been following the ClojureScript 101 tutorial, and I don't see any clear advantage from these code examples. What am I missing?
Why is the use of core.async any better here?
(defn listen [el type]
(let [out (chan)]
(events/listen el type
(fn [e] (put! out e)))
out))
(defn dosomethingasync
[e]
(js/console.log "async: " e))
(let [clicks (listen (dom/getElement "search1") "click")]
(go (while true (dosomethingasync (<! clicks)))))
vs.
(defn dosomethingcallback
[e]
(js/console.log "callback: " e))
(events/listen (dom/getElement "search2") "click" dosomethingcallback)
Great question!
I think your first step to understand the advantage would be Timothy Baldridge Video
And below my try:
I think that the differences will clear up if we change a bit your code.
Firstly, trying to highlight the sentence "There comes a time in all good programs when components or subsystems must stop communicating directly with one another" extracted from the presentation of core.async posted on the clojure blog. I think that we can separate the input events channel from the let fn:
(def clicks (listen (dom/getElement "search1") "click"))
(go
(while true
(dosomethingasync (<! clicks))))
(put! clicks "this channel can be written from differents parts of your code")
Secondly, with core.async we can write asynchronous calls as we'll write synchronous calls (sequential code). An example of this situation require more than one channel:
(def clicks (listen (dom/getElement "search1") "click"))
(def keys-pressed (listen (dom/getElement "search1") "keypress"))
(def to-out (chan))
(go
(while true
(let [click-recieved (<! clicks)]
(dosomethingasync click-recieved)
(>! to-out "click recieved!")
(let [other-input-waited (<! keys-pressed)]
(dosomethingwithkey other-input-waited)
(>! to-out "keypressed recieved!")
)
)
))
And lastly, i think that you are not properly using the meaning of callback function. When we talk of a callback function i think we are referring to a function that besides its own parameters it receives a function "callback". At the end of the execution of the function we call the callback function to return the execution flow to the original point.
Changing your "callback" function come up as follow:
(defn dosomethingcallback
[e call-back-fn]
(js/console.log "callback: " e)
(call-back-fn))
And if we try to issue something similar to the same behaviour achieved with previous code core.async example:
(defn do-key
[call-back-fn e]
(.log js/console "before callback key" )
(call-back-fn e))
(defn do-click
[call-back-fn e]
(.log js/console "before callback click")
(call-back-fn e))
(defn key-callback-fn [e]
(.log js/console (str "doing some work with this key: " e))
)
(defn click-callback-fn [e]
(.log js/console (str "doing some work with this click" e))
(events/listen (dom/getElement "search2") "keypress" (partial do-key key-callback-fn)))
(events/listen (dom/getElement "search2") "click" (partial do-click click-callback-fn))