我正在尝试制作一个将数据存储为状态的愚蠢的网络服务器.我正在使用
Web.Scotty
.
I’ve used ReaderT before with scotty to access config,但遵循相同的方法在这里不起作用.它会根据每个请求重置状态.
我想在程序启动时设置初始状态,然后在程序的整个生命周期中保持相同的状态.
我怎样才能做到这一点? (以下为每个请求创建一个新状态)
- {-# LANGUAGE OverloadedStrings #-}
- import Web.Scotty.Trans
- import Control.Monad.State (StateT,evalStateT,lift)
- import qualified Control.Monad.State as S
- import Data.Text.Lazy (Text)
- main :: IO ()
- main = do
- let runner = flip evalStateT "message"
- scottyT 3000 runner runner routes
- routes :: ScottyT Text (StateT Text IO) ()
- routes = do
- get "/data" $do
- val <- lift S.get
- text val
- put "/data/:val" $do
- val <- param "val"
- lift $S.put val
- text val
解决方法
您所看到的行为绝对是预期的行为:
注意 documentation for
注意 documentation for
scottyT
中第三个参数的注释:
-> (m Response -> IO Response)
— Run monadm
intoIO
,called at each action.
您可以做的是将状态存储在StateT monad外部,以便您可以在每个操作的处理程序中恢复它.我能想到的最天真的方式是这样的:
- main :: IO ()
- main = do
- let s0 = "message"
- let transform = flip evalStateT s0
- runner <- restartableStateT s0
- scottyT 3000 transform runner routes
- restartableStateT :: s -> IO (StateT s IO a -> IO a)
- restartableStateT s0 = do
- r <- newIORef s0
- return $\act -> do
- s <- readioRef r
- (x,s') <- runStateT act s
- atomicModifyIORef' r $const (s',x)
但这并没有真正解决如果两个请求同时进入会发生什么,它只是“最后一个完成胜利”.