i'm implementing simple http server and i want my responses depend on some global state. For example if i get request 'get_settings' from the same client for the first time i will send large settings json, and for the second time i will just send 'Not-modified' http response.
Something like that
import Network.Simple.TCP
main = withSocketsDo $ do
let settings_state = 0 -- flag for settings response
serve (Host "127.0.0.1") "23980" $ \(conn_sock, remote_addr) -> do
putStrLn $ "TCP connection established from " ++ show remote_addr
(Just inp) <- recv conn_sock 1024
send conn_sock (process inp settings_state)
process :: B.ByteString -> Int -> B.ByteString
process inp flag
| flag == 0 = ... -- return full response and change global flag
| otherwise = ... -- return 'Not-modified'
And the question is how can i implement it? And i would like to do it as simple as possible, manually, without any Monad Transformers and so on. Let the code be ugly, but simple. Thanks
Since changing the flag clearly has some side effects, the result of process
will be in IO
:
process :: B.ByteString -> Int -> IO B.ByteString
Since you don't want to use any kind of monad transformer, you need to exchange the Int
with some mutable reference. Yes, you've read correctly: There are several types that are mutable, such as IORef
, MVar
, TVar
, MVector
, STRef
…. To stay simple, lets stick to IORef
.
process :: B.ByteString -> IORef Int -> IO B.ByteString
process inp flag = do
oldFlag <- readIORef flag
if oldFlag == 0
then do modifyIORef' flag (+1)
return bigJSONObject
else return notModified
Note that you didn't provide any logic for the flag, so I simply increased the value, but you probably want to do something else (or change the flag to IORef Bool
). Note that you also want to use atomicModifyIORef'
if you want to use the IORef
safely in a multithreaded program:
oldFlag <- atomicModifyIORef' flag (\o -> (o+1,o))
Either way, you need to create the IORef
with newIORef value
, so your code snippets becomes something like
main = withSocketsDo $ do
settings_state <- newIORef 0
serve (Host "127.0.0.1") "23980" $ \(conn_sock, remote_addr) -> do
-- ...