172 lines
4.7 KiB
Haskell
172 lines
4.7 KiB
Haskell
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}
|
|
module Network.Minio.Data where
|
|
|
|
import qualified Data.ByteString as B
|
|
import Network.HTTP.Client (defaultManagerSettings, HttpException)
|
|
import Network.HTTP.Types (Method, Header, Query)
|
|
import qualified Network.HTTP.Conduit as NC
|
|
import Data.Default (Default(..))
|
|
import qualified Network.HTTP.Types as HT
|
|
|
|
import Control.Monad.Trans.Resource
|
|
import Control.Monad.Trans.Control
|
|
import Control.Monad.Base
|
|
|
|
import Text.XML
|
|
|
|
import Lib.Prelude
|
|
|
|
-- | Connection Info data type. Use the Default instance to create
|
|
-- connection info for your service.
|
|
data ConnectInfo = ConnectInfo {
|
|
connectHost :: Text
|
|
, connectPort :: Int
|
|
, connectAccessKey :: Text
|
|
, connectSecretKey :: Text
|
|
, connectIsSecure :: Bool
|
|
} deriving (Eq, Show)
|
|
|
|
instance Default ConnectInfo where
|
|
def = ConnectInfo "localhost" 9000 "minio" "minio123" False
|
|
|
|
-- |
|
|
-- Represents a bucket in the object store
|
|
type Bucket = Text
|
|
|
|
-- |
|
|
-- Represents an object name
|
|
type Object = Text
|
|
|
|
-- |
|
|
-- Represents a region
|
|
-- TODO: This could be a Sum Type with all defined regions for AWS.
|
|
type Region = Text
|
|
|
|
-- | A type alias to represent an Entity-Tag returned by S3-compatible
|
|
-- APIs.
|
|
type ETag = Text
|
|
|
|
-- |
|
|
-- BucketInfo returned for list buckets call
|
|
data BucketInfo = BucketInfo {
|
|
biName :: Bucket
|
|
, biCreationDate :: UTCTime
|
|
} deriving (Show, Eq)
|
|
|
|
-- | A type alias to represent a part-number for multipart upload
|
|
type PartNumber = Int16
|
|
|
|
-- | A type alias to represent an upload-id for multipart upload
|
|
type UploadId = Text
|
|
|
|
-- | A data-type to represent info about a part
|
|
data PartInfo = PartInfo PartNumber ETag
|
|
deriving (Show, Eq)
|
|
|
|
instance Ord PartInfo where
|
|
(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
|
|
| PayloadH Handle
|
|
Int64 -- offset
|
|
Int64 -- size
|
|
|
|
instance Default Payload where
|
|
def = PayloadBS ""
|
|
|
|
data RequestInfo = RequestInfo {
|
|
riMethod :: Method
|
|
, riBucket :: Maybe Bucket
|
|
, riObject :: Maybe Object
|
|
, riQueryParams :: Query
|
|
, riHeaders :: [Header]
|
|
, riPayload :: Payload
|
|
, riPayloadHash :: ByteString
|
|
, riRegion :: Maybe Region
|
|
}
|
|
|
|
instance Default RequestInfo where
|
|
def = RequestInfo HT.methodGet def def def def def "" def
|
|
|
|
getPathFromRI :: RequestInfo -> ByteString
|
|
getPathFromRI ri = B.concat $ parts
|
|
where
|
|
objPart = maybe [] (\o -> ["/", encodeUtf8 o]) $ riObject ri
|
|
parts = maybe ["/"] (\b -> "/" : encodeUtf8 b : objPart) $ riBucket ri
|
|
|
|
getRegionFromRI :: RequestInfo -> Text
|
|
getRegionFromRI ri = maybe "us-east-1" identity (riRegion ri)
|
|
|
|
-- | Various validation errors
|
|
data MErrV = MErrVSinglePUTSizeExceeded Int64
|
|
| MErrVETagHeaderNotFound
|
|
deriving (Show)
|
|
|
|
-- |
|
|
-- Minio Error data type for various errors/exceptions caught and
|
|
-- returned.
|
|
data MinioErr = MErrMsg ByteString -- generic
|
|
| MErrHttp HttpException -- http exceptions
|
|
| MErrXml ByteString -- XML parsing/generation errors
|
|
| MErrService ByteString -- error response from service
|
|
| MErrValidation MErrV -- client-side validation errors
|
|
| MErrIO IOException -- exceptions while working with files
|
|
deriving (Show)
|
|
|
|
newtype Minio a = Minio {
|
|
unMinio :: ReaderT MinioConn (ExceptT MinioErr (ResourceT IO)) a
|
|
}
|
|
deriving (
|
|
Functor
|
|
, Applicative
|
|
, Monad
|
|
, MonadIO
|
|
, MonadReader MinioConn
|
|
, MonadError MinioErr
|
|
, MonadThrow
|
|
, MonadBase IO
|
|
, MonadResource
|
|
)
|
|
|
|
instance MonadBaseControl IO Minio where
|
|
type StM Minio a = Either MinioErr a
|
|
liftBaseWith f = Minio $ liftBaseWith $ \q -> f (q . unMinio)
|
|
restoreM = Minio . restoreM
|
|
|
|
-- | MinioConn holds connection info and a connection pool
|
|
data MinioConn = MinioConn {
|
|
mcConnInfo :: ConnectInfo
|
|
, mcConnManager :: NC.Manager
|
|
}
|
|
|
|
-- | Takes connection information and returns a connection object to
|
|
-- be passed to @runMinio
|
|
connect :: ConnectInfo -> IO MinioConn
|
|
connect ci = do
|
|
mgr <- NC.newManager defaultManagerSettings
|
|
return $ MinioConn ci mgr
|
|
|
|
-- | Run the Minio action and return the result or error.
|
|
runMinio :: ConnectInfo -> Minio a -> ResourceT IO (Either MinioErr a)
|
|
runMinio ci m = do
|
|
conn <- liftIO $ connect ci
|
|
runExceptT . flip runReaderT conn . unMinio $ m
|
|
|
|
s3Name :: Text -> Name
|
|
s3Name s = Name s (Just "http://s3.amazonaws.com/doc/2006-03-01/") Nothing
|