module StoreChunks (storeChunks) where
import Prelude ()
import BasicPrelude
import Crypto.Hash
(Digest, SHA1, SHA256, SHA512, hashUpdate, hashFinalize, hashInit)
import System.Directory
(createDirectoryIfMissing, renameFile, createFileLink, doesFileExist)
import UnexceptionalIO (Unexceptional, UIO)
import qualified UnexceptionalIO as UIO
import qualified Data.ByteString as ByteString
import qualified Data.IPLD.CID as CID
import qualified Data.Multihash as Multihash
digestCID :: (Multihash.Multihashable a) => Digest a -> Text
digestCID = CID.cidToText . CID.newCidV1 CID.Raw
createLinkIfNotExist :: FilePath -> FilePath -> IO ()
createLinkIfNotExist target link = do
exist <- doesFileExist link
when (not exist) $ createFileLink target link
storeChunks :: (Unexceptional m) =>
FilePath
-> String
-> UIO (Maybe ByteString)
-> m (
Either
IOError
(FilePath, Digest SHA1, Digest SHA256, Digest SHA512)
)
storeChunks storePath tmpName getChunk = loop hashInit hashInit hashInit
where
tmpPath = storePath ++ "/tmp/" ++ tmpName
cidPath digest = storePath ++ "/" ++ textToString (digestCID digest)
loop sha1 sha256 sha512 = do
Just chunk <- UIO.lift getChunk
if ByteString.null chunk then
finish sha1 sha256 sha512
else
step sha1 sha256 sha512 chunk
step sha1 sha256 sha512 chunk = do
result <- UIO.fromIO' (error.show) $ do
createDirectoryIfMissing True (storePath ++ "/tmp")
ByteString.appendFile tmpPath chunk
case result of
Left e -> return (Left e)
Right () ->
loop
(hashUpdate sha1 chunk)
(hashUpdate sha256 chunk)
(hashUpdate sha512 chunk)
finish sha1 sha256 sha512 = do
let sha1f = hashFinalize sha1
let sha256f = hashFinalize sha256
let sha512f = hashFinalize sha512
let finalPath = cidPath sha512f
let finalCID = textToString (digestCID sha512f)
(fmap.fmap) (const (finalPath, sha1f, sha256f, sha512f)) $
UIO.fromIO' (error.show) $ do
renameFile tmpPath finalPath
createLinkIfNotExist finalCID (cidPath sha1f)
createLinkIfNotExist finalCID (cidPath sha256f)