{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Antiope.S3.Lazy
( unsafeDownload
, unsafeDownloadRequest
, unsafeDownloadIfModifiedSince
, download
, downloadRequest
, downloadFromS3Uri
, downloadIfModifiedSince
, listObjectsV2
, listS3Uris
, dlistObjectsV2
, dlistS3Uris
, s3UriToListObjectsV2
, DownloadResult (..)
, S3Uri(..)
, AWS.BucketName
, AWS.ObjectKey
, UTCTime
) where
import Antiope.Core.Error
import Antiope.S3.GetObject
import Antiope.S3.Types (DownloadResult (..), S3Uri (S3Uri), s3UriToListObjectsV2)
import Control.Lens
import Control.Monad.IO.Unlift
import Control.Monad.Trans.Resource
import Data.Maybe (fromMaybe)
import Data.Time.Clock (UTCTime)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Network.AWS (MonadAWS)
import Network.HTTP.Types.Status (Status (..))
import qualified Antiope.S3.Internal as I
import qualified Data.ByteString.Lazy as LBS
import qualified Data.DList as DL
import qualified Network.AWS as AWS
import qualified Network.AWS.S3 as AWS
import qualified System.IO.Unsafe as IO
unsafeDownloadRequest :: (MonadAWS m, MonadResource m)
=> AWS.GetObject
-> m LBS.ByteString
unsafeDownloadRequest req = do
resp <- AWS.send req
lazyByteString (resp ^. AWS.gorsBody)
unsafeDownload :: (MonadAWS m, MonadResource m)
=> AWS.BucketName
-> AWS.ObjectKey
-> m LBS.ByteString
unsafeDownload bucketName objectKey = unsafeDownloadRequest (AWS.getObject bucketName objectKey)
unsafeDownloadIfModifiedSince :: (MonadAWS m, MonadResource m)
=> AWS.BucketName
-> AWS.ObjectKey
-> Maybe UTCTime
-> m (UTCTime, LBS.ByteString)
unsafeDownloadIfModifiedSince bkt obj since = do
let req = AWS.getObject bkt obj & AWS.goIfModifiedSince .~ since
resp <- AWS.send req
let modified = fromMaybe (posixSecondsToUTCTime 0) (resp ^. AWS.gorsLastModified)
body <- lazyByteString (resp ^. AWS.gorsBody)
pure (modified, body)
downloadIfModifiedSince :: (MonadAWS m, MonadResource m)
=> S3Uri
-> Maybe UTCTime
-> m (DownloadResult LBS.ByteString)
downloadIfModifiedSince uri@(S3Uri bucketName objectKey) since =
handleServiceError
(unsafeDownloadIfModifiedSince bucketName objectKey since)
(\(ts, bs) -> Downloaded ts uri bs)
(\case
Status 404 _ -> Just $ NotFound uri
Status 304 _ -> Just $ NotModified uri
_ -> Nothing
)
downloadRequest :: (MonadAWS m, MonadResource m)
=> AWS.GetObject
-> m (Maybe LBS.ByteString)
downloadRequest req = handle404ToNone (unsafeDownloadRequest req)
download :: (MonadAWS m, MonadResource m)
=> AWS.BucketName
-> AWS.ObjectKey
-> m (Maybe LBS.ByteString)
download bucketName objectKey = downloadRequest (AWS.getObject bucketName objectKey)
downloadFromS3Uri :: (MonadAWS m, MonadResource m)
=> S3Uri
-> m (Maybe LBS.ByteString)
downloadFromS3Uri (S3Uri b k) = download b k
dlistObjectsV2 :: (MonadAWS m, MonadResource m, MonadUnliftIO m)
=> AWS.ListObjectsV2
-> m (DL.DList AWS.ListObjectsV2Response)
dlistObjectsV2 req = do
f <- askUnliftIO
r <- AWS.send req
case r ^. AWS.lovrsIsTruncated of
Just True -> do
rs <- liftIO $ IO.unsafeInterleaveIO (unliftIO f (dlistObjectsV2 (I.nextPageReq req r)))
return (DL.cons r rs)
_ -> return (DL.singleton r)
dlistS3Uris :: (MonadAWS m, MonadResource m, MonadUnliftIO m)
=> AWS.ListObjectsV2
-> m (DL.DList S3Uri)
dlistS3Uris req = dlistObjectsV2 req >>= toS3Uris
where toS3Uris responses = return (responses >>= toS3Uris')
toS3Uris' response = do
c <- response ^. AWS.lovrsContents & DL.fromList
response ^.. AWS.lovrsName . _Just & DL.fromList <&> \bucketName -> S3Uri bucketName (c ^. AWS.oKey)
listObjectsV2 :: (MonadAWS m, MonadResource m, MonadUnliftIO m)
=> AWS.ListObjectsV2
-> m [AWS.ListObjectsV2Response]
listObjectsV2 req = DL.toList <$> dlistObjectsV2 req
listS3Uris :: (MonadAWS m, MonadResource m, MonadUnliftIO m)
=> AWS.ListObjectsV2
-> m [S3Uri]
listS3Uris req = DL.toList <$> dlistS3Uris req