Corentin Dupont | 30 Aug 19:29 2012
Picon

happstack simpleHTTP & state monad

Hi all,
I'm trying to make a web server that manages its own state. The user can issue commands that modifies the state.
I did like below but unfortunatly the state is not keep after a command is issued...
What is the right way to do it? Is there any example sites with an internal state with happstack?

data Game = (the state of my game)
type NomicServer             = ServerPartT (StateT Game IO)

launchWebServer :: Game -> IO ()
launchWebServer initialState = do
   putStrLn "Starting web server...\nTo connect, drive your browser to \"http://localhost:8000/Login\""
   d <- getDataDir
   simpleHTTP' unpackStateT nullConf $ server d


server :: FilePath -> ServerPartT (StateT Game IO) Response
server d sh = mconcat [fileServe [] d, do
                                   decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096)
                                   html <- implSite "http://localhost:8000/" "" nomicSite
                                   return $ toResponse html]

unpackStateT:: Game -> UnWebT (StateT Game IO) Response -> UnWebT IO Response
unpackStateT g w = evalStateT w g
 
--handler for web routes
nomicSite :: Site PlayerCommand (NomicServer Html)
nomicSite = setDefault (Noop 0) Site {
      handleSite         = \f url -> unRouteT (routedNomicCommands url) f
    , formatPathSegments = \u -> (toPathSegments u, [])
    , parsePathSegments  = parseSegments fromPathSegments
}

Thanks a lot,
Corentin

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Erik Hesselink | 30 Aug 21:47 2012
Picon

Re: happstack simpleHTTP & state monad

The way you wrote it, you run the state transformer once for each
request. So the state will be available within a single request, but
not between requests. If you want to persist state between requests,
you can use one the the mutable variables available (TVar or MVar are
good choices; IORefs also work, but you have to take care about
concurrency, using e.g. atomicModifyIORef). Create them before calling
simpleHTTP, then pass them in to use them in your handler. You can put
them in a ReaderT to avoid passing them, if you want.

Another choice is to use something like a database or the file system
for persistent state. Databases usually handle most concurrency
problems for you, while file systems don't.

Regards,

Erik

On Thu, Aug 30, 2012 at 7:29 PM, Corentin Dupont
<corentin.dupont <at> gmail.com> wrote:
> Hi all,
> I'm trying to make a web server that manages its own state. The user can
> issue commands that modifies the state.
> I did like below but unfortunatly the state is not keep after a command is
> issued...
> What is the right way to do it? Is there any example sites with an internal
> state with happstack?
>
> data Game = (the state of my game)
> type NomicServer             = ServerPartT (StateT Game IO)
>
> launchWebServer :: Game -> IO ()
> launchWebServer initialState = do
>    putStrLn "Starting web server...\nTo connect, drive your browser to
> \"http://localhost:8000/Login\""
>    d <- getDataDir
>    simpleHTTP' unpackStateT nullConf $ server d
>
>
> server :: FilePath -> ServerPartT (StateT Game IO) Response
> server d sh = mconcat [fileServe [] d, do
>                                    decodeBody (defaultBodyPolicy "/tmp/"
> 4096 4096 4096)
>                                    html <- implSite "http://localhost:8000/"
> "" nomicSite
>                                    return $ toResponse html]
>
> unpackStateT:: Game -> UnWebT (StateT Game IO) Response -> UnWebT IO
> Response
> unpackStateT g w = evalStateT w g
>
> --handler for web routes
> nomicSite :: Site PlayerCommand (NomicServer Html)
> nomicSite = setDefault (Noop 0) Site {
>       handleSite         = \f url -> unRouteT (routedNomicCommands url) f
>     , formatPathSegments = \u -> (toPathSegments u, [])
>     , parsePathSegments  = parseSegments fromPathSegments
> }
>
> Thanks a lot,
> Corentin
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe <at> haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
Corentin Dupont | 30 Aug 22:42 2012
Picon

Re: happstack simpleHTTP & state monad

Hi Erik,
yes you're right, I'm experimenting with an IORef now (a TVar would be a better idea).
I also tried the idea expressed here, to keep the state:
https://groups.google.com/forum/?fromgroups=#!msg/happs/_JSpaJKub0k/oa0K01IBlh0J
But without success so far. The server is returning me the state in the Response type but I cannot manage to reinject it for the next call :)

Best,
Corentin

On Thu, Aug 30, 2012 at 9:47 PM, Erik Hesselink <hesselink <at> gmail.com> wrote:
The way you wrote it, you run the state transformer once for each
request. So the state will be available within a single request, but
not between requests. If you want to persist state between requests,
you can use one the the mutable variables available (TVar or MVar are
good choices; IORefs also work, but you have to take care about
concurrency, using e.g. atomicModifyIORef). Create them before calling
simpleHTTP, then pass them in to use them in your handler. You can put
them in a ReaderT to avoid passing them, if you want.

Another choice is to use something like a database or the file system
for persistent state. Databases usually handle most concurrency
problems for you, while file systems don't.

Regards,

Erik

On Thu, Aug 30, 2012 at 7:29 PM, Corentin Dupont
<corentin.dupont <at> gmail.com> wrote:
> Hi all,
> I'm trying to make a web server that manages its own state. The user can
> issue commands that modifies the state.
> I did like below but unfortunatly the state is not keep after a command is
> issued...
> What is the right way to do it? Is there any example sites with an internal
> state with happstack?
>
> data Game = (the state of my game)
> type NomicServer             = ServerPartT (StateT Game IO)
>
> launchWebServer :: Game -> IO ()
> launchWebServer initialState = do
>    putStrLn "Starting web server...\nTo connect, drive your browser to
> \"http://localhost:8000/Login\""
>    d <- getDataDir
>    simpleHTTP' unpackStateT nullConf $ server d
>
>
> server :: FilePath -> ServerPartT (StateT Game IO) Response
> server d sh = mconcat [fileServe [] d, do
>                                    decodeBody (defaultBodyPolicy "/tmp/"
> 4096 4096 4096)
>                                    html <- implSite "http://localhost:8000/"
> "" nomicSite
>                                    return $ toResponse html]
>
> unpackStateT:: Game -> UnWebT (StateT Game IO) Response -> UnWebT IO
> Response
> unpackStateT g w = evalStateT w g
>
> --handler for web routes
> nomicSite :: Site PlayerCommand (NomicServer Html)
> nomicSite = setDefault (Noop 0) Site {
>       handleSite         = \f url -> unRouteT (routedNomicCommands url) f
>     , formatPathSegments = \u -> (toPathSegments u, [])
>     , parsePathSegments  = parseSegments fromPathSegments
> }
>
> Thanks a lot,
> Corentin
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe <at> haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Gmane