如何结合 postgresql snaplet 和 websockets?
How to combine postgresql snaplet and websockets?
以下代码尝试组合两个单独工作的示例:
day 19 of 24 (2012) and e.g. ws example 但我把几乎所有与 websocket 相关的东西都拿走了,以获得一个小例子。
请找到下面的代码。 msgHandler
由 helloDb
调用,它将获取包含数据库连接的快照并将其传递给 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'd)编译直到 WS.runWebSocketsSnap
直接或间接调用 aFun
。
- 试图告诉
msgHandler :: (MonadIO m, HasPostgres m)
但 ghc 说没有 HasPosgres IO
的实例。我的感觉是,这在没有 IO 实例的情况下应该是可行的。或者是?
- 下面的代码试图在非 snaplet 上下文中使用 snaplet,但我不确定这是否是正确的方法。
是否有更好的方法在 snapframework 中组合 websockets 和 (db-) snaplets?在尝试了几种方法后,我处于严重的精神锁定状态,显然需要帮助。任何帮助(即使是关于我应该开始什么样的事情的小提示 learning/refreshing),将不胜感激!
{-# 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
您 运行 遇到的重叠实例问题 bug in the snaplet-postgresql-simple library 已修复,但修复尚未发布。你可能想问一下维护者。
与此同时,您可以从 Github 中提取最新版本的库,或者重新定义一个不同但同构于 ReaderT (Snaplet Postgres)
的类型,复制 HasPostgres
实例。
以下代码尝试组合两个单独工作的示例:
day 19 of 24 (2012) and e.g. ws example 但我把几乎所有与 websocket 相关的东西都拿走了,以获得一个小例子。
请找到下面的代码。 msgHandler
由 helloDb
调用,它将获取包含数据库连接的快照并将其传递给 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'd)编译直到WS.runWebSocketsSnap
直接或间接调用aFun
。- 试图告诉
msgHandler :: (MonadIO m, HasPostgres m)
但 ghc 说没有HasPosgres IO
的实例。我的感觉是,这在没有 IO 实例的情况下应该是可行的。或者是? - 下面的代码试图在非 snaplet 上下文中使用 snaplet,但我不确定这是否是正确的方法。
是否有更好的方法在 snapframework 中组合 websockets 和 (db-) snaplets?在尝试了几种方法后,我处于严重的精神锁定状态,显然需要帮助。任何帮助(即使是关于我应该开始什么样的事情的小提示 learning/refreshing),将不胜感激!
{-# 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
您 运行 遇到的重叠实例问题 bug in the snaplet-postgresql-simple library 已修复,但修复尚未发布。你可能想问一下维护者。
与此同时,您可以从 Github 中提取最新版本的库,或者重新定义一个不同但同构于 ReaderT (Snaplet Postgres)
的类型,复制 HasPostgres
实例。