2013-06-18 4 views
1

this을 Haskell로 변환하려고 시도했습니다. 궁극적으로 나는 도관을 사용하고 싶지만, 지금은 게으른 ByteString이 할 것입니다.지연 줄을 사용한 스트리밍

그래서 나는 wrote this : 나는 그것을 시작하고 localhost:3000을 열 때

{-# LANGUAGE OverloadedStrings, RecordWildCards #-} 
module Main where 

--import Data.Conduit.Binary 
import Network.Wai 
import Network.Wai.Handler.Warp 
import Network.HTTP.Types 
import qualified Data.ByteString.Lazy as L 
import qualified Data.ByteString.Char8 as B 
import Control.Monad.Trans 
import System.IO 
import Control.Exception 
import Data.List.Split (splitOn) 

video = "videos/big_buck_bunny.mp4" 

main = bracket (openFile video ReadMode) (hClose) $ \h -> 
    run 3000 $ \Request{..} -> do 
     liftIO $ putStrLn "Connection" 
     total <- liftIO $ hFileSize h 
     case lookup "Range" requestHeaders of 
      Nothing -> do 
       v <- liftIO $ L.hGetContents h 
       return $ responseLBS ok200 [("Content-Type", "video/mp4"), ("Connection","keep-alive"), ("Content-Length", B.pack $ show total)] v 
      Just r -> do 
       let (starts:ends:_) = splitOn "-" $ drop 6 $ B.unpack r 
        start = read starts 
        end = if not (null ends) then read ends else total - 1 
       liftIO $ putStrLn $ "Range request " ++ show start ++ " " ++ show end 
       liftIO $ hSeek h AbsoluteSeek start 
       v <- liftIO $ L.hGetContents h 
       return $ responseLBS partialContent206 [("Content-Type", "video/mp4") 
                 , ("Accept-Ranges", "bytes") 
                 , ("Content-Length", B.pack . show $ (end - start) + 1) 
                 , ("Content-Range", B.pack $ concat ["bytes ", show start, "-", show end, "/", show total]) 
                 ] v 

그러나, 나는 이러한 오류를 얻을 : 이러한 오류가 발생하는 이유

Connection 
send: resource vanished (Connection reset by peer) 
Connection 
Range request 0 159240553 
send: resource vanished (Connection reset by peer) 
Connection 
Range request 158852274 159240553 
Connection 
videos/big_buck_bunny.mp4: hFileSize: illegal operation (handle is closed) 
Connection 
videos/big_buck_bunny.mp4: hFileSize: illegal operation (handle is closed) 

난 정말 이해가 안가, 대부분의 이유는 모두 resource vanished입니다. 그리고 핸들이 제가 처리하지 않고 닫히는 이유도 hClose입니다.

내가 잘못 생각한 사람이 있습니까?

답변

1

나는 첫 번째 오류에 대한 모르겠지만, 코드에서 명확한 버그가 : 당신이 그것으로 완료되면 파일을 닫는 알려져있다 hGetContents를 사용

  v <- liftIO $ L.hGetContents h 

은. 참조 : http://hackage.haskell.org/packages/archive/bytestring/0.10.2.0/doc/html/Data-ByteString-Lazy.html#v:hGetContents

파일을 처음 제공 한 후 핸들이 닫히고이어서 읽기 시도시 오류가 발생합니다.

  v <- liftIO $ L.readFile video 

그러나 당신이 수에 제한이 있기 때문에 안전하지 않은 참고 : 당신이 게으른 IO를 사용하려면 경우

, 당신은 뭔가를 시도 할 수 있습니다, 안전하고 건전 사실에도 불구하고 당신이 가질 수있는 열린 손잡이 중 하나를 사용 했으므로 그 핸들이 풀릴 때 확신 할 수 없습니다.

이러한 문제를 해결하려면 Conduits (또는 그 위에 빌드 된 라이브러리) 만 사용해야합니다. WAI에서이 RESPONSEFILE,하지만 난이 작업을 수행하는 방법을 정확하게 확실 해요 : http://hackage.haskell.org/packages/archive/wai/1.4.0.1/doc/html/Network-Wai.html#v:ResponseFile

업데이트 : 여기

하는 노력 코드가 RESPONSEFILE를 사용하여. https://gist.github.com/Tener/5803280

+0

닫지 않고 대체 할 수있는 것은 무엇입니까? – Lanbo

+0

@ LambdaDusk : 없습니다. 핸들은 항상 파일의 단일 위치를 가리 킵니다. 모든 사용자에 대해 현저하게 하나의 핸들을 사용할 수 없습니다. 전체 파일을 메모리로 읽거나 많은 핸들을 사용할 수 있습니다. – Tener

+0

그것은 방향의 한 걸음이지만, 내가 원하는대로 실제로 작동하지 않기 때문에, 나는 도관을 알아 내야합니다. 어쨌든 고마워! – Lanbo

0

hGetContents의 documentation에 따르면 하나의 EOF에 도달하면 핸들이 닫힙니다. 수행 명령 대신 hFileSizehGetContents을 사용하면 지연된 평가로 인해 파일의 필수 데이터 만 메모리에 저장됩니다. 범위 요청의 경우 hGetContents에서 가져온 자선 처리 결과에서 takedrop 함수를 사용하여 데이터를 가져와야합니다.

관련 문제