8

I'm trying to implement a server for a turn based game in Haskell. My choice would be to use Yesod for adminstration and meta-information (like, what games a user participates in and such).

I'd like to use web sockets to keep the in-game data overhead small.

Looking at the ws-chat example, I'm not sure how to get access to the Handler Monad and with it Persistent.

It would be perfect to have some bookkeeping-code for the connections wrapped around a "normal" Handler that itself updates the database and informs relevant users.

recursion.ninja
  • 5,377
  • 7
  • 46
  • 78
Tobi Nary
  • 4,566
  • 4
  • 30
  • 50
  • Does this example help? https://github.com/gertcuykens/haskell-design – Gert Cuykens Feb 23 '13 at 04:44
  • Not really, Gert. I'm looking for a way to use Yesods Persist library rather then Acid. Generally, i'd like to have a way to start a Yesod Handler Monad from within the WS.intercept-Handler. – Tobi Nary Feb 23 '13 at 13:47

3 Answers3

8

This is how I think it should look like.

{-# LANGUAGE QuasiQuotes, TypeFamilies, GeneralizedNewtypeDeriving, TemplateHaskell, OverloadedStrings, GADTs, FlexibleContexts #-}
module Main where
import Control.Monad.IO.Class (liftIO)
import Data.String (fromString)
import Database.Persist
import Database.Persist.TH
import Database.Persist.Sqlite
import Network.Wai.Application.Static (staticApp, defaultWebAppSettings, defaultFileServerSettings)
import Network.Wai.Handler.Warp (runSettings, defaultSettings, settingsIntercept, settingsPort)
import Network.Wai.Handler.WebSockets (intercept)
import qualified Network.WebSockets as WS

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
Person
    name String
    age Int
    deriving Show
|]

ws :: WS.Request -> WS.WebSockets WS.Hybi10 ()
ws r = do
    WS.acceptRequest r
    liftIO $ runSqlite ":memory:" $ do
        runMigration migrateAll
        michaelId <- insert $ Person "Michael" 26
        michael <- get michaelId
        liftIO $ print michael

main :: IO ()
main = runSettings defaultSettings
    { settingsPort = 9160
    , settingsIntercept = intercept $ ws
    } $ staticApp (defaultFileServerSettings $ fromString ".")
Gert Cuykens
  • 6,845
  • 13
  • 50
  • 84
4

If you're looking to run a Handler monad yourself, you can use runFakeHandler.

Michael Snoyman
  • 31,100
  • 3
  • 48
  • 77
  • Don't know if I am talking about the same handler as Jan but can you make something like this work :) https://gist.github.com/gertcuykens/5022515 – Gert Cuykens Feb 24 '13 at 04:07
  • Yes Gert, that is what I was looking for, thanks :) Michael: Thanks for replying. Seems I have been inaccurate describing my goals; yet Gert seemed to get what I wanted with your input :) Also, great work on Yesod! Thanks a lot for that :) I'm not sure if I should "accept" your answer, as it is Gerts comment that does the trick. – Tobi Nary Feb 24 '13 at 13:29
  • Can you gist your version because Michael is the one who knows for sure if there are any performance issues or something. – Gert Cuykens Feb 24 '13 at 16:18
  • Gert: I'd recommend giving your response as an answer so that Jan can accept it as the correct one. – Michael Snoyman Feb 24 '13 at 16:38
0

I am using Yesod.WebSockets library and was able to access DB in a web socket application like this:

voteApp :: WebSocketsT Handler ()
voteApp = do
  uuid <- liftIO nextRandom
  master <- getYesod
  runSqlPool (insert (Session uuid)) $ appConnPool master
  -- rest of the handler
dimsuz
  • 8,969
  • 8
  • 54
  • 88