chore: minio-runner

This commit is contained in:
Gregor Kleen 2021-06-24 10:47:43 +02:00
parent 555d8e64e5
commit 79ec5184e6
6 changed files with 58 additions and 5 deletions

View File

@ -101,6 +101,7 @@ sourceFileDBChunks :: (MonadThrow m, MonadHandler m, HandlerSite m ~ UniWorX, Ba
=> ((Int, Int) -> ReaderT SqlReadBackend m (Maybe ByteString) -> ReaderT SqlReadBackend m (Maybe ByteString)) -> FileContentChunkReference -> ConduitT i (ByteString, (Int, Int)) (ReaderT backend m) () => ((Int, Int) -> ReaderT SqlReadBackend m (Maybe ByteString) -> ReaderT SqlReadBackend m (Maybe ByteString)) -> FileContentChunkReference -> ConduitT i (ByteString, (Int, Int)) (ReaderT backend m) ()
sourceFileDBChunks cont chunkHash = transPipe (withReaderT $ projectBackend @SqlReadBackend) $ do sourceFileDBChunks cont chunkHash = transPipe (withReaderT $ projectBackend @SqlReadBackend) $ do
dbChunksize <- getsYesod $ view _appFileUploadDBChunksize dbChunksize <- getsYesod $ view _appFileUploadDBChunksize
-- mRunner <- getMinioRunner
let retrieveChunk = \case let retrieveChunk = \case
Nothing -> return Nothing Nothing -> return Nothing
Just start -> do Just start -> do
@ -109,11 +110,12 @@ sourceFileDBChunks cont chunkHash = transPipe (withReaderT $ projectBackend @Sql
return $ E.substring (fileContentChunk E.^. FileContentChunkContent) (E.val start) (E.val dbChunksize) return $ E.substring (fileContentChunk E.^. FileContentChunkContent) (E.val start) (E.val dbChunksize)
chunk <- fileChunkARC Nothing (chunkHash, (start, dbChunksize)) getChunkDB chunk <- fileChunkARC Nothing (chunkHash, (start, dbChunksize)) getChunkDB
case chunk of case chunk of
Nothing -> throwM SourceFilesContentUnavailable
Just c -> do Just c -> do
return . Just . ((c, (start, dbChunksize)), ) $ if return . Just . ((c, (start, dbChunksize)), ) $ if
| olength c >= dbChunksize -> Just $ start + dbChunksize | olength c >= dbChunksize -> Just $ start + dbChunksize
| otherwise -> Nothing | otherwise -> Nothing
-- Nothing | Just MinioRunner{..} <- mRunner -> do
Nothing -> throwM SourceFilesContentUnavailable
C.unfoldM retrieveChunk $ Just (1 :: Int) C.unfoldM retrieveChunk $ Just (1 :: Int)

View File

@ -1,5 +1,7 @@
module Handler.Utils.Minio module Handler.Utils.Minio
( runAppMinio ( MinioRunner(..)
, getMinioRunner
, runAppMinio
, minioIsDoesNotExist , minioIsDoesNotExist
) where ) where
@ -10,14 +12,24 @@ import Network.Minio (Minio)
import qualified Network.Minio as Minio import qualified Network.Minio as Minio
newtype MinioRunner = MinioRunner
{ runMinio :: forall m' a. (MonadHandler m', HandlerSite m' ~ UniWorX, MonadThrow m') => Minio a -> m' a
}
getMinioRunner :: (MonadHandler m, HandlerSite m ~ UniWorX)
=> m (Maybe MinioRunner)
getMinioRunner = runMaybeT $ do
conn <- hoistMaybe =<< getsYesod appUploadCache
return MinioRunner{ runMinio = throwLeft <=< liftIO . Minio.runMinioWith conn }
runAppMinio :: ( MonadHandler m, HandlerSite m ~ UniWorX runAppMinio :: ( MonadHandler m, HandlerSite m ~ UniWorX
, MonadThrow m , MonadThrow m
, MonadPlus m , MonadPlus m
) )
=> Minio a -> m a => Minio a -> m a
runAppMinio act = do runAppMinio act = do
conn <- hoistMaybe =<< getsYesod appUploadCache MinioRunner{..} <- hoistMaybe =<< getMinioRunner
throwLeft <=< liftIO $ Minio.runMinioWith conn act runMinio act
minioIsDoesNotExist :: HttpException -> Bool minioIsDoesNotExist :: HttpException -> Bool
minioIsDoesNotExist (HttpExceptionRequest _ (StatusCodeException resp _)) minioIsDoesNotExist (HttpExceptionRequest _ (StatusCodeException resp _))

View File

@ -6,7 +6,7 @@ module Model.Types.File
, File(..), _fileTitle, _fileContent, _fileModified , File(..), _fileTitle, _fileContent, _fileModified
, PureFile, toPureFile, fromPureFile, pureFileToFileReference, _pureFileContent , PureFile, toPureFile, fromPureFile, pureFileToFileReference, _pureFileContent
, transFile , transFile
, minioFileReference, etagFileReference , minioFileChunkReference, minioFileReference, etagFileReference
, FileReference(..), _fileReferenceTitle, _fileReferenceContent, _fileReferenceModified , FileReference(..), _fileReferenceTitle, _fileReferenceContent, _fileReferenceModified
, HasFileReference(..), IsFileReference(..), FileReferenceResidual(FileReferenceResidual, FileReferenceResidualEither, unFileReferenceResidualEither, FileReferenceResidualEntity, fileReferenceResidualEntityKey, fileReferenceResidualEntityResidual, unPureFileResidual) , HasFileReference(..), IsFileReference(..), FileReferenceResidual(FileReferenceResidual, FileReferenceResidualEither, unFileReferenceResidualEither, FileReferenceResidualEntity, fileReferenceResidualEntityKey, fileReferenceResidualEntityResidual, unPureFileResidual)
, FileReferenceTitleMap(..) , FileReferenceTitleMap(..)
@ -39,6 +39,8 @@ import Text.Show
import qualified Data.Aeson as JSON import qualified Data.Aeson as JSON
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Text as Text
newtype FileContentChunkReference = FileContentChunkReference (Digest SHA3_512) newtype FileContentChunkReference = FileContentChunkReference (Digest SHA3_512)
@ -55,6 +57,13 @@ instance PersistFieldSql FileContentChunkReference where
makeWrapped ''FileContentChunkReference makeWrapped ''FileContentChunkReference
minioFileChunkReference :: Prism' Minio.Object FileContentReference
minioFileChunkReference = prism' toObjectName fromObjectName
where toObjectName = (chunkPrefix <>) . decodeUtf8 . Base64.encodeUnpadded . ByteArray.convert
fromObjectName = fmap (review _Wrapped) . Crypto.digestFromByteString <=< preview _Right . Base64.decodeUnpadded . encodeUtf8 <=< Text.stripPrefix chunkPrefix
chunkPrefix = "partial."
newtype FileContentReference = FileContentReference (Digest SHA3_512) newtype FileContentReference = FileContentReference (Digest SHA3_512)
deriving (Eq, Ord, Read, Show, Lift, Generic, Typeable) deriving (Eq, Ord, Read, Show, Lift, Generic, Typeable)
deriving newtype ( PersistField deriving newtype ( PersistField

View File

@ -0,0 +1,15 @@
module Crypto.Hash.TestInstances
() where
import Crypto.Hash (Digest, HashAlgorithm)
import qualified Crypto.Hash as Crypto
import TestImport
import qualified Data.ByteArray as BA
instance HashAlgorithm a => Arbitrary (Digest a) where
arbitrary = Crypto.hash @ByteString @a <$> arbitrary
instance CoArbitrary (Digest a) where
coarbitrary = coarbitrary . BA.convert @_ @ByteString
instance HashAlgorithm a => Function (Digest a) where
function = functionShow

View File

@ -57,6 +57,13 @@ instance Arbitrary (FileReferenceTitleMap fileid (FileFieldUserOption Bool)) =>
arbitrary = genericArbitrary arbitrary = genericArbitrary
shrink = genericShrink shrink = genericShrink
deriving newtype instance Arbitrary FileContentReference
instance CoArbitrary FileContentReference
instance Function FileContentReference
deriving newtype instance Arbitrary FileContentChunkReference
instance CoArbitrary FileContentChunkReference
instance Function FileContentChunkReference
spec :: Spec spec :: Spec
spec = do spec = do
parallel $ do parallel $ do
@ -70,3 +77,10 @@ spec = do
[ eqLaws, ordLaws, semigroupLaws, monoidLaws, semigroupMonoidLaws, idempotentSemigroupLaws ] [ eqLaws, ordLaws, semigroupLaws, monoidLaws, semigroupMonoidLaws, idempotentSemigroupLaws ]
lawsCheckHspec (Proxy @(FileField FileReference)) lawsCheckHspec (Proxy @(FileField FileReference))
[ eqLaws, ordLaws, jsonLaws ] [ eqLaws, ordLaws, jsonLaws ]
lawsCheckHspec (Proxy @FileContentChunkReference)
[ eqLaws, ordLaws, showLaws, persistFieldLaws, pathPieceLaws, httpApiDataLaws, jsonLaws, hashableLaws, binaryLaws ]
lawsCheckHspec (Proxy @FileContentReference)
[ eqLaws, ordLaws, showLaws, persistFieldLaws, pathPieceLaws, httpApiDataLaws, jsonLaws, hashableLaws, binaryLaws ]
describe "minioFileChunkReference" . it "is a prism" . property $ isPrism minioFileChunkReference
describe "minioFileReference" . it "is a prism" . property $ isPrism minioFileReference

View File

@ -5,3 +5,4 @@ module TestInstances
import Text.Blaze.TestInstances as TestInstances () import Text.Blaze.TestInstances as TestInstances ()
import Database.Persist.Sql.Types.TestInstances as TestInstances () import Database.Persist.Sql.Types.TestInstances as TestInstances ()
import Data.NonNull.TestInstances as TestInstances () import Data.NonNull.TestInstances as TestInstances ()
import Crypto.Hash.TestInstances as TestInstances ()