如何在snaplet中使用Network.WebSockets.Snap?

时间:2014-03-22 03:56:27

标签: haskell websocket haskell-snap-framework acid-state

能够在snaplet中使用Network.WebSockets模块会很高兴,但我无法弄清楚如何实际操作。

使用runWebSocketsSnap :: MonadSnap m => ServerApp -> m ()中的Network.WebSockets.Snap函数,很容易在我的应用中包含一个简单的无状态websocket服务器:

routes :: [(ByteString, Handler App App ())]
routes = [ ("/ws", runWebSocketsSnap wsApp) ]

wsApp :: PendingConnection -> IO () -- this is the ServerApp type
wsApp pending = do
    conn <- acceptRequest pending
    forever $ do
        msg <- receiveData conn
        sendTextData conn ("Echo " `mappend` msg :: Text)

但我的目标是维护webscket服务器的状态(例如,连接的客户端列表,如http://jaspervdj.be/websockets/example.html)。或者,访问snaplet的酸状态存储器会很棒。

我的第一个想法是liftIOHandler App App monad中的websocket操作,并编写这样的应用程序:

wsApp :: PendingConnection -> Handler App App ()
wsApp pending = do
    conn <- liftIO $ acceptRequest pending
    forever $ do
        msg <- liftIO $ receiveData conn
        update (SetLastMsg msg)
        liftIO $ sendTextData conn ("Stored msg in datastore.")

但是没有runWebSocketsSnap版本可以使用上述形式的应用,而我无法弄清楚如何修改现有版本(source on hackage)。在我看来,我需要一个替代forkIO代替Handler App App monad中的一个动作,但我对Haskell的理解,特别是Snap中的并发性在这里结束......

1 个答案:

答案 0 :(得分:4)

runWebSocketsSnap函数要求其参数的类型为PendingConnection -> IO ()。这意味着您无法直接访问该功能内部的App数据结构。您需要做的是将信息作为参数传递给函数。

routes = [ ("/ws", webSocketsDriver) ]

webSocketsDriver :: Handler App App ()
webSocketsDriver = do
    appState <- get
    runWebSocketsSnap (wsApp appState)

wsApp :: App -> PendingConnection -> IO ()
wsApp app pending = do
    ...