2019年5月14日火曜日

YesodのFileInfoにハマった

Yesodでアップロードファイルを扱うのにFileInfo型を使うんだけどこれ


data FileInfo = FileInfo {
    fileName :: !Text,
    fileContentType :: !Text,
    fileSourceRaw :: !(ConduitT () ByteString (ResourceT IO) ()),
    fileMove :: !(FilePath -> IO ())
}

これのfileSourceRawなんだが、こうやってとってみると[ByteString]がでてくる


bss <- sourceToList $ fileSource finfo

でたまたまこれをbase64化すればhtmlのimgタグで見れるかとおもいこうやってTextへ変換してhamletテンプレートに出力してみた

import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as C
import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8)
...
byteString2Base64 :: [ByteString] -> T.Text
byteString2Base64 = decodeUtf8 . B64.encode . C.unwords

これで吐かれたテキストを


<img src="data:#{contentType};base64,#{b64img}" class="img-fluid mx-auto d-block" alt="">

b64imgにbase64のTextが流れてくが、これが甘い



これだと出力される画像が途中で腐ってしまう、しばらくハマる...よくよく調べてみると、こんなのあった


fileSourceByteString!!

Yesod.Core.Handlerで定義されテイルではないですか、、、やりたかったことそのまんま。

気になったので実装みてみたら....


fileSourceByteString :: MonadResource m => FileInfo -> m S.ByteString
fileSourceByteString fileInfo = runConduit (L.toStrict <$> (fileSource fileInfo .| sinkLazy))

なんか、CombinatorsでつなげてLazyをStrictに直してるようにしか見えないけど、sourceToListを使った方法との違いが分からない。

まぁ結果オーライとします。