【问题标题】:How to use Network.WebSockets.Snap in a snaplet?如何在 snaplet 中使用 Network.WebSockets.Snap?
【发布时间】:2014-04-29 16:12:53
【问题描述】:

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

使用Network.WebSockets.Snap 中的runWebSocketsSnap :: MonadSnap m => ServerApp -> m () 函数可以很容易地在我的应用程序中包含一个简单的无状态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 的酸性状态存储会很棒。

我的第一个想法是把liftIO websocket 的动作放到Handler App App monad 中,然后写一个这样的应用:

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 中的并发性到此结束......

【问题讨论】:

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


    【解决方案1】:

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

    routes = [ ("/ws", webSocketsDriver) ]
    
    webSocketsDriver :: Handler App App ()
    webSocketsDriver = do
        appState <- get
        runWebSocketsSnap (wsApp appState)
    
    wsApp :: App -> PendingConnection -> IO ()
    wsApp app pending = do
        ...
    

    【讨论】:

    • 最初,这对我来说似乎不是有状态的。但是,如果需要,我想您可以在应用程序中从 TVar、MVar 或 IORef 中抛出来管理状态。
    • 我同意@boyd-stephen-smith-jr,这解决了我的问题。特别是,我可以执行 acidState &lt;- getAcidState 之类的操作,将其传递给 wsApp,然后从那里使用 acid-state:Data.Acid.update acidState (SetLastMsg msg)
    • Handler monad 本质上是有状态的,因为它使 App(或 b 和 v)对您可用而无需显式传递它。此外,如果您想让它更简单,您可以定义 wsApp 函数内联(在get 行之后,执行let wsApp = ...),然后您不必传递任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多