This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-12-22
Channels
- # adventofcode (1)
- # beginners (172)
- # boot (47)
- # cider (7)
- # cljs-dev (30)
- # cljsrn (43)
- # clojure (180)
- # clojure-dusseldorf (1)
- # clojure-greece (1)
- # clojure-italy (3)
- # clojure-russia (41)
- # clojure-spec (67)
- # clojure-uk (101)
- # clojurescript (128)
- # core-async (4)
- # cursive (13)
- # datomic (29)
- # devcards (5)
- # emacs (19)
- # events (1)
- # hoplon (38)
- # lein-figwheel (1)
- # luminus (8)
- # midje (1)
- # off-topic (47)
- # om (10)
- # onyx (23)
- # protorepl (1)
- # re-frame (11)
- # reagent (7)
- # ring (3)
- # ring-swagger (9)
- # rum (6)
- # sql (5)
- # untangled (4)
how about:
(defn wrap-castra [handler & [opts & more :as namespaces]]
(let [{:keys [body-keys state-fn on-error] :as opts} (when (map? opts) opts)
nses (if opts more namespaces)
head {"X-Castra-Tunnel" "transit"}
seq* #(or (try (seq %) (catch Throwable e)) [%])
vars (fn [] (->> nses (map seq*) (mapcat #(apply select-vars %)) set))]
(fn [req]
(if-not (castra-req? req)
(handler req)
(binding [*print-meta* true
*pre* true
*request* req
*session* (atom (:session req))
*validate-only* (= "true" (get-in req [:headers "x-castra-validate-only"]))]
(let [h (headers req head {"Content-Type" "application/json"})
fn&args (expression body-keys req)
f #(do (csrf!) (do-rpc (vars) fn&args))
d (try (response body-keys req {:result (f) :state (when state-fn (state-fn))})
(catch Throwable e
(when on-error (on-error fn&args e))
(response body-keys req {:error (ex->clj e)})))]
{:status 200, :headers h, :body d, :session @*session*}))))))
Is there a general article somewhere about the best kind of architecture to build a hoplon front-end with? For example, the react-based communities seem to favor sharding out pieces of some "central atom of truth" to the different components. You could do that with javelin as well, but most of the hoplon demos I've looked at seem to favor having each component rely on its own cells, and then some formula cell computes the overall state from the individual cells. I would appreciate seeing a discussion of the trade-offs, and what approaches scale the best.
I understand the current consensus is in building layers of view elements at different abstraction levels in the application, e.g. div
-> popup
-> settings-panel
, each with a set of parameter cells which capture all the needed interactions and render values. Also Micha showcased his form-machines a few times - an additional abstraction which captures the workflow (as opposed to view elements) - https://gist.github.com/micha/622a62d6a52ff419e5ac. I don't think there's the best solution for storing the overall state of the application, some people use Datascript, some multiple cells, some a single cell...
@puzzler a useful thing to recognize about cells is that in many ways, the cell graph is a single atom
in the sense that cells can update consistently
the difference is cells can be anonymous, which named places in a global atom-map cannot be
any news on castra middleware on-error
option?
i can make a pull request if you ok with it
@peterromfeld: that would probably be a good idea 👍
ok, @peterromfeld, hold off a bit first until micha can weigh in.
a pr would be much appreciated, but we might want to review castra's approach to error handling as a group first so we can maximize your contribution.
ill just do pr tomorrow, and if something is to your dislike you can reply in the pr
also if you guy have time this we or the week after
i need to help debug some flash (css get loaded second time) because we maybe dont include 3rd party js lib the way hoplon wants it
im about to sleep now, need to work in few hours lol 😉
thats why we or i have free whole week next week
@peterromfeld, @dm3, @flyboarder: i'm actually thinking that error handling should be factored out into an entirely separate castra middleware.
and this middleware, as the outer wrapper, can handle all the errors in a uniform way to both ensure they are all a) logged properly and b) returned to the client.
@alandipert: this also comes into play with panoply, where our call to github's oath api might return:
2016-12-22 12:51:55.005:WARN:oejs.ServletHandler:qtp1392923222-100: /
clojure.lang.ExceptionInfo: The code passed is incorrect or expired. {:error "bad_verification_code", :error_description "The code passed is incorrect or expired.", :error_uri ""}
at clojure.core$ex_info.invokeStatic(core.clj:4617)
at clojure.core$ex_info.invoke(core.clj:4617)
at panoply.backend.github$guard.invokeStatic(github.clj:10)
at panoply.backend.github$guard.invoke(github.clj:7)
at panoply.backend.github$get_access_token.invokeStatic(github.clj:13)
at panoply.backend.github$get_access_token.invoke(github.clj:12)
at panoply.backend.github$wrap_token$fn__7532.invoke(github.clj:34)
at castra.middleware$wrap_castra_session$fn__1465.invoke(middleware.clj:98)
at clojure.lang.Var.invoke(Var.java:379)
at ring.middleware.reload$wrap_reload$fn__7011.invoke(reload.clj:38)
at clojure.lang.Var.invoke(Var.java:379)
at tailrecursion.clojure_adapter_servlet.impl$service.invokeStatic(impl.clj:137)
at tailrecursion.clojure_adapter_servlet.impl$service.invoke(impl.clj:135)
at clojure.lang.Var.invoke(Var.java:383)
at tailrecursion.ClojureAdapterServlet.service(ClojureAdapterServlet.java:40)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:816)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1113)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1047)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:119)
at org.eclipse.jetty.server.Server.handle(Server.java:517)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:302)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:242)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:238)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:57)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:147)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
at java.lang.Thread.run(Thread.java:745)
@jumblerg i like that plan
so you're saying to opt in, you just place it above original castra in your middleware stack?
"around" it i guess
maybe it also has a config option so that stack traces are removed when in production mode.
@jumblerg: 👌👍 agreed
it could know its being wrapped by looking at a dynamic variable...
but then, maybe it makes more sense just to add a 2nd castra-something
middleware that does the new thing?