2012-06-04 16 views
12

Chcę zaimplementować przesyłanie dużych plików za pomocą aplikacji Yesod. Teraz mam:Efektywne przesyłanie dużych plików za pomocą Yesod

module Handler.File where 

import Import 

import System.Random 
import System.FilePath 
import Control.Monad 
import qualified Data.ByteString.Lazy as LBS 
import qualified Data.Text.Encoding 

-- upload 

uploadDirectory :: FilePath -- FIXME: make this configurable 
uploadDirectory = "incoming" 

randomFileName :: IO FilePath 
randomFileName = do 
    fname'base <- replicateM 20 (randomRIO ('a','z')) 
    let fname = uploadDirectory </> fname'base <.> "bin" 
    return fname 

fileUploadForm :: Form (FileInfo, Textarea) 
fileUploadForm = renderDivs $ (,) 
    <$> fileAFormReq "Choose a file" 
    <*> areq textareaField "What's on the file?" Nothing 

getFileNewR :: Handler RepHtml 
getFileNewR = do 
    (formWidget, formEnctype) <- generateFormPost fileUploadForm 
    defaultLayout $ do 
     setTitle "Upload new file." 
     $(widgetFile "file-new") 

postFileNewR :: Handler RepHtml 
postFileNewR = do 
    user <- requireAuth 
    ((result, formWidget), formEnctype) <- runFormPost fileUploadForm 
    case result of 
    FormSuccess (fi,info) -> do 
       fn <- liftIO randomFileName 
       liftIO (LBS.writeFile fn (fileContent fi)) 
       let newFile = File (entityKey user) fn info (fileName fi) (fileContentType fi) 
       fid <- runDB $ insert newFile 
       redirect (FileViewR fid) 
    _ -> return() 

    defaultLayout $ do 
     setTitle "Upload new file." 
     $(widgetFile "file-new") 

Jest przeważnie w porządku, z wyjątkiem kilku problemów:

  1. Maksymalny rozmiar pliku jest około 2 megabajtów. Mam poprawkę, ale czy jest to właściwy sposób na zrobienie tego? Moja poprawka jest nadrzędne domyślną implementację metody maximumContentLength na przykład Yesod dla mojej aplikacji, na przykład:

    maximumContentLength _ (Tylko (FileNewR _)) = 2 * 1024 * 1024 * 1024 - 2 gigabajty maximumContentLength _ _ = 2 * 1024 * 1024 - 2 megabajty

  2. Ilość wykorzystanej pamięci jest równa wielkości pliku. To jest naprawdę nieoptymalne. Chciałbym użyć tempFileBackEnd z http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html, ale nie mam pojęcia, jak faktycznie podłączyć go do mojej prośby i sprawić, by działał z logiką formularzy (ukryte pole wpisane itd.).

  3. Przesyłanie to "pojedyncze ujęcie": przykłady, jak sprawić, aby działał on z przesyłającymi treści Flash/HTML5, które pokazują postępy dla użytkownika?

Odpowiedz

11
  1. Twoje rozwiązanie jest prawidłowe. Celem ustawienia maximumContentLength jest umożliwienie przesłonięcia tej wartości dla określonych tras, które wymagają większych plików.

  2. Jest to wada obecnej konfiguracji obsługi plików w takod-core. Obecnie jest to zakodowane na stałe, aby używać przesyłania plików w pamięci. W przeszłości omawialiśmy listę mailingową, która jest nieoptymalna. Właśnie stworzyłem dla tego Github issue, a poprawka zostanie uwzględniona w Yesod 1.1 (brak jednak harmonogramu przy wydaniu).

  3. Nie mam tego przykładu, przepraszam.

Powiązane problemy