packages feed

antiope-s3 2.0.0 → 3.1.0

raw patch · 3 files changed

+238/−71 lines, 3 filesdep +unliftio-corePVP ok

version bump matches the API change (PVP)

Dependencies added: unliftio-core

API changes (from Hackage documentation)

- Antiope.S3: class (Functor m, Applicative m, Monad m, MonadIO m, MonadCatch m) => MonadAWS (m :: * -> *)
+ Antiope.S3.Classy: Beijing :: Region
+ Antiope.S3.Classy: BucketName :: Text -> BucketName
+ Antiope.S3.Classy: ETag :: ByteString -> ETag
+ Antiope.S3.Classy: Frankfurt :: Region
+ Antiope.S3.Classy: GovCloud :: Region
+ Antiope.S3.Classy: GovCloudFIPS :: Region
+ Antiope.S3.Classy: Ireland :: Region
+ Antiope.S3.Classy: London :: Region
+ Antiope.S3.Classy: Montreal :: Region
+ Antiope.S3.Classy: Mumbai :: Region
+ Antiope.S3.Classy: NorthCalifornia :: Region
+ Antiope.S3.Classy: NorthVirginia :: Region
+ Antiope.S3.Classy: ObjectKey :: Text -> ObjectKey
+ Antiope.S3.Classy: Ohio :: Region
+ Antiope.S3.Classy: Oregon :: Region
+ Antiope.S3.Classy: S3Uri :: BucketName -> ObjectKey -> S3Uri
+ Antiope.S3.Classy: SaoPaulo :: Region
+ Antiope.S3.Classy: Seoul :: Region
+ Antiope.S3.Classy: Singapore :: Region
+ Antiope.S3.Classy: Sydney :: Region
+ Antiope.S3.Classy: Tokyo :: Region
+ Antiope.S3.Classy: class FromText a
+ Antiope.S3.Classy: class MonadIO m => MonadResource (m :: * -> *)
+ Antiope.S3.Classy: class ToLogStr msg
+ Antiope.S3.Classy: class ToText a
+ Antiope.S3.Classy: copySingle :: MonadAWS m => BucketName -> ObjectKey -> BucketName -> ObjectKey -> m ()
+ Antiope.S3.Classy: data Region
+ Antiope.S3.Classy: data S3Uri
+ Antiope.S3.Classy: downloadLBS :: MonadAWS m => BucketName -> ObjectKey -> m ByteString
+ Antiope.S3.Classy: downloadLBS' :: MonadAWS m => BucketName -> ObjectKey -> m (Maybe ByteString)
+ Antiope.S3.Classy: downloadS3Uri :: MonadAWS m => S3Uri -> m (Maybe ByteString)
+ Antiope.S3.Classy: fromS3Uri :: Text -> Maybe S3Uri
+ Antiope.S3.Classy: fromText :: FromText a => Text -> Either String a
+ Antiope.S3.Classy: lsBucketStream :: MonadAWS m => ListObjectsV2 -> ConduitM a Object m ()
+ Antiope.S3.Classy: newtype BucketName
+ Antiope.S3.Classy: newtype ETag
+ Antiope.S3.Classy: newtype ObjectKey
+ Antiope.S3.Classy: parser :: FromText a => Parser a
+ Antiope.S3.Classy: putContent :: MonadAWS m => BucketName -> ObjectKey -> ByteString -> m (Maybe ETag)
+ Antiope.S3.Classy: putContent' :: MonadAWS m => S3Uri -> ByteString -> m (Maybe ETag)
+ Antiope.S3.Classy: putFile :: MonadAWS m => BucketName -> ObjectKey -> FilePath -> m (Maybe ETag)
+ Antiope.S3.Classy: s3ObjectSource :: (MonadAWS m, MonadResource m) => BucketName -> ObjectKey -> m (ConduitT () ByteString m ())
+ Antiope.S3.Classy: toLogStr :: ToLogStr msg => msg -> LogStr
+ Antiope.S3.Classy: toS3Uri :: BucketName -> ObjectKey -> Text
+ Antiope.S3.Classy: toText :: ToText a => a -> Text
- Antiope.S3: copySingle :: MonadAWS m => BucketName -> ObjectKey -> BucketName -> ObjectKey -> m ()
+ Antiope.S3: copySingle :: (MonadUnliftIO m, HasEnv e) => e -> BucketName -> ObjectKey -> BucketName -> ObjectKey -> m ()
- Antiope.S3: downloadLBS :: MonadAWS m => BucketName -> ObjectKey -> m ByteString
+ Antiope.S3: downloadLBS :: (MonadResource m, HasEnv e) => e -> BucketName -> ObjectKey -> m ByteString
- Antiope.S3: downloadLBS' :: MonadAWS m => BucketName -> ObjectKey -> m (Maybe ByteString)
+ Antiope.S3: downloadLBS' :: (MonadResource m, MonadCatch m, HasEnv e) => e -> BucketName -> ObjectKey -> m (Maybe ByteString)
- Antiope.S3: downloadS3Uri :: MonadAWS m => S3Uri -> m (Maybe ByteString)
+ Antiope.S3: downloadS3Uri :: (MonadResource m, MonadCatch m, HasEnv e) => e -> S3Uri -> m (Maybe ByteString)
- Antiope.S3: lsBucketStream :: MonadAWS m => ListObjectsV2 -> ConduitT i Object m ()
+ Antiope.S3: lsBucketStream :: (HasEnv e, MonadUnliftIO m) => e -> ListObjectsV2 -> ConduitM a Object m ()
- Antiope.S3: putContent :: MonadAWS m => BucketName -> ObjectKey -> ByteString -> m (Maybe ETag)
+ Antiope.S3: putContent :: (MonadUnliftIO m, HasEnv e) => e -> BucketName -> ObjectKey -> ByteString -> m (Maybe ETag)
- Antiope.S3: putContent' :: MonadAWS m => S3Uri -> ByteString -> m (Maybe ETag)
+ Antiope.S3: putContent' :: (MonadUnliftIO m, HasEnv e) => e -> S3Uri -> ByteString -> m (Maybe ETag)
- Antiope.S3: putFile :: MonadAWS m => BucketName -> ObjectKey -> FilePath -> m (Maybe ETag)
+ Antiope.S3: putFile :: (HasEnv e, MonadUnliftIO m) => e -> BucketName -> ObjectKey -> FilePath -> m (Maybe ETag)
- Antiope.S3: s3ObjectSource :: (MonadResource m, MonadAWS m) => BucketName -> ObjectKey -> m (ConduitT () ByteString m ())
+ Antiope.S3: s3ObjectSource :: (MonadResource m, HasEnv e) => e -> BucketName -> ObjectKey -> m (ConduitT () ByteString m ())

Files

antiope-s3.cabal view
@@ -1,23 +1,22 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: d27f08dbb8adb0aede2eb51d192a537d08b2fb0e89644a43b6ddc599dc913b92+-- hash: 339850d6d7aa355605615867bda6f25b1bdca660d94c1fc26ccc9d1f7502f6af  name:           antiope-s3-version:        2.0.0+version:        3.1.0 description:    Please see the README on Github at <https://github.com/arbor/antiope#readme> category:       Services homepage:       https://github.com/arbor/antiope#readme bug-reports:    https://github.com/arbor/antiope/issues-author:         Tyler Durden+author:         Arbor Networks maintainer:     mayhem@arbor.net copyright:      Arbor Networks license:        MIT license-file:   LICENSE build-type:     Simple cabal-version:  >= 1.10- extra-source-files:     ChangeLog.md     README.md@@ -47,8 +46,10 @@     , network-uri     , resourcet     , text+    , unliftio-core   exposed-modules:       Antiope.S3+      Antiope.S3.Classy       Antiope.S3.Internal       Antiope.S3.Types   other-modules:@@ -79,6 +80,7 @@     , network-uri     , resourcet     , text+    , unliftio-core   other-modules:       Paths_antiope_s3   default-language: Haskell2010
src/Antiope/S3.hs view
@@ -16,7 +16,6 @@ , ObjectKey(..) , ETag(..) , S3Uri(..)-, MonadAWS , MonadResource , FromText(..), fromText , ToText(..)@@ -27,7 +26,7 @@ import Antiope.S3.Types             (S3Uri (S3Uri)) import Control.Lens import Control.Monad-import Control.Monad.Catch          (catch)+import Control.Monad.Catch          (MonadCatch, catch) import Control.Monad.Logger         (ToLogStr (..)) import Control.Monad.Trans.AWS      hiding (send) import Control.Monad.Trans.Resource@@ -38,7 +37,7 @@ import Data.Conduit.List            (unfoldM) import Data.Monoid                  ((<>)) import Data.Text                    (Text, pack, unpack)-import Network.AWS                  (Error (..), MonadAWS, ServiceError (..), send)+import Network.AWS                  (Error (..), ServiceError (..)) import Network.AWS.Data import Network.AWS.Data.Body        (_streamBody) import Network.AWS.S3@@ -46,10 +45,10 @@ import Network.URI                  (URI (..), URIAuth (..), parseURI)  import qualified Data.ByteString as BS+import qualified Network.AWS     as AWS  chunkSize :: ChunkSize-chunkSize = ChunkSize (1024*1024)-+chunkSize = ChunkSize (1024 * 1024)  fromS3Uri :: Text -> Maybe S3Uri fromS3Uri uri = do@@ -59,79 +58,82 @@   let k = pack $ drop 1 $ puri & uriPath   pure $ S3Uri (BucketName b) (ObjectKey k) -downloadLBS :: MonadAWS m-            => BucketName-            -> ObjectKey-            -> m ByteString-downloadLBS bucketName objectKey = do-  resp <- send $ getObject bucketName objectKey+downloadLBS :: (MonadResource m, HasEnv e)+  => e+  -> BucketName+  -> ObjectKey+  -> m ByteString+downloadLBS e bucketName objectKey = AWS.runAWS e $ do+  resp <- AWS.send $ getObject bucketName objectKey   (resp ^. gorsBody) `sinkBody` sinkLbs -downloadLBS' :: MonadAWS m-             => BucketName-             -> ObjectKey-             -> m (Maybe ByteString)-downloadLBS' bucketName objectKey = do-  ebs <- (Right <$> downloadLBS bucketName objectKey) `catch` \(e :: Error) -> case e of+downloadLBS' :: (MonadResource m, MonadCatch m, HasEnv e)+  => e+  -> BucketName+  -> ObjectKey+  -> m (Maybe ByteString)+downloadLBS' e bucketName objectKey = do+  ebs <- (Right <$> downloadLBS e bucketName objectKey) `catch` \(err :: Error) -> case err of     (ServiceError (ServiceError' _ (Status 404 _) _ _ _ _)) -> return (Left empty)-    _                                                       -> throwM e+    _                                                       -> throwM err   case ebs of     Right bs -> return (Just bs)     Left _   -> return Nothing -downloadS3Uri :: MonadAWS m-              => S3Uri-              -> m (Maybe ByteString)-downloadS3Uri (S3Uri b k) = downloadLBS' b k+downloadS3Uri :: (MonadResource m, MonadCatch m, HasEnv e)+  => e+  -> S3Uri+  -> m (Maybe ByteString)+downloadS3Uri e (S3Uri b k) = downloadLBS' e b k -s3ObjectSource :: (MonadResource m, MonadAWS m)-               => BucketName-               -> ObjectKey-               -> m (ConduitT () BS.ByteString m ())-s3ObjectSource bkt obj = do-  resp <- send $ getObject bkt obj+s3ObjectSource :: (MonadResource m, HasEnv e)+  => e+  -> BucketName+  -> ObjectKey+  -> m (ConduitT () BS.ByteString m ())+s3ObjectSource e bkt obj = do+  resp <- AWS.runAWS e $ AWS.send $ getObject bkt obj   return $ transPipe liftResourceT $ _streamBody $ resp ^. gorsBody  -- | Puts file into a specified S3 bucket-putFile :: MonadAWS m-        => BucketName       -- ^ Target bucket-        -> ObjectKey        -- ^ File name on S3-        -> FilePath         -- ^ Source file path-        -> m (Maybe ETag)   -- ^ Etag when the operation is successful-putFile b k f = do+putFile :: (HasEnv e, MonadUnliftIO m)+  => e+  -> BucketName       -- ^ Target bucket+  -> ObjectKey        -- ^ File name on S3+  -> FilePath         -- ^ Source file path+  -> m (Maybe ETag)   -- ^ Etag when the operation is successful+putFile e b k f = AWS.runResourceT . AWS.runAWS e $ do     req <- chunkedFile chunkSize f-    view porsETag <$> send (putObject b k req)+    view porsETag <$> AWS.send (putObject b k req) -putContent :: MonadAWS m-           => BucketName-           -> ObjectKey-           -> ByteString-           -> m (Maybe ETag)-putContent b k c =-  view porsETag <$> send (putObject b k (toBody c))+putContent :: (MonadUnliftIO m, HasEnv e)+  => e+  -> BucketName+  -> ObjectKey+  -> ByteString+  -> m (Maybe ETag)+putContent e b k c = AWS.runResourceT . AWS.runAWS e $+  view porsETag <$> AWS.send (putObject b k (toBody c)) -putContent' :: MonadAWS m-            => S3Uri-            -> ByteString-            -> m (Maybe ETag)-putContent' (S3Uri b k) = putContent b k+putContent' :: (MonadUnliftIO m, HasEnv e)+  => e+  -> S3Uri+  -> ByteString+  -> m (Maybe ETag)+putContent' e (S3Uri b k) = putContent e b k  -- | Copies a single object within S3-copySingle :: MonadAWS m-           => BucketName          -- ^ Source bucket name-           -> ObjectKey           -- ^ Source key-           -> BucketName          -- ^ Target bucket name-           -> ObjectKey           -- ^ Target key-           -> m ()-copySingle sb sk tb tk =-  void . send $ copyObject tb (toText sb <> "/" <> toText sk) tk+copySingle :: (MonadUnliftIO m, HasEnv e)+  => e+  -> BucketName          -- ^ Source bucket name+  -> ObjectKey           -- ^ Source key+  -> BucketName          -- ^ Target bucket name+  -> ObjectKey           -- ^ Target key+  -> m ()+copySingle e sb sk tb tk = AWS.runResourceT . AWS.runAWS e $+  void . AWS.send $ copyObject tb (toText sb <> "/" <> toText sk) tk      & coMetadataDirective ?~ MDCopy --- | Streams the entire set of results (i.e. all pages) of a ListObjectsV2--- request from S3.-lsBucketStream :: MonadAWS m => ListObjectsV2 -> ConduitT i Object m ()-lsBucketStream bar = unfoldM lsBucketPage (Just bar) .| CC.concatMap (^. lovrsContents)- -- Private --  -- Builds the request for the next page of a NextObjectsV2 request,@@ -141,13 +143,23 @@   initial & lovContinuationToken .~ resp ^. lovrsNextContinuationToken  -- The type signature is like this so that it can be used with `unfoldM`-lsBucketPage :: MonadAWS m-             => Maybe ListObjectsV2-             -> m (Maybe (ListObjectsV2Response, Maybe ListObjectsV2))-lsBucketPage Nothing    = pure Nothing-lsBucketPage (Just req) = do-  resp <- send req+lsBucketPage :: (MonadUnliftIO m, HasEnv e)+  => e+  -> Maybe ListObjectsV2+  -> m (Maybe (ListObjectsV2Response, Maybe ListObjectsV2))+lsBucketPage _ Nothing    = pure Nothing+lsBucketPage e (Just req) = AWS.runResourceT . AWS.runAWS e $ do+  resp <- AWS.send req   pure . Just . (resp, ) $     case resp ^. lovrsIsTruncated of       Just True -> Just $ nextPageReq req resp       _         -> Nothing++-- | Streams the entire set of results (i.e. all pages) of a ListObjectsV2+-- request from S3.+-- lsBucketStream :: MonadAWS m => ListObjectsV2 -> ConduitT i Object m ()+lsBucketStream :: (HasEnv e, MonadUnliftIO m)+  => e+  -> ListObjectsV2+  -> ConduitM a Object m ()+lsBucketStream e bar = unfoldM (lsBucketPage e) (Just bar) .| CC.concatMap (^. lovrsContents)
+ src/Antiope/S3/Classy.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections       #-}++module Antiope.S3.Classy+( downloadLBS+, downloadLBS'+, downloadS3Uri+, s3ObjectSource+, putFile, putContent , putContent'+, copySingle+, fromS3Uri+, toS3Uri+, lsBucketStream+, Region(..)+, BucketName(..)+, ObjectKey(..)+, ETag(..)+, S3Uri(..)+, MonadResource+, FromText(..), fromText+, ToText(..)+, ToLogStr(..)+) where++import Antiope.S3.Internal+import Antiope.S3.Types             (S3Uri (S3Uri))+import Control.Lens+import Control.Monad+import Control.Monad.Catch          (catch)+import Control.Monad.Logger         (ToLogStr (..))+import Control.Monad.Trans.AWS      hiding (send)+import Control.Monad.Trans.Resource+import Data.ByteString.Lazy         (ByteString, empty)+import Data.Conduit+import Data.Conduit.Binary          (sinkLbs)+import Data.Conduit.Combinators     as CC (concatMap)+import Data.Conduit.List            (unfoldM)+import Data.Monoid                  ((<>))+import Data.Text                    (Text, pack, unpack)+import Network.AWS                  (Error (..), MonadAWS, ServiceError (..))+import Network.AWS.Data+import Network.AWS.Data.Body        (_streamBody)+import Network.AWS.S3+import Network.HTTP.Types.Status    (Status (..))+import Network.URI                  (URI (..), URIAuth (..), parseURI)++import qualified Data.ByteString as BS+import qualified Network.AWS     as AWS++chunkSize :: ChunkSize+chunkSize = ChunkSize (1024 * 1024)++fromS3Uri :: Text -> Maybe S3Uri+fromS3Uri uri = do+  puri <- parseURI (unpack uri)+  auth <- puri & uriAuthority+  let b = pack $ auth & uriRegName       -- URI lib is pretty weird+  let k = pack $ drop 1 $ puri & uriPath+  pure $ S3Uri (BucketName b) (ObjectKey k)++downloadLBS :: MonadAWS m+  => BucketName+  -> ObjectKey+  -> m ByteString+downloadLBS bucketName objectKey = do+  resp <- AWS.send $ getObject bucketName objectKey+  (resp ^. gorsBody) `sinkBody` sinkLbs++downloadLBS' :: MonadAWS m+  => BucketName+  -> ObjectKey+  -> m (Maybe ByteString)+downloadLBS' bucketName objectKey = do+  ebs <- (Right <$> downloadLBS bucketName objectKey) `catch` \(err :: Error) -> case err of+    (ServiceError (ServiceError' _ (Status 404 _) _ _ _ _)) -> return (Left empty)+    _                                                       -> throwM err+  case ebs of+    Right bs -> return (Just bs)+    Left _   -> return Nothing++downloadS3Uri :: MonadAWS m+  => S3Uri+  -> m (Maybe ByteString)+downloadS3Uri (S3Uri b k) = downloadLBS' b k++s3ObjectSource :: (MonadAWS m, MonadResource m)+  => BucketName+  -> ObjectKey+  -> m (ConduitT () BS.ByteString m ())+s3ObjectSource bkt obj = do+  resp <- AWS.send $ getObject bkt obj+  return $ transPipe liftResourceT $ _streamBody $ resp ^. gorsBody++-- | Puts file into a specified S3 bucket+putFile :: MonadAWS m+  => BucketName       -- ^ Target bucket+  -> ObjectKey        -- ^ File name on S3+  -> FilePath         -- ^ Source file path+  -> m (Maybe ETag)   -- ^ Etag when the operation is successful+putFile b k f = do+    req <- chunkedFile chunkSize f+    view porsETag <$> AWS.send (putObject b k req)++putContent :: MonadAWS m+  => BucketName+  -> ObjectKey+  -> ByteString+  -> m (Maybe ETag)+putContent b k c = view porsETag <$> AWS.send (putObject b k (toBody c))++putContent' :: MonadAWS m+  => S3Uri+  -> ByteString+  -> m (Maybe ETag)+putContent' (S3Uri b k) = putContent b k++-- | Copies a single object within S3+copySingle :: MonadAWS m+  => BucketName          -- ^ Source bucket name+  -> ObjectKey           -- ^ Source key+  -> BucketName          -- ^ Target bucket name+  -> ObjectKey           -- ^ Target key+  -> m ()+copySingle sb sk tb tk = void . AWS.send $ copyObject tb (toText sb <> "/" <> toText sk) tk+     & coMetadataDirective ?~ MDCopy++-- Private --++-- Builds the request for the next page of a NextObjectsV2 request,+-- based on the original request and the most recent response.+nextPageReq :: ListObjectsV2 -> ListObjectsV2Response -> ListObjectsV2+nextPageReq initial resp =+  initial & lovContinuationToken .~ resp ^. lovrsNextContinuationToken++-- The type signature is like this so that it can be used with `unfoldM`+lsBucketPage :: MonadAWS m+  => Maybe ListObjectsV2+  -> m (Maybe (ListObjectsV2Response, Maybe ListObjectsV2))+lsBucketPage Nothing    = pure Nothing+lsBucketPage (Just req) = do+  resp <- AWS.send req+  pure . Just . (resp, ) $+    case resp ^. lovrsIsTruncated of+      Just True -> Just $ nextPageReq req resp+      _         -> Nothing++-- | Streams the entire set of results (i.e. all pages) of a ListObjectsV2+-- request from S3.+-- lsBucketStream :: MonadAWS m => ListObjectsV2 -> ConduitT i Object m ()+lsBucketStream :: MonadAWS m+  => ListObjectsV2+  -> ConduitM a Object m ()+lsBucketStream bar = unfoldM lsBucketPage (Just bar) .| CC.concatMap (^. lovrsContents)