2012-04-25 4 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의 인스턴스로 새 사용자 지정 모나드를 정의하는 경우 서버를 실제로 사용하려면 어떻게해야합니까? 내 스택 에서이 예외 처리를 소개하는 적절한 방법을 찾고 (또는 심지어 컴파일러를 만족).

감사/O는

+2

작동하지 않는 것의 예가 있습니까? ghc-7.4.1, http-conduit-1.4.1.2, conduit-0.4.1.1 및 warp-1.2.0.1 사용 –

+0

내 버전의 워프 때문인 것 같습니다. 위의 코드는 warp-1.0.0.1에서 오류를 나타냅니다. warp-1.2.0.1로 업그레이드되었으며 이제는 정상적으로 작동합니다. Haddock을 보면 ResourceT는 1.0.0.1에서는 MonadThrow의 인스턴스를 정의하지 않았지만 1.2.0.1에서는 _does_를 정의했습니다. 이것은 직접적인 문제를 확실히 해결하지만 인스턴스가 이미 포함되어 있지 않은 경우 인스턴스를 추가하는 방법은 무엇입니까? 1.0.0.1)? 감사합니다 !!!! – jdo

답변

2

이것은 (당신 import Control.Monad.Trans.Resource 그래서 당신이 얻을 경우 ResourceT)를 수행해야합니다 모든 응답에 대한

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

'ResourceT'는'Data.Conduit'에서 재방송됩니다. –

+0

나는 이것을 받아 들인 대답으로 표시해야 할 것 같지만, 나는 오래된 것을 다시 설치할 수 없으므로 믿음으로 받아 들여야 할 것입니다. warp-1.0.0.1 (깨끗한 .cabal 디렉토리에서도) - 모든 로컬 모듈을 제거하기 전에 warp-1.2.0.1을 등록 취소 한 후에도 여전히 원래 Conduit 내보내기를 사용하고 예상 된 오류를 제공합니다. 복제 인스턴스 선언 '. 즉, 원래의 문제는 더 이상 쉽게 재현되지 않습니다. 나는 행복하게'Duplicate instances' 오류를 솔루션의 유효성에 대한 증거로 사용합니다 :) 다시 한번 감사드립니다! /영형 – 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)