This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-30
Channels
- # arachne (5)
- # beginners (42)
- # cider (35)
- # cljs-dev (25)
- # cljsrn (2)
- # clojure (107)
- # clojure-dev (32)
- # clojure-finland (2)
- # clojure-greece (3)
- # clojure-italy (6)
- # clojure-nl (7)
- # clojure-spec (27)
- # clojure-uk (45)
- # clojurescript (152)
- # core-async (3)
- # cursive (26)
- # data-science (4)
- # datomic (33)
- # defnpodcast (1)
- # duct (12)
- # editors (3)
- # emacs (6)
- # events (5)
- # fulcro (6)
- # jobs (1)
- # lein-figwheel (9)
- # off-topic (7)
- # onyx (7)
- # re-frame (1)
- # reagent (9)
- # reitit (31)
- # shadow-cljs (130)
- # slack-help (1)
- # spacemacs (53)
- # tools-deps (55)
- # yada (4)
Is there a reason to use cljs.nodejs/require
(http://cljs.github.io/api/cljs.nodejs/) rather than simply js/require
?
Another q — can anyone recommend a library/implementation for locking (mutex) for JavaScript/ClojureScript?
missionary has a semaphore implementation https://github.com/leonoel/missionary
that's incorrect. You still need locking for critical sections when making async fn calls
nope. no such thing in JS. only one thing can happen and if there were locks you'd deadlock 100% of the time since the lock holder can never release.
@thheller again wrong (why not think about it for a second before replying?). Check this example for example: https://www.npmjs.com/package/async-lock#why-do-you-need-locking-on-single-threaded-nodejs
> In computer science, a lock or mutex (from mutual exclusion) is a synchronization mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution.
thats my understanding of mutex but I can you can stretch callsback to mean "many threads of execution"
I think async-lock
is a good choice, I was just wondering if people have used something smaller (perhaps included in GCL?)
yes, JavaScript has concurrency (but not parallelism)
As I understand it, locking or other mutexes are required when a common resource is used, not only by parallel processes, but also by concurrent processes (which JS has)
When I create an empty project with the following deps.edn
, I weirdly get an Error building classpath
. What am I doing wrong?
{:deps
{org.clojure/clojurescript {:mvn/version "1.10.339"}
org.clojure/core.async {:mvn/verison "0.4.474"}}}
In each case a critical section is protected from concurrent access by processes. In JS a "process" is a series of callbacks, so multiple "processes" using the same resource can interleave.
"verison"
@pesterhazy Oh dear, thanks
hello guys
i would like to handle login + refresh page still logged in, what i have tried is: 1- define js variable var identity = {{identity|json|safe}}; in the base.html template 2- wrap-identity middleware which try to add identity key like: (defn wrap-identity [handler] (fn [request] (prn request) (binding [identity (get-in request [:session :identity])] (handler request)))) actually i'm following Web Development with Clojure book example but i still get identity = null after successfully login session
did anybody face this problem and successfully fix it?
or how do you guys handle login + session management to not loss session info after reloading the page ?
I would recommend using let
instead of binding
. The binding
function is mostly for testing and/or for those rare cases where you want to override the value of some global var.
Also, I'd say you might want to avoid using the ->
threading operator in early stages. If you use let
and assign each value one at a time, you can inspect each step and see what's going on better.
That's the general advice, now for your specific question: What should be happening here is that some other middleware should be adding the session to your request before your wrap-identity
middleware gets called.
If the user has already logged in, the session value should contain the identity
, so you should be able to get it using
(let [session (:session request)
identity (:identity session) ...]
In the code you posted, you're passing request
to the handler
function, which means you're getting back a response. You're then getting the body of the response, and calling parse-string
on it, which is probably not what you want.
I'm guessing that your response body contains <html ...
, or in other words, the rendered page. It might be a web page or an error message, but it's not what you're looking for. Also, since you're only looking at the response coming back, it's probably not useful to get the identity
at that point, because all your processing has finished, and you're in the middle of returning the web page back to the client now
trying to include https://pushjs.org/ via :npm-deps
but I get:
[eval]:85
!id.startsWith(goog:);
^^^^
SyntaxError: missing ) after argument list
at new Script (vm.js:74:7)
at createScript (vm.js:246:10)
at Object.runInThisContext (vm.js:298:10)
at Object.<anonymous> ([eval]-wrapper:6:22)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at evalScript (internal/bootstrap/node.js:563:27)
at startup (internal/bootstrap/node.js:248:9)
at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)
@manutter51 thanks for this advice, but actually i'm defining identity as global var in to be used with render, i have another question if the user has already logged in how the session contain the identity ?
the flow as i understand: 1- make request, user send creds to the server 2- response should have {:session {:identity "email"}}
The basic idea is that somewhere early in your chain of middlewares you have a session handler middleware like ring-session
that adds the session to the request on the way in, and then extracts the session from the response on the way out. Then in your login
handler, you verify the user’s credentials, and add them to the session under the :identity
key. So something like
(if (valid?)
(let [session (:session request)
identity (get-user-identity-somehow)
session (assoc session :identity identity)]
(-> (make-response)
(assoc :session session)))
That’s code out of my head so apologies for any typos/bugs, but that’s the general idea — you pull the session out of the request, add the identity to it, then add the session to the response. The ring-session
middleware takes care of storing the session data between requests, so the next request that comes in should have your session (and identity
) added automatically.
So you don’t really need a global var for identity
, you can always get it from the request with (get-in request [:session :identity])
how can you set the identity to the request from the client?
(session/put! :identity id) -> after successful login ?
You do not do it from the client. It has to be done from the server. It would be a security vulnerability if the client could set the identity because then it would be exposed to hackers.
The way sessions work with clients is that the ring-session
middleware sets a cookie with a SessionID and sends that to the client. The client sends back the same SessionID in the cookie, and the ring-server
middleware uses that to look up the session data for that specific client.
Right, that’s the basic idea. It’s important to understand that all that is happening on the server, not the client.
yeah got it
:thumbsup:
@pesterhazy regarding locking, you can often solve the problem with a simple promise queue. (also be sure to think about whether a locking library will solve the problem when you have more than one node process)
We do not need locking because we have atoms no? ...having said that I do not have any experience report with trying atom coming back from concurrent promises
locking across events. I don’t even think the concurrency guarantees of atoms are necessary in js
Atoms do not save every scenario in true concurrency, for ClojureScript they are more than enough
I’m trying to think if atoms help in any scenario in cljs. Synchronous code cannot be interrupted in javascript.
JavaScript as a language has been designed to be concurrency safe... By being single threaded
Only within a given synchronous block of code. In node, where you will do lots of i/o, you can do things that are not safe and require synchronization.
I think atoms are helpful in that they allow people to pass around a box as a value and change the thing within it
@lilactown yeah agree but that has nothing to do with concurrency
if you do something like read a file and then write some files based on that read, you’ll probably need to lock around that piece of code. atoms and single-threadedness will not help you
@lilactown well, there are no ref
s in cljs so yeah, obviously
there was a discussion in here about how to deal with that. a simple solution is to create a little queue at the beginning of the function and chain promises until the queue is empty. but that won’t help if there’s more than one node process
I think that’s right: a locking library in js would only get you to the same level as a threaded language. it seems to me that it wouldn’t often be useful for just that reason, but I well could be wrong about that. i always use the database as synchronization
@niklas.collin it's a common misconception that there are no concurrency issues in JavaScript because it's single-threaded
"JavaScript as a language has been designed to be concurrency safe"
If multiple processes (as in composites of async callbacks) are using a common resource, interleaving access from multiple concurrent processes (in the same single-threaded environment) can cause concurrency problems
Web workers give you concurrency but due to their design you really can't fuck things up
A single browser window gives you concurrency
No web workers needed
This is the reason why libraries like async-lock exist: https://www.npmjs.com/package/async-lock#why-do-you-need-locking-on-single-threaded-nodejs
@pesterhazy but how can that help you if you have multiple node processes?
@lee.justin.m I'm actually not thinking about Node but the browser - multiple processes accessing IndexedDb
even in Node, there are resources that are local to a single process
oh that makes sense. (you had asked about nodejs require earlier so I thought that’s what you were doing)
Naturally in cases like in that Redis example you might get into trouble, that's why there's database transactions
right, I see how that was confusing, sorry about htat
@lee.justin.m thanks for the pointer to promise-queue, that's very helpful
@lee.justin.m when max-queue-length is reached, does it "block" (i.e. wait until the queue has space and then fire the promise) or throw?
in my case i’m not worrying about having a queue too long, but if I wanted to be more robust I think you’d want to throw
the docs are a bit sparse: https://github.com/promise-queue/promise-queue#readme
when you enter the function, you just check to see if there is a slot. if so, you decrement a slot counter and go. if not, you throw the arguments on a queue. then you throw a then
at the end of the function that checks the queue and repeats
>> throat(concurrency) This returns a function that acts a bit like a lock (exactly as a lock if concurrency is 1).
very useful pointers
yea. and lindesay forbes is the boss. that library is widely used and probably pretty robust
this kind of stuff is known too little in the cljs community (people are too quick to jump to core.async for these issues)
This kind of stuff is precisely what leads the cljs community to look for alternatives to mainstream paradigms. When you encounter the need to wrap promises in thunks, you're basically lazifying a reification, and at this point it should be common sense to start questioning your design choices.
if you dig a bit, npm is a gold mine of solid libraries
I'm guessing it's a problem with the cljs automatic commonjs analysis which surfaces with that lib
@niklas.collin the short answer is that npm-deps has rough edges so you may have an easier time with the alternatives (shadow-cljs or using a webpack bundle) — not sure if you knew this
(if you're interested in making it work with npm-deps, that's also great, just noting that it's not the path of least resistance)
@jplaza I think I tried https://github.com/MikeMcl/big.js/ some time ago and it worked fine
Thanks @pesterhazy! I’m using that, just wanted to know if there was a “CLJS way”
it has a ton of github stars so it must be good 🙂
@pesterhazy was afraid that would be the answer
google found me this: https://github.com/funcool/decimal @jplaza
@jplaza my advice would be to pick a lib off NPM and use it directly, via JS interop
I was hoping that if it can output wasm, then I could use cljs to write smart contract code
my understanding is that you’d have to implement your own gc with webasm in the main thread, so that’s a big obstacle
this aside - doing a webasm DSL in ClojureScript does sound fun / useful - probably even easy given it’s a s-expr based thing
not on hand - but there’s been a few talks at Clojure conferences over the years on this subject
np, if Webasm gets GC, calling into JS (which isn’t too painful), and multithreading then I could see us going for it - but this is a long way off
btw, I saw this talk earlier this month on the webassembly roadmap: https://www.youtube.com/watch?v=WTxPqDBo8CI&t=1830
so v2 is due next year targeting high level langauges, v3 later (so prob at least two years away) targeting dynamic languages
You can’t say they are rushing things