【问题标题】:How to combine postgresql snaplet and websockets?如何结合 postgresql snaplet 和 websockets?
【发布时间】:2017-04-30 02:09:54
【问题描述】:

以下代码尝试结合两个单独工作的示例:

day 19 of 24 (2012) 和例如ws example 但我拿走了几乎所有与 websocket 相关的东西来获得一个小例子。

请在下面找到代码。 msgHandlerhelloDb 调用,它将获取包含db-connection 的snaplet 并将其传递给msgHandlersnaplet-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


    【解决方案1】:

    您遇到的重叠实例问题是 bug in the snaplet-postgresql-simple library,已修复但尚未发布修复程序。您可能想向维护者询问这一点。

    与此同时,您可以从 Github 拉取最新版本的库,或者重新定义与 ReaderT (Snaplet Postgres) 不同但同构的类型,复制 HasPostgres 实例。

    【讨论】:

    • 获得了有效的源代码(至少可以编译),谢谢!你对“架构”有什么看法(这是ws与db结合的方式)吗?
    • 我对框架不够熟悉,无法说出正确的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 2014-04-29
    • 2012-10-19
    相关资源
    最近更新 更多