Kevin
Kevin

Reputation: 1667

Shared data in Yesod

I want to share some data across requests in Yesod. In my case that data is a MVar (Data.Map Text ReadWriteLock), but I don't think the format of the data being shared matters too much here.

In Foundation.hs, there is a comment that says I can add fields to App, and every handler will have access to the data there. This seems like an approach I could use to share data between different handlers. I have been looking through the Yesod book, but I could not find any examples of getting data from App.

I think this might be a good use case for STM. I could share a TVar (Data.Map Text ReadWriteLock). But creating a TVar wraps the TVar in the STM monad. I might be mistaken, but to me that seems like the entire Yesod "main loop" would need to be run in the STM monad.

Upvotes: 3

Views: 248

Answers (2)

Sam
Sam

Reputation: 15310

This tutorial for building a file server with Yesod shows quite nicely how you can use STM to access shared data. The relevant part starts from part 2.

Upvotes: 2

asm
asm

Reputation: 8898

To elaborate on pxqr's comment, you want to do something like this.

In your Foundation.hs file (assuming you started your project with yesod init).

data App = App
    { ... other fields
    , shared :: TVar Int -- New shared TVar field
    }

Then in your Application.hs file where you create the App instance.

makeFoundation conf = do
    .... snip .....
    tv <- newTVarIO 0  -- Initialize your TVar

    let logger = Yesod.Core.Types.Logger loggerSet' getter
        foundation = App conf s manager logger tv  -- Add TVar here

    return foundation

Then in your Handler use the TVar

getHomeR :: Handler Html
getHomeR = do
    app <- getYesod  -- Get the instance of App
    x <- liftIO $ atomically $ do -- Read and update the TVar value.
      val <- readTVar (shared app)
      writeTVar (shared app) (val + 1)
      return val
    (formWidget, formEnctype) <- generateFormPost sampleForm
    let submission = Nothing :: Maybe (FileInfo, Text)
        handlerName = "getHomeR" :: Text
    defaultLayout $ do
        aDomId <- newIdent
         -- Use the TVar value (increments on each page refresh).
        setTitle $  fromString (show x)
        $(widgetFile "homepage")

Upvotes: 1

Related Questions