Add listObjects s3api.
This commit is contained in:
parent
06214c1cae
commit
72f824dd31
@ -1,26 +1,5 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}
|
||||||
module Network.Minio.Data
|
module Network.Minio.Data where
|
||||||
( ConnectInfo(..)
|
|
||||||
, RequestInfo(..)
|
|
||||||
, MinioConn(..)
|
|
||||||
, Bucket
|
|
||||||
, Object
|
|
||||||
, Region
|
|
||||||
, BucketInfo(..)
|
|
||||||
, PartNumber
|
|
||||||
, UploadId
|
|
||||||
, ETag
|
|
||||||
, PartInfo(..)
|
|
||||||
, getPathFromRI
|
|
||||||
, getRegionFromRI
|
|
||||||
, Minio
|
|
||||||
, MinioErr(..)
|
|
||||||
, MErrV(..)
|
|
||||||
, runMinio
|
|
||||||
, connect
|
|
||||||
, Payload(..)
|
|
||||||
, s3Name
|
|
||||||
) where
|
|
||||||
|
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import Network.HTTP.Client (defaultManagerSettings, HttpException)
|
import Network.HTTP.Client (defaultManagerSettings, HttpException)
|
||||||
@ -87,6 +66,21 @@ data PartInfo = PartInfo PartNumber ETag
|
|||||||
instance Ord PartInfo where
|
instance Ord PartInfo where
|
||||||
(PartInfo a _) `compare` (PartInfo b _) = a `compare` b
|
(PartInfo a _) `compare` (PartInfo b _) = a `compare` b
|
||||||
|
|
||||||
|
|
||||||
|
data ListObjectsResult = ListObjectsResult {
|
||||||
|
lorHasMore :: Bool
|
||||||
|
, lorNextToken :: Maybe Text
|
||||||
|
, lorObjects :: [ObjectInfo]
|
||||||
|
, lorCPrefixes :: [Text]
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
data ObjectInfo = ObjectInfo {
|
||||||
|
oiObject :: Object
|
||||||
|
, oiModTime :: UTCTime
|
||||||
|
, oiETag :: ETag
|
||||||
|
, oiSize :: Int64
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
data Payload = PayloadBS ByteString
|
data Payload = PayloadBS ByteString
|
||||||
| PayloadH Handle
|
| PayloadH Handle
|
||||||
Int64 -- offset
|
Int64 -- offset
|
||||||
|
|||||||
@ -6,6 +6,9 @@ module Network.Minio.S3API
|
|||||||
--------------------
|
--------------------
|
||||||
, getService
|
, getService
|
||||||
|
|
||||||
|
-- * Listing objects
|
||||||
|
--------------------
|
||||||
|
, listObjects
|
||||||
|
|
||||||
-- * Retrieving objects
|
-- * Retrieving objects
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -101,6 +104,25 @@ putObject bucket object headers h offset size = do
|
|||||||
, riPayload = PayloadH h offset size
|
, riPayload = PayloadH h offset size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listObjects :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text
|
||||||
|
-> Minio ListObjectsResult
|
||||||
|
listObjects bucket prefix nextToken delimiter = do
|
||||||
|
resp <- executeRequest $ def { riMethod = HT.methodGet
|
||||||
|
, riBucket = Just bucket
|
||||||
|
, riQueryParams = ("list-type", Just "2") : qp
|
||||||
|
}
|
||||||
|
parseListObjectsResponse $ NC.responseBody resp
|
||||||
|
where
|
||||||
|
-- build optional query params
|
||||||
|
ctokList = map ((\k -> ("continuation_token", k)) . Just . encodeUtf8) $
|
||||||
|
maybeToList nextToken
|
||||||
|
prefixList = map ((\k -> ("prefix", k)) . Just . encodeUtf8) $
|
||||||
|
maybeToList prefix
|
||||||
|
delimList = map ((\k -> ("delimiter", k)) . Just . encodeUtf8) $
|
||||||
|
maybeToList delimiter
|
||||||
|
qp = concat [ctokList, prefixList, delimList]
|
||||||
|
|
||||||
|
|
||||||
-- | DELETE a bucket from the service.
|
-- | DELETE a bucket from the service.
|
||||||
deleteBucket :: Bucket -> Minio ()
|
deleteBucket :: Bucket -> Minio ()
|
||||||
deleteBucket bucket = do
|
deleteBucket bucket = do
|
||||||
|
|||||||
@ -3,12 +3,15 @@ module Network.Minio.XmlParser
|
|||||||
, parseLocation
|
, parseLocation
|
||||||
, parseNewMultipartUpload
|
, parseNewMultipartUpload
|
||||||
, parseCompleteMultipartUploadResponse
|
, parseCompleteMultipartUploadResponse
|
||||||
|
, parseListObjectsResponse
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Text.XML
|
import Text.XML
|
||||||
import Text.XML.Cursor
|
import Text.XML.Cursor
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time
|
import Data.Time
|
||||||
|
import Data.Text.Read (decimal)
|
||||||
|
import Data.List (zip4)
|
||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
|
|
||||||
@ -53,3 +56,50 @@ parseCompleteMultipartUploadResponse xmldata = do
|
|||||||
doc <- either (throwError . MErrXml . show) return $ parseLBS def xmldata
|
doc <- either (throwError . MErrXml . show) return $ parseLBS def xmldata
|
||||||
return $ T.concat $ fromDocument doc
|
return $ T.concat $ fromDocument doc
|
||||||
$// element (s3Name "ETag") &/ content
|
$// element (s3Name "ETag") &/ content
|
||||||
|
|
||||||
|
parseListObjectsResponse :: (MonadError MinioErr m)
|
||||||
|
=> LByteString -> m ListObjectsResult
|
||||||
|
parseListObjectsResponse xmldata = do
|
||||||
|
doc <- either (throwError . MErrXml . show) return $ parseLBS def xmldata
|
||||||
|
|
||||||
|
let
|
||||||
|
root = fromDocument doc
|
||||||
|
s3Elem = element . s3Name
|
||||||
|
|
||||||
|
hasMore :: Bool
|
||||||
|
hasMore = "true" == (T.concat $ contentOfChildElem root "IsTruncated")
|
||||||
|
|
||||||
|
nextToken :: Maybe Text
|
||||||
|
nextToken = listToMaybe $ contentOfChildElem root "NextContinuationToken"
|
||||||
|
|
||||||
|
cPrefTags :: [Cursor]
|
||||||
|
cPrefTags = child root >>= element (s3Name "CommonPrefixes")
|
||||||
|
|
||||||
|
prefixes :: [Text]
|
||||||
|
prefixes = cPrefTags >>= flip contentOfChildElem "Prefix"
|
||||||
|
|
||||||
|
keys = root $/ s3Elem "Contents" &/ s3Elem "Key" &/ content
|
||||||
|
modTimeStr = root $/ s3Elem "Contents" &/ s3Elem "LastModified" &/ content
|
||||||
|
etags = root $/ s3Elem "Contents" &/ s3Elem "ETag" &/ content
|
||||||
|
sizeStr = root $/ s3Elem "Contents" &/ s3Elem "Size" &/ content
|
||||||
|
|
||||||
|
|
||||||
|
modTimes <- either (throwError . MErrXml) return $
|
||||||
|
mapM (parseTimeM True defaultTimeLocale s3TimeFormat . T.unpack) $
|
||||||
|
modTimeStr
|
||||||
|
|
||||||
|
sizes <- forM sizeStr $ \str ->
|
||||||
|
either (throwError . MErrXml . show) return $ fst <$> decimal str
|
||||||
|
|
||||||
|
let objects = map (uncurry4 ObjectInfo) $ zip4 keys modTimes etags sizes
|
||||||
|
return $ ListObjectsResult hasMore nextToken objects prefixes
|
||||||
|
|
||||||
|
where
|
||||||
|
uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e
|
||||||
|
uncurry4 f (a, b, c, d) = f a b c d
|
||||||
|
|
||||||
|
-- get content of children with given cursor and child-element name.
|
||||||
|
contentOfChildElem :: Cursor -> Text -> [Text]
|
||||||
|
contentOfChildElem cursor elemName = child cursor >>=
|
||||||
|
element (s3Name elemName) >>=
|
||||||
|
content
|
||||||
|
|||||||
20
test/Spec.hs
20
test/Spec.hs
@ -12,6 +12,7 @@ import Data.Default (Default(..))
|
|||||||
-- import Data.Conduit.Binary
|
-- import Data.Conduit.Binary
|
||||||
|
|
||||||
import Network.Minio
|
import Network.Minio
|
||||||
|
import Network.Minio.Data
|
||||||
import Network.Minio.S3API
|
import Network.Minio.S3API
|
||||||
import Network.Minio.XmlGenerator.Test
|
import Network.Minio.XmlGenerator.Test
|
||||||
import Network.Minio.XmlParser.Test
|
import Network.Minio.XmlParser.Test
|
||||||
@ -112,6 +113,25 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
|
|
||||||
step $ "Cleanup actions"
|
step $ "Cleanup actions"
|
||||||
deleteObject bucket object
|
deleteObject bucket object
|
||||||
|
|
||||||
|
, funTestWithBucket "Basic listObjects Test" "testbucket3" $ \step bucket -> do
|
||||||
|
step "put 10 objects"
|
||||||
|
forM_ [1..10] $ \s ->
|
||||||
|
fPutObject bucket (T.concat ["lsb-release", T.pack (show s)]) "/etc/lsb-release"
|
||||||
|
|
||||||
|
step "Simple list"
|
||||||
|
res <- listObjects bucket Nothing Nothing Nothing
|
||||||
|
let expected = sort $ map (T.concat .
|
||||||
|
("lsb-release":) .
|
||||||
|
(\x -> [x]) .
|
||||||
|
T.pack .
|
||||||
|
show) [1..10]
|
||||||
|
liftIO $ assertEqual "Objects match failed!" expected
|
||||||
|
(map oiObject $ lorObjects res)
|
||||||
|
|
||||||
|
step "cleanup"
|
||||||
|
forM_ [1..10] $ \s ->
|
||||||
|
deleteObject bucket (T.concat ["lsb-release", T.pack (show s)])
|
||||||
]
|
]
|
||||||
|
|
||||||
unitTests :: TestTree
|
unitTests :: TestTree
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user