Было бы неплохо иметь возможность использовать модуль Network.WebSockets
внутри снимка, но я не могу понять, как это сделать на самом деле.
Используя функцию runWebSocketsSnap :: MonadSnap m => ServerApp -> m ()
из Network.WebSockets.Snap
, легко включить в мое приложение простой сервер веб-сокетов без сохранения состояния:
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)
Но моя цель — поддерживать состояние сервера веб-сайта (например, список подключенных клиентов, как в http://jaspervdj.be/websockets/example.html). В качестве альтернативы доступ к кислотному хранилищу Snaplet был бы отличным.
Моей первой идеей было liftIO
liftIO
действия веб-сокета в Handler App App
монаде и написать такое приложение:
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
, которая принимает приложение вышеуказанной формы, и я не могу понять, как модифицировать существующую (источник взлома). Мне кажется, что нужна альтернатива forkIO
, которая вместо этого выполняет действие в монаде Handler App App
, но мое понимание Haskell и особенно параллелизма в Snap на этом заканчивается...