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

der*_*itz 5 haskell websocket haskell-snap-framework acid-state

能够Network.WebSockets从 snaplet 内部使用该模块会很好,但我不知道如何实际操作。

使用它的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)
Run Code Online (Sandbox Code Playgroud)

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

我的第一个想法是liftIO将 websocket 操作添加到Handler App Appmonad 中,并编写一个这样的应用程序:

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.")
Run Code Online (Sandbox Code Playgroud)

但是没有runWebSocketsSnap采用上述形式的应用程序的版本,我不知道如何修改现有的应用程序(来自 hackage 的来源)。在我看来,人们需要一种替代方法来代替forkIOHandler App Appmonad中采取行动,但我对 Haskell 的理解,尤其是 Snap 中的并发性在这里结束......

mig*_*yte 4

runWebSocketsSnap 函数要求其参数的类型为PendingConnection -> IO ()。这意味着您无法直接访问该函数内部的应用程序数据结构。您需要做的是将信息作为参数传递给函数,如下所示。

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

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

wsApp :: App -> PendingConnection -> IO ()
wsApp app pending = do
    ...
Run Code Online (Sandbox Code Playgroud)