在 pubSub 回调之外使用 Redis.Message

Use Redis.Message from outside of the pubSub callback

documentation for Hedis中给出了使用pubSub函数的例子:

pubSub :: PubSub -> (Message -> IO PubSub) -> Redis ()

pubSub (subscribe ["chat"]) $ \msg -> do
    putStrLn $ "Message from " ++ show (msgChannel msg)
    return $ unsubscribe ["chat"]

鉴于 pubSub return 是一个 Redis (),是否可以在代码的下方从回调外部重新使用此 msg 消息?

我正在从在 ScottyM monad 中运行的 Scotty 端点调用 pubSub,应该 return(长话短说)一个 json msg

myEndpoint :: ScottyM ()
myEndpoint =
    post "/hello/world" $ do
        data :: MyData <- jsonData
        runRedis redisConn $ do
            pubSub (subscribe ["channel"]) $ \msg -> do
                doSomethingWith msg
                return $ unsubscribe ["channel"]

        -- how is it possible to retrieve `msg` from here?
        json $ somethingBuiltFromMsg

或者,有没有办法在回调中使用 Scotty 的 json?到目前为止我还没能做到这一点。

我假设您打算进一步缩进 json

为此,您可以在 IO 中使用可变变量,例如IORef:

import Data.IORef (newIORef, writeIORef, readIORef)
import Control.Monad.IO.Class (liftIO)

myEndpoint :: ScottyM ()
myEndpoint =
    post "/hello/world" $ do
        data :: MyData <- jsonData
        msgRef <- liftIO (newIORef Nothing)
        runRedis redisConn $ do
            pubSub (subscribe ["channel"]) $ \msg -> do
                writeIORef msgRef (Just msg)
                return $ unsubscribe ["channel"]
        Just msg <- liftIO (readIORef msgRef)
        json $ doSomethingWithMsg msg

编辑:我想我真的不知道 runRedis 函数是否在收到消息之前阻塞,如果不是这种情况,那么您可以使用 MVar 代替:

import Control.Concurrent.MVar (putMVar, takeMVar, newEmptyMVar)
import Control.Monad.IO.Class (liftIO)

myEndpoint :: ScottyM ()
myEndpoint =
    post "/hello/world" $ do
        data :: MyData <- jsonData
        msgVar <- liftIO newEmptyMVar
        runRedis redisConn $ do
            pubSub (subscribe ["channel"]) $ \msg -> do
                putMVar msgVar msg
                return $ unsubscribe ["channel"]
        msg <- liftIO (takeMVar msgVar)
        json $ doSomethingWithMsg msg