Add statObject high-level API (#11)

This commit is contained in:
Krishnan Parthasarathi 2017-02-11 14:38:33 +05:30 committed by Aditya Manthramurthy
parent 153c5a67cd
commit 00176ff976
6 changed files with 64 additions and 7 deletions

View File

@ -43,6 +43,7 @@ module Network.Minio
, putObjectFromSource , putObjectFromSource
, getObject , getObject
, statObject
) where ) where
@ -96,3 +97,7 @@ makeBucket :: Bucket -> Maybe Region -> Minio ()
makeBucket bucket regionMay= do makeBucket bucket regionMay= do
region <- maybe (asks $ connectRegion . mcConnInfo) return regionMay region <- maybe (asks $ connectRegion . mcConnInfo) return regionMay
putBucket bucket region putBucket bucket region
-- | Get an object's metadata from the object store.
statObject :: Bucket -> Object -> Minio ObjectInfo
statObject bucket object = headObject bucket object

View File

@ -230,6 +230,7 @@ s3Name s = Name s (Just "http://s3.amazonaws.com/doc/2006-03-01/") Nothing
data MErrV = MErrVSinglePUTSizeExceeded Int64 data MErrV = MErrVSinglePUTSizeExceeded Int64
| MErrVPutSizeExceeded Int64 | MErrVPutSizeExceeded Int64
| MErrVETagHeaderNotFound | MErrVETagHeaderNotFound
| MErrVInvalidObjectInfoResponse
deriving (Show, Eq) deriving (Show, Eq)
-- | Errors thrown by the library -- | Errors thrown by the library

View File

@ -13,6 +13,7 @@ module Network.Minio.S3API
-- * Retrieving objects -- * Retrieving objects
----------------------- -----------------------
, getObject' , getObject'
, headObject
-- * Creating buckets and objects -- * Creating buckets and objects
--------------------------------- ---------------------------------
@ -246,3 +247,20 @@ listIncompleteParts' bucket object uploadId maxParts partNumMarker = do
, ("part-number-marker", partNumMarker) , ("part-number-marker", partNumMarker)
, ("max-parts", maxParts) , ("max-parts", maxParts)
] ]
-- | Get metadata of an object.
headObject :: Bucket -> Object -> Minio ObjectInfo
headObject bucket object = do
resp <- executeRequest $ def { riMethod = HT.methodHead
, riBucket = Just bucket
, riObject = Just object
}
let
headers = NC.responseHeaders resp
modTime = getLastModifiedHeader headers
etag = getETagHeader headers
size = getContentLength headers
maybe (throwM $ ValidationError MErrVInvalidObjectInfoResponse) return $
ObjectInfo <$> Just object <*> modTime <*> etag <*> size

View File

@ -9,17 +9,25 @@ import qualified Control.Monad.Trans.Resource as R
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.Conduit as C import qualified Data.Conduit as C
import qualified Data.Text as T
import Data.Text.Encoding.Error (lenientDecode) import Data.Text.Encoding.Error (lenientDecode)
import Data.Text.Read (decimal)
import Data.Time
import qualified Network.HTTP.Client as NClient import qualified Network.HTTP.Client as NClient
import Network.HTTP.Conduit (Response) import Network.HTTP.Conduit (Response)
import qualified Network.HTTP.Conduit as NC import qualified Network.HTTP.Conduit as NC
import qualified Network.HTTP.Types as HT import qualified Network.HTTP.Types as HT
import qualified Network.HTTP.Types.Header as Hdr
import qualified System.IO as IO import qualified System.IO as IO
import Lib.Prelude import Lib.Prelude
import Network.Minio.Data import Network.Minio.Data
-- | Represent the time format string returned by S3 API calls.
s3TimeFormat :: [Char]
s3TimeFormat = iso8601DateFormat $ Just "%T%QZ"
allocateReadFile :: (R.MonadResource m, R.MonadResourceBase m) allocateReadFile :: (R.MonadResource m, R.MonadResourceBase m)
=> FilePath -> m (R.ReleaseKey, Handle) => FilePath -> m (R.ReleaseKey, Handle)
allocateReadFile fp = do allocateReadFile fp = do
@ -72,7 +80,18 @@ lookupHeader :: HT.HeaderName -> [HT.Header] -> Maybe ByteString
lookupHeader hdr = headMay . map snd . filter (\(h, _) -> h == hdr) lookupHeader hdr = headMay . map snd . filter (\(h, _) -> h == hdr)
getETagHeader :: [HT.Header] -> Maybe Text getETagHeader :: [HT.Header] -> Maybe Text
getETagHeader hs = decodeUtf8Lenient <$> lookupHeader "ETag" hs getETagHeader hs = decodeUtf8Lenient <$> lookupHeader Hdr.hETag hs
getLastModifiedHeader :: [HT.Header] -> Maybe UTCTime
getLastModifiedHeader hs = do
modTimebs <- decodeUtf8Lenient <$> lookupHeader Hdr.hLastModified hs
parseTimeM True defaultTimeLocale rfc822DateFormat (T.unpack modTimebs)
getContentLength :: [HT.Header] -> Maybe Int64
getContentLength hs = do
nbs <- decodeUtf8Lenient <$> lookupHeader Hdr.hContentLength hs
fst <$> hush (decimal nbs)
decodeUtf8Lenient :: ByteString -> Text decodeUtf8Lenient :: ByteString -> Text
decodeUtf8Lenient = decodeUtf8With lenientDecode decodeUtf8Lenient = decodeUtf8With lenientDecode

View File

@ -19,6 +19,7 @@ import Text.XML.Cursor
import Lib.Prelude import Lib.Prelude
import Network.Minio.Data import Network.Minio.Data
import Network.Minio.Utils (s3TimeFormat)
-- | Helper functions. -- | Helper functions.
@ -28,19 +29,17 @@ uncurry3 f (a, b, c) = f a b c
uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e
uncurry4 f (a, b, c, d) = f a b c d uncurry4 f (a, b, c, d) = f a b c d
-- | Represent the time format string returned by S3 API calls.
s3TimeFormat :: [Char]
s3TimeFormat = iso8601DateFormat $ Just "%T%QZ"
-- | Parse time strings from XML -- | Parse time strings from XML
parseS3XMLTime :: (MonadThrow m) => Text -> m UTCTime parseS3XMLTime :: (MonadThrow m) => Text -> m UTCTime
parseS3XMLTime = either (throwM . XMLParseError) return parseS3XMLTime = either (throwM . XMLParseError) return
. parseTimeM True defaultTimeLocale s3TimeFormat . parseTimeM True defaultTimeLocale s3TimeFormat
. T.unpack . T.unpack
parseDecimal :: (MonadThrow m, Integral a) => Text -> m a
parseDecimal numStr = either (throwM . XMLParseError . show) return $ fst <$> decimal numStr
parseDecimals :: (MonadThrow m, Integral a) => [Text] -> m [a] parseDecimals :: (MonadThrow m, Integral a) => [Text] -> m [a]
parseDecimals numStr = forM numStr $ \str -> parseDecimals numStr = forM numStr parseDecimal
either (throwM . XMLParseError . show) return $ fst <$> decimal str
s3Elem :: Text -> Axis s3Elem :: Text -> Axis
s3Elem = element . s3Name s3Elem = element . s3Name

View File

@ -300,6 +300,21 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
incompleteParts <- (listIncompleteParts bucket object uid) $$ sinkList incompleteParts <- (listIncompleteParts bucket object uid) $$ sinkList
liftIO $ (length incompleteParts) @?= 10 liftIO $ (length incompleteParts) @?= 10
, funTestWithBucket "High-level statObject Test" $ \step bucket -> do
let
object = "sample"
zeroByte = 0
step "create an object"
inputFile <- mkRandFile zeroByte
fPutObject bucket object inputFile
step "get metadata of the object"
res <- statObject bucket object
liftIO $ (oiSize res) @?= 0
step "delete object"
deleteObject bucket object
] ]
unitTests :: TestTree unitTests :: TestTree