Подтвердить что ты не робот

Эффективная загрузка большого файла с помощью 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 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")

В основном это нормально, за исключением нескольких проблем:

  • Максимальный размер файла составляет около 2 мегабайт. У меня есть исправление, но это правильный способ сделать это? Мое исправление переопределяет реализацию по умолчанию метода maximumContentLength в экземпляре Yesod для моего приложения, например:

    maximumContentLength _ (Just (FileNewR _)) = 2 * 1024 * 1024 * 1024 - 2 гигабайта maximumContentLength _ _ = 2 * 1024 * 1024 - 2 мегабайта

  • Объем используемой памяти равен размеру файла. Это действительно субоптимально. Я хотел бы использовать tempFileBackEnd из http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html, но я не знаю, как на самом деле подключить это к моему запросу и заставить его работать с логикой форм ( скрытое поле _token и т.д.).

  • Загрузка - это "одиночный снимок": любые примеры того, как заставить его работать с загрузчиками на основе Flash/Html5, которые показывают прогресс для пользователя?

4b9b3361

Ответ 1

  • Ваше решение верное. Цель параметра maximumContentLength - разрешить вам переопределять это значение для определенных маршрутов, требующих больших загрузок.

  • Это недостаток текущей настройки обработки файлов в yesod-core. В настоящее время он жестко запрограммирован для загрузки файлов в память. В прошлом мы обсуждали в списке рассылки, что это субоптимально. Я только что создал Github issue для этого, и исправление будет включено в Yesod 1.1 (расписание пока отсутствует).

  • У меня нет примера этого, извините.