使用Yesod高效上传大文件

Ten*_*ner 12 haskell yesod

我想用我的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")
Run Code Online (Sandbox Code Playgroud)

它很好,除了几个问题:

  1. 文件的最大大小约为2兆字节.我有一个修复,但这是正确的方法吗?我的修复是覆盖我的应用程序的Yesod实例中的maximumContentLength方法的默认实现,如下所示:

    maximumContentLength _(Just(FileNewR _))= 2*1024*1024*1024 - 2千兆字节maximumContentLength _ _ = 2*1024*1024 - 2兆字节

  2. 使用的内存量等于文件的大小.这真的不是最理想的.我想使用来自http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html的 tempFileBackEnd,但我不知道如何实际连线进入我的请求并使其与表单逻辑(隐藏_token字段等)一起使用.

  3. 上传是"一次性":如何使其适用于向用户显示进度的基于Flash/Html5的上传者的任何示例?

Mic*_*man 11

  1. 你的解决方案是对的.maximumContentLength设置的目的是允许您为需要更大上载的特定路由覆盖此值.

  2. 这是yesod-core中当前文件处理设置的缺点.它目前硬编码使用内存文件上传.我们在过去的邮件列表中讨论过这不是最理想的.我刚刚为此创建了一个Github问题,修复程序将包含在Yesod 1.1中(虽然没有发布时间表).

  3. 抱歉,我没有这方面的例子.