2012-06-04 5 views
12

Ich möchte mit meiner Jessod-Anwendung große Dateien hochladen. Im Moment habe ich:Effizientes Hochladen großer Dateien mit 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") 

Es ist vor allem gut, außer einige Probleme:

  1. Maximale Größe einer Datei ist ca. 2 Megabyte. Ich habe eine Lösung, aber ist es richtig, dies zu tun? Meine fix ist zwingende Standardimplementierung von maximumContentLength Methode in Yesod Beispiel für meine app, wie folgt aus:

    maximumContentLength _ (Just (FileNewR _)) = 2 * 1024 * 1024 * 1024-2 Gigabyte maximumContentLength _ _ = 2 * 1024 * 1024 - 2 Megabyte

  2. Die Größe des verwendeten Arbeitsspeichers entspricht der Größe einer Datei. Das ist wirklich suboptimal. Ich möchte tempFileBackEnd von http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html verwenden, aber ich habe keine Ahnung, wie man das tatsächlich in meine Anfrage einbindet und es mit Formularlogik arbeiten lässt (verstecktes _token Feld etc.).

  3. Der Upload ist "single shot": Gibt es Beispiele, wie man es mit Flash/Html5-basierten Uploadern, die dem Benutzer den Fortschritt zeigen, macht?

Antwort

11
  1. Ihre Lösung ist richtig. Mit der Einstellung "maximumContentLength" können Sie diesen Wert für bestimmte Routen überschreiben, die größere Uploads erfordern.

  2. Dies ist ein Nachteil der aktuellen Einrichtung der Dateiverarbeitung in yesod-core. Derzeit ist die Verwendung von In-Memory-Datei-Uploads fest programmiert. Wir haben auf der Mailing-Liste in der Vergangenheit diskutiert, dass dies suboptimal ist. Ich habe gerade eine Github issue dafür erstellt, und das Update wird in Jessod 1.1 enthalten sein (kein Zeitplan für die Freigabe).

  3. Ich habe kein Beispiel dafür, sorry.

Verwandte Themen