Open samvher opened 7 years ago
To implement a custom SessionStore, you'll have to "fill" this data-type:
data SessionStore sess tx
= SessionStore
{ ss_runTx :: forall a. tx a -> IO a
, ss_loadSession :: SessionId -> tx (Maybe sess)
, ss_deleteSession :: SessionId -> tx ()
, ss_storeSession :: sess -> tx ()
, ss_toList :: tx [sess]
, ss_filterSessions :: (sess -> Bool) -> tx ()
, ss_mapSessions :: (sess -> tx sess) -> tx ()
}
You can take a look here for the implementation of the default STM session store. Basically, a SessionStore sess tx
is a store for sessions of type sess
running in the monad tx
.
ss_runTx
: how to lift your custom monad tx
into IO
. For the STM store, this is atomically
ss_loadSession
: load a session given an idss_deleteSession
: delete a session given an idss_storeSession
: write a sessionss_toList
: list all sessionsss_filterSessions
: keep only sessions that match the predicatess_mapSessions
: apply function to all stored sessionsThanks, that helps. I was a bit overwhelmed because it looked a lot more complicated than just the pair of load/store functions in the older versions of Spock. Is there a specific reason the readShowSessionPersist is no longer available? Let's say, if I would implement it, would you want to add it to the code base?
Also, is there a way to use a SpockAction monad as tx? Because it seems a bit unpleasant to open a separate database connection (for example in the IO monad), when Spock already has a set-up for the connection in place. But at the same time I think the SpockAction monad depends on the SessionStore, right?
I personally never used the readShowSessionPersist and wasn't aware that anyone used it. If you like to add it back it would make sense to have it sit on top of the stm
version such that it only flushes the stm
version's state to disk periodically and reads it once on launch. That way everything will stay performant. Alternatively one could also abstract over the read and show parts so that a user could theoretically also use safecopy
for example.
Currently there is not since the WebState
type of the SpockAction
holds the session manager, but there's no reason not to pass the database down to the SessionStore. But here also keep in mind that hitting the database for every session/request will be expensive, so having a layer on top with stm or using an in-memory database like redis is attractive.
Ah ok. I just noticed that it existed, and I think it's an easy way to get persistent sessions in a dev environment (like now, I often restart my spock app, and it forgets that I'm logged in so I have to go through that process for testing, which takes time). Having to "derive (Read, Show)" on your session type is a much smaller up-front investment than implementing a whole session storage system. If the way you suggest could be both persistent and performant I think that could actually be a valuable addition (maybe then it would be realistic to avoid using the database for persistence altogether).
I'm not sure what you mean about abstracting over read and show though.
With passing the database down to the SessionStore, you mean generating it with a function of PoolOrConn a, passing it the same instance that's also used to configure SpockAction?
By abstracting over read and show I meant that instead of using read
and show
in the code to parse/serialize to instead allow the user to provide a function parse :: BS.ByteString -> Either String a
and serialize :: a-> BS.ByteString
so that it's possible to use something other than read
and show
.
No. If you look at Web.Spock then all PoolOrConn a
are converted into a connection pool. You can then pass this into createSessionManager for example.
Hello, I tried to write custom SessionStore for Redis https://github.com/elephanter/spock-session-redis Is there better way than whole rewrite defaultSpockCfg method for Spock initialization with custom SessionStore? Also, Web.Spock.Config does not export errorHandler and errorTemplate methods, so I have to copy them. Maybe rename and export them as default methods?
Oh, nice!
I think you can implement your custom defaultSpockCfg
in terms of the existing defaultSpockCfg
: You would call the existing one first and then simply swap out sc_store
with your custom store.
There seems to be little documentation other than the types :)
I want to make my sessions persistent, I was hoping I could just use readShowSessionPersist (for a development environment) but it seems that in the version I'm using (0.11.0.0) that has been removed. Do you have an example implementation?