mount

cjmurphy 2018-08-28T11:59:07.000100Z

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.

cjmurphy 2018-08-28T12:00:19.000100Z

I mean examples of the defstate thing interacting with a protocol, any protocol.

cjmurphy 2018-08-28T12:03:17.000100Z

Here (impl/memory-session-store) is returning a map and impl/read-memory-session expects to be given back that map.

cjmurphy 2018-08-28T12:05:11.000100Z

(read-session [store key]) is one of three methods of ring's SessionStore protocol.

cjmurphy 2018-08-28T12:06:22.000100Z

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'.

cjmurphy 2018-08-28T12:07:15.000100Z

I think it is the same error in both cases.

arnout 2018-08-28T12:29:55.000100Z

@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.

cjmurphy 2018-08-28T12:31:40.000100Z

All the code is cljs. Never heard of that mode before (so it must be the default??). Will read...

arnout 2018-08-28T12:32:15.000100Z

In ClojureScript it is indeed the default mode.

arnout 2018-08-28T12:32:42.000100Z

I assumed you use Clojure, as I was not aware that ring's SessionStore is also available in ClojureScript.

cjmurphy 2018-08-28T12:33:59.000100Z

Oh sorry - must be in Clojure, getting confused.

cjmurphy 2018-08-28T12:35:57.000100Z

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?

arnout 2018-08-28T12:39:58.000100Z

Then I guess the code that's using it is using it before the state has been started.

cjmurphy 2018-08-28T12:47:19.000100Z

: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.

cjmurphy 2018-08-28T12:48:07.000100Z

Sorry not the broswer console, the browser itself, so msg is coming from server.

cjmurphy 2018-08-28T12:50:16.000100Z

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.

cjmurphy 2018-08-28T12:51:25.000100Z

I'm still confused however, because the debug messages indicate that the mount 'system' is up and running before browser refresh.

cjmurphy 2018-08-28T12:53:41.000100Z

I see another error msg from print-stack-trace: 'java.lang.RuntimeException: could not start [#'accounting.server.basic/session-store] due to'.

cjmurphy 2018-08-28T12:54:39.000100Z

So you are right, it is not starting, even thou it is required by other things. Interesting how it is different to component.

cjmurphy 2018-08-28T12:55:59.000100Z

There's nothing following the 'due to' unfortunately.

arnout 2018-08-28T12:57:05.000100Z

Those are the best errors 😉

arnout 2018-08-28T12:57:43.000100Z

So, nothing wrong with your defstate per se, now you know where to search 🙂

cjmurphy 2018-08-28T12:58:16.000100Z

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".

cjmurphy 2018-08-28T12:58:31.000100Z

So it hasn't really started it properly.

arnout 2018-08-28T12:59:17.000100Z

Or it has started it, but the code using it has captured the var's value before it was started.

cjmurphy 2018-08-28T13:00:01.000100Z

But there are seconds between starting and me refreshing the browser.

cjmurphy 2018-08-28T13:01:37.000100Z

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.

arnout 2018-08-28T13:04:16.000100Z

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?

cjmurphy 2018-08-28T13:06:22.000100Z

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.

cjmurphy 2018-08-28T13:07:04.000100Z

So the defstate is being used right away.

cjmurphy 2018-08-28T13:09:48.000100Z

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.

cjmurphy 2018-08-28T13:10:55.000100Z

So there's a big pause already I would think 😉

cjmurphy 2018-08-28T13:18:23.000100Z

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.

arnout 2018-08-28T13:19:21.000100Z

Alright, nice!

cjmurphy 2018-08-28T13:20:47.000100Z

So you were 100% correct in what you said. Still hard for me to know exactly what is going on with this user namespace.

cjmurphy 2018-08-28T13:21:27.000100Z

It just has stale state I guess.

arnout 2018-08-28T13:23:44.000100Z

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.

cjmurphy 2018-08-28T13:26:49.000100Z

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.