minio-hs/src/Network/Minio/Data.hs
2017-02-13 16:03:42 +05:30

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