【发布时间】:2017-04-30 02:09:54
【问题描述】:
以下代码尝试结合两个单独工作的示例:
day 19 of 24 (2012) 和例如ws example 但我拿走了几乎所有与 websocket 相关的东西来获得一个小例子。
请在下面找到代码。 msgHandler 由helloDb 调用,它将获取包含db-connection 的snaplet 并将其传递给msgHandler。 snaplet-posgresql-simple docs(最后)给出了方便的实例以及如何在 Initializer monad 中使用其中之一的示例。
当我删除这两条注释行时,ghc 说有两个实例涉及超出范围的类型并且实例确实重叠:HasPostgres (ReaderT r m) 和 HasPostgres (ReaderT (Snaplet Postgres) m)。
所以问题是,如何让程序编译,以便我可以将 db-connection 从 snaplet 传递到 websocket-part。
我的目标是让 websocket 监听消息、查询数据库和发送消息包。我已经尝试过的其他事情:
-
aFun :: (MonadIO m, HasPostgres m) => ... m (..)同时具有 db-queries 和 websocket-things(均是 liftIO )编译,直到WS.runWebSocketsSnap直接或间接调用aFun。 - 试图告诉
msgHandler :: (MonadIO m, HasPostgres m),但随后ghc 说没有HasPosgres IO的实例。我的感觉是,这在没有 IO 实例的情况下应该是可行的。是吗? - 下面的代码尝试在非 snaplet 上下文中使用 snaplet,但我不确定这是否正确。
有没有更好的方法在 snapframework 中结合 websockets 和 (db-) snaplets?在尝试了几种方法后,我处于严重的精神锁定状态,显然需要帮助。任何帮助(甚至是关于我应该开始学习/刷新什么样的东西的小提示),将不胜感激!
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Maybe
import Data.Monoid ((<>))
import Control.Lens
import Control.Monad.Trans
import Control.Monad.Reader
import Snap.Snaplet
import Snap.Snaplet.PostgresqlSimple
import Snap.Http.Server
import Snap.Core as SC
import Data.ByteString as BS
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Network.WebSockets as WS
import qualified Network.WebSockets.Snap as WS
newtype App = App { _db :: Snaplet Postgres }
makeLenses ''App
msgHandler :: (MonadIO m) => App -> BS.ByteString -> WS.PendingConnection -> m ()
msgHandler appSt mUId pending = do
conn <- liftIO $ WS.acceptRequest pending
-- res <- liftIO $ runReaderT (query "SELECT name FROM users WHERE id = ?" (Only mUId)) dbSnaplet
-- liftIO $ print (res :: [Name])
liftIO $ T.putStrLn "msgHandler ended"
where dbSnaplet = view db appSt
initApp :: SnapletInit App App
initApp = makeSnaplet "myapp" "My application" Nothing $
App <$> nestSnaplet "db" db pgsInit
<* addRoutes [("/hello/:id", helloDb)]
newtype Name = Name { _nm :: Text } deriving (Show, Eq)
instance FromRow Name where fromRow = Name <$> field
helloDb :: Handler App App ()
helloDb = do
Just mUId <- getParam "id"
userName <- with db $ listToMaybe <$> query "SELECT name FROM users WHERE id = ?" (Only mUId)
writeText $ maybe "User not found" (\h -> "Hello, " <> (T.pack . show) h) (userName :: Maybe Name)
sStApp <- getSnapletState
WS.runWebSocketsSnap $ msgHandler (view snapletValue sStApp) mUId
main :: IO ()
main = serveSnaplet defaultConfig initApp
【问题讨论】:
标签: haskell haskell-snap-framework