2012-04-25 15 views
5

Warpを使用して簡単な逆プロキシサーバーを構築しようとしています(他の多くの既製オプションが多数あるため、 )。WarpサーバーのMonadThrowインスタンスをResourceT Monad Transformerに追加する方法

これまでのところ、私のコードは、主にワープドキュメントから持ち上げられる

(出力をファイルに書き込むには、ちょうど中間テスト、再びドキュメントから持ち上げられる) :

import Network.Wai as W 
import Network.Wai.Handler.Warp 
import Network.HTTP.Types 
import Network.HTTP.Conduit as H 
import qualified Data.Conduit as C 
import Data.Conduit.Binary (sinkFile) 
import Blaze.ByteString.Builder.ByteString 
import Control.Monad.Trans.Resource 
import Control.Monad.IO.Class 

proxApp req = do 
    let hd = headerAccept "Some header" 
    {-liftIO $ logReq req-} 
    pRequest <- parseUrl "http://some_website.com" 
    H.withManager $ \manager -> do 
     Response _ _ _ src <- http pRequest manager 
     src C.$$ sinkFile "test.html" 
    return $ ResponseBuilder status200 [hd] $ fromByteString "OK\n" 

main = do 
    putStrLn "Setting up reverse proxy on 8080" 
    run 8080 proxApp 

私は内部のNetwork.HTTP操作を実行しようと

ResourceT Monadの場合、コンパイラはMonadThrowのインスタンスであることを正しく要求します。私の難しさは、これをモナド・スタックに追加するか、またはそのインスタンスをResourceTに追加する方法です。私は、HTTPの行を削除した場合

No instance for (MonadThrow 
        (conduit-0.1.1.1:Control.Monad.Trans.Resource.ResourceT IO)) 
    arising from a use of `proxApp' 
Possible fix: 
    add an instance declaration for 
    (MonadThrow 
    (conduit-0.1.1.1:Control.Monad.Trans.Resource.ResourceT IO)) 
In the second argument of `run', namely `proxApp' 
In a stmt of a 'do' block: run 8080 proxApp 
In the expression: 
    do { putStrLn "Setting up reverse proxy on 8080"; 
     run 8080 proxApp } 

は、MonadThrowインスタンスが不要になった、とすべてが正常に動作します:以下のコードでコンパイルエラーではありません。

新しいカスタムモナドをMonadThrowのインスタンスとして定義した場合、実際にそれを使用してサーバーを実行するにはどうすればよいですか?私のスタックでこの例外処理を導入する適切な方法を探しています(あるいはコンパイラだけでも満足しています)。 (あなたimport Control.Monad.Trans.ResourceはそうあなたがResourceTを取得する場合)

感謝/ O

+2

何が問題になるのでしょうか? ghc-7.4.1、http-conduit-1.4.1.2、conduit-0.4.1.1、warp-1.2.0.1を使用してこれをコンパイルします。 –

+0

私のバージョンのwarpのようです。 上記のコードはwarp-1.0.0.1でエラーを表示します warp-1.2.0.1にアップグレードして正常に動作しました。 ResourceTは、1.0.0.1でMonadThrowのインスタンスを定義しませんでしたが、1.2.0.1で_does_を定義しました。 これは確実に直接の問題を解決しますが、インスタンスが既に含まれていない場合1.0.0.1)? ありがとう!!!! – jdo

答えて

2

これはそれを行う必要があります:すべての応答のための

instance (MonadThrow m) => MonadThrow (ResourceT m) where 
    monadThrow = lift . monadThrow 
+0

'ResourceT'は' Data.Conduit'から再エクスポートされました –

+0

私はこれを受け入れられた回答としてマークしなければならないと思いますが、古いものを再インストールできないので、 warp-1.2.0.1(すべてのローカルモジュールを削除する前に)の登録を解除した後でも、オリジナルのConduitエクスポートを使用して、予想されるエラーを返します。 '' warp-1.0.0.1(カバン依存関係地獄、きれいな.cabalディレクトリでさえ)重複するインスタンスの宣言。つまり、私の元の問題はもはや簡単には再現されません。私は喜んで 'Duplicate instances'エラーを解決の有効性の証拠として取り上げます:)もう一度ありがとう!/O – jdo

0

感謝を。 warp-1.2.0.1で完全に動作するように見える以下のコードで終わりました。

proxApp req = do 
    liftIO $ logReq req 
    pRequest <- parseUrl "http://some_website.com" 
    H.withManager $ \manager -> do 
     Response status version headers src <- http pRequest manager 
     body <- src C.$$ responseSink 
     liftIO $ putStrLn $ show status 
     return $ ResponseBuilder status headers body 

responseSink = C.sinkState 
    (fromByteString "") 
    (\acc a -> return $ C.StateProcessing $ mappend acc $ fromByteString a) 
    (\acc -> return acc) 
関連する問題