I'm trying to translate a component that implements a 'ring session store' protocol into a mount defstate
. I'm a bit stuck because can't find any examples. Here are two things I've tried so far.
I mean examples of the defstate
thing interacting with a protocol, any protocol.
Here (impl/memory-session-store)
is returning a map and impl/read-memory-session
expects to be given back that map.
(read-session [store key])
is one of three methods of ring's SessionStore protocol.
The error from the browser is: 'No implementation of method: :read-session of protocol: #'ring.middleware.session.store/SessionStore found for class: mount.core.DerefableState'.
I think it is the same error in both cases.
@cjmurphy I guess you have cljc
mode on? (https://github.com/tolitius/mount/blob/master/doc/clojurescript.md). In that case you need to deref (`@`) your started state where you use it.
All the code is cljs. Never heard of that mode before (so it must be the default??). Will read...
In ClojureScript it is indeed the default mode.
I assumed you use Clojure, as I was not aware that ring's SessionStore is also available in ClojureScript.
Oh sorry - must be in Clojure, getting confused.
So I don't have that mode on and shouldn't need it, I'm thinking. Would you expect :start (.start (session-storages/map->MemorySessionStore {}))
to work?
Then I guess the code that's using it is using it before the state has been started.
:start
is getting a {:memory-store #<Atom@4a8e8eaa: {}>}
, but that might not necessarily be a map. That's a good point you make. The error occurs after :start
has been done. It occurs when I refresh the browser. I can see it in the browser console and in the server REPL console.
Sorry not the broswer console, the browser itself, so msg is coming from server.
Oh - it is happening on auto-refresh. So I think what you say is correct. I've read some docs and you need to do some requires to make sure your mount system is up and running.
I'm still confused however, because the debug messages indicate that the mount 'system' is up and running before browser refresh.
I see another error msg from print-stack-trace: 'java.lang.RuntimeException: could not start [#'accounting.server.basic/session-store] due to'.
So you are right, it is not starting, even thou it is required by other things. Interesting how it is different to component.
There's nothing following the 'due to' unfortunately.
Those are the best errors 😉
So, nothing wrong with your defstate
per se, now you know where to search 🙂
Now it is saying it has started the session store, but the error message is "No implementation of method: :read-session of protocol: #'ring.middleware.session.store/SessionStore found for class: mount.core.NotStartedState".
So it hasn't really started it properly.
Or it has started it, but the code using it has captured the var's value before it was started.
But there are seconds between starting and me refreshing the browser.
Hmm - there is of course code that is using it. Maybe there has to be a pause before the referrer grabs it?? Seems a bit odd if that's the case.
Such pauses don't seem a good idea. So, you probably have setup your routes and middleware somewhere that uses the session-store
state, right?
Yes. The thing that uses session-store
(which is a defstate as well) is called middleware-2
, and it is used in the call to session/wrap-session
, which is a standard ring handler.
So the defstate is being used right away.
But it is a higher order function and I can't see it doing anything with this store, and it would not make sense for it to do anything with it until the handler inner function is being called, which is when I refresh the browser, and when the error messages turns up.
So there's a big pause already I would think 😉
Thanks for your help @arnout. I fixed the problem by requiring the namespace that has the defstate from the user namespace where the browser refresh is happening.
Alright, nice!
So you were 100% correct in what you said. Still hard for me to know exactly what is going on with this user namespace.
It just has stale state I guess.
Yeah probably. Using vars for storing and updating the state (which is what happens internally in mount), is a bit of a hack, and leads to surprises sometimes.
Right. I'm calling mount/start
from a function, exactly when the not code refresh is being done. Not like I was calling it as the namespace was loading i.e. outside of any function. Anyway, thanks again.