Iteratee ã¨ããæ¦å¿µã¯ãHaskell çã«é©åãªè³æºç®¡çã¨åæå¯è½ãª IO ãããããããããã¦ã以ä¸ã®3ã¤ã®ããã±ã¼ã¸ãä¹±ç«ãããã¨ã«ãªã£ãã
- iteraee
- enumerator
- iterIO
æ¨å¹´ã® ICFP ã®éãIteratee ã®çã¿ã®è¦ªã§ãã Oleg ããã«ããã®ç¶æ³ãã©ãæã£ã¦ããã®ããã¨èãã¦ã¿ããæ°ããã¨ã¦ãããç¶æ³ã§ããããã¤ãã®å®è£ ãç¾ãå®éã«ä½¿ããããã¨ã§ãæ¬å½ã«å¿ è¦ãªæ©è½ãåããã§ããããã
ãããããã¨ãConduit ã«ãã£ã¦å½¼ã®é¡ããããå®ç¾ãããã®ãããããªãã
Iteratee ã«ã¯ä½ã足ããªãã£ãã®ãï¼
以ä¸ã¯ãenumerator ã®ä½¿ç¨çµé¨åºã¥ãèå¯ã ãããã¶ã Iteratee å ¨ä½ã«è¨ããã¨æãã
- Iteratee ã§è³æºãå²ãå½ã¦ãããªã
- Michael Snoyman ããã®ä¸æº
- ä¾å¤å¦çã大å¤
- liftIO 㨠catch ã使ãããã®ã«ãtryIO 㨠catchError ã使ããªãã¨ãããªã
- Enumerator ã¨ããæ
å ±æºãèªç±ã«å¼ãåããªã
- åãå«ãã Proxy ãµã¼ããä½ã£ã¦ãã人ã®ä¸æº
1) ã¯ç°¡åã«åãããenumFile ã¯ããã®ã«ãiterFile ããªãã
2) ã¯ãã³ã¼ããæ¸ãã¦ã¿ãã°ãããã«å«ã«ãªãã
3) ã¯é£ããã説æãã¦ã¿ããèªé£ã°ãã¦ããã£ã¦ããã¾ããªããWAI + Warp + http-enumerator 㧠Proxy ãä½ãã¨ããã以ä¸ã®ããã«ãã¼ã¿ãããåããããã
---a--> ---c--> Brower Proxy Server <--b--- <--d---
ããã§ãHTTP ã® POST ãèãããHTTP Request ã®ããã£ã¯ãa ãã c ã¸åºå®é·ã®ãããã¡ã使ã£ã¦ã¹ããªã¼ãã³ã°ããã¦ã»ãããHTTP Response ã®ããã£ã d ãã b ã¸åºå®é·ã®ãããã¡ã使ã£ã¦ã¹ããªã¼ãã³ã°ããã¦ã»ããã
WAI ã§ã¯ãa ã® HTTP Reuqest ããããå¼æ°ã¨ãã¦åãåããã¨ãã§ããããa ã®ããã£ã¯ enumerator ã¨ãã¦é 管ã®ä¸ã«åã¾ã£ã¦ããããã®ããã£ã c ãä½æãã http-enumrator ã«æ¸¡ãæ¹æ³ãåå¨ããªããéã« d ãã b ã¸ã®ã¹ããªã¼ãã³ã°ã¯ãä½ãããªãã¦ãå®ç¾ã§ããã
ã¤ã¾ããWAI ä¸ã« Proxy ãä½æããã¨ãä¸ãã¯ã¹ãã¢ï¼ãã©ã¯ã¼ããä¸ãã¯ã¹ããªã¼ãã³ã°ã«ãªããããã¯ã大ã㪠HTTP ããã£ãæ㤠DOS ã«å¯¾ãã¦ããã¾ãã«ãèå¼±ã ã
çµå±ãIteratee ã¯ç°¡åãªåé¡ã«å©ç¨ããã®ã¯ããã£ãããè¤éãªåé¡ã解ãã«ã¯çª®å±ãªæãã ã£ãã
Iteratee ã§ã¯ãEnumerator 㯠Iteratee ã¨ãããªã¼ãããã³ãé§åãã主役ã§ãã£ã¦ãèªåèªèº«ãã©ããã«å¼ã渡ããããã¨ãªãã¦æ³å®ããã¦ããªãã£ã訳ã ã
Conduit
æ¨å¹´ã®11æé ã«ãMichael ããã«3) ã®ä¸æºãä¼ããã¨ãããæåã¯ç解ãããªãã£ãã幸éãªãã¨ã«ããã®ããããã¤ã¿ãªã¢äººã Proxy ãä½ã£ã¦ãã¦ãåã®åé¡ãç解ãã¦ããããããã¦ãäºäººæããã§ã®èª¬æãå§ã¾ã£ããçµå±ãOleg ããã¨ãã3 ã¤ã®ã©ã¤ããªã®ä½è ã¨ããå·»ãè¾¼ãã 大è°è«ãèµ·ãããenumerator ã«ä¸æºãæãã¦ãã Michael ãããççãªå¢ã㧠Conduit ãå®è£ ãããyesodweb のブログãè¦ãã°ããã®å¢ããåããã ããã
Conduit ã¯ãIteratee ã® push åãæ¹ããpull åã«å ç¥å¸°ãããã3人ã®ç»å ´äººç©ã®ååã¯ä»¥ä¸ã®éãã
- çç£è ï¼Source
- æ¶è²»è ï¼Sink
- ãã¤ãï¼Conduit
Sink ã¨ããååã«ã¯éåæãããããæ°´é管ãæå³ãã Conduit ããã®é£æ³ã¨æãã°ç´å¾ã§ããã
Conduit ã§ã¯ãã¢ããã IO (㨠ST) ã«å¶éãã¦ãããIORef (STRef) ã使ã£ã¦ãè³æºã®è§£æ¾ã管çãããã¾ããä¸è¨3ã¤ã®åé¡ããã¹ã¦è§£æ±ºããã¦ããã
1) ã解決ããä¾ï¼
import Data.Conduit import qualified Data.Conduit.Binary as CB copyFile :: FilePath -> FilePath -> IO () copyFile src dest = runResourceT $ CB.sourceFile src $$ CB.sinkFile dest
2) ã¯ãlifted-base ã® Control.Exception.Lifted ãèªç±èªå¨ã«ä½¿ãããã¨ã§è§£æ±ºããã¦ããã2) ã¨3) ã解決ããä¾ã®ä¸é¨ã示ãï¼
import Control.Exception (SomeException) import Control.Exception.Lifted (catch) import qualified Network.HTTP.Conduit as H import Network.Wai -- WAI ã® Request ã HTTP.Conduit ã® Request ã¸å¤æ toHTTPRequest :: Request -> RevProxyRoute -> Int64 -> H.Request IO toHTTPRequest req route len = H.def { H.host = revProxyDomain route , H.port = revProxyPort route , H.secure = isSecure req , H.checkCerts = H.defaultCheckCerts , H.requestHeaders = addForwardedFor req $ requestHeaders req , H.path = pathByteString path' , H.queryString = rawQueryString req -- WAI ãã Source ãªããã£ãåããï¼ -- enumerator ã ã¨ãããã§ããªã , H.requestBody = H.RequestBodySource len (toSource . requestBody $ req) , H.method = requestMethod req , H.proxy = Nothing , H.rawBody = False , H.decompress = H.alwaysDecompress } where path = fromByteString $ rawPathInfo req src = revProxySrc route dst = revProxyDst route path' = dst </> (path <\> src) -- catch ãèªç±èªå¨ã ã revProxyApp :: ClassicAppSpec -> RevProxyAppSpec -> RevProxyRoute -> Application revProxyApp cspec spec route req = revProxyApp' cspec spec route req `catch` badGateway cspec req revProxyApp' :: ClassicAppSpec -> RevProxyAppSpec -> RevProxyRoute -> Application revProxyApp' cspec spec route req = do let mlen = getLen req len = fromMaybe 0 mlen httpReq = toHTTPRequest req route len -- Request ã®ããã£ãã¹ããªã¼ãã³ã°ããªãã転é H.Response status hdr downbody <- H.http httpReq mgr let hdr' = fixHeader hdr liftIO $ logger cspec req status (fromIntegral <$> mlen) -- Response ã®ããã£ã¯èªåçã«ã¹ããªã¼ãã³ã°ã«ãªã return $ ResponseSource status hdr' (toSource downbody) where mgr = revProxyManager spec fixHeader = addVia cspec req . filter p p ("Content-Encoding", _) = False p _ = True badGateway :: ClassicAppSpec -> Request-> SomeException -> ResourceT IO Response badGateway cspec req _ = do liftIO $ logger cspec req st Nothing return $ ResponseBuilder st hdr bdy where hdr = addServer cspec textPlainHeader bdy = byteStringToBuilder "Bad Gateway\r\n" st = statusBadGateway
åè
WAI 1.0 㨠Yesod 1.0 ã¯ãConduit ãã¼ã¹ã«ãªãã¾ãã