--
-- MinIO Haskell SDK, (C) 2017-2019 MinIO, Inc.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

-- |
-- Module:      Network.Minio
-- Copyright:   (c) 2017-2019 MinIO Dev Team
-- License:     Apache 2.0
-- Maintainer:  MinIO Dev Team <dev@min.io>
--
-- Types and functions to conveniently access S3 compatible object
-- storage servers like MinIO.
module Network.Minio
  ( -- * Credentials
    Credentials (..),

    -- ** Credential providers

    -- | Run actions that retrieve 'Credentials' from the environment or
    -- files or other custom sources.
    Provider,
    fromAWSConfigFile,
    fromAWSEnv,
    fromMinioEnv,
    findFirst,

    -- * Connecting to object storage
    ConnectInfo,
    setRegion,
    setCreds,
    setCredsFrom,
    isConnectInfoSecure,
    disableTLSCertValidation,
    MinioConn,
    mkMinioConn,

    -- ** Connection helpers

    -- | These are helpers to construct 'ConnectInfo' values for common
    -- cases.
    minioPlayCI,
    awsCI,
    gcsCI,

    -- * Minio Monad
    ----------------

    -- | The Minio Monad provides connection-reuse, bucket-location
    -- caching, resource management and simpler error handling
    -- functionality. All actions on object storage are performed within
    -- this Monad.
    Minio,
    runMinioWith,
    runMinio,
    runMinioResWith,
    runMinioRes,

    -- * Bucket Operations

    -- ** Creation, removal and querying
    Bucket,
    makeBucket,
    removeBucket,
    bucketExists,
    Region,
    getLocation,

    -- ** Listing buckets
    BucketInfo (..),
    listBuckets,

    -- ** Listing objects
    listObjects,
    listObjectsV1,
    ListItem (..),
    ObjectInfo,
    oiObject,
    oiModTime,
    oiETag,
    oiSize,
    oiUserMetadata,
    oiMetadata,

    -- ** Listing incomplete uploads
    listIncompleteUploads,
    UploadId,
    UploadInfo (..),
    listIncompleteParts,
    ObjectPartInfo (..),

    -- ** Bucket Notifications
    getBucketNotification,
    putBucketNotification,
    removeAllBucketNotification,
    Notification (..),
    defaultNotification,
    NotificationConfig (..),
    Arn,
    Event (..),
    Filter (..),
    defaultFilter,
    FilterKey (..),
    defaultFilterKey,
    FilterRules (..),
    defaultFilterRules,
    FilterRule (..),

    -- * Object Operations
    Object,

    -- ** File-based operations
    fGetObject,
    fPutObject,

    -- ** Conduit-based streaming operations
    putObject,
    PutObjectOptions,
    defaultPutObjectOptions,
    pooContentType,
    pooContentEncoding,
    pooContentDisposition,
    pooContentLanguage,
    pooCacheControl,
    pooStorageClass,
    pooUserMetadata,
    pooNumThreads,
    pooSSE,
    getObject,
    GetObjectOptions,
    defaultGetObjectOptions,
    gooRange,
    gooIfMatch,
    gooIfNoneMatch,
    gooIfModifiedSince,
    gooIfUnmodifiedSince,
    gooSSECKey,
    GetObjectResponse,
    gorObjectInfo,
    gorObjectStream,

    -- ** Server-side object copying
    copyObject,
    SourceInfo,
    defaultSourceInfo,
    srcBucket,
    srcObject,
    srcRange,
    srcIfMatch,
    srcIfNoneMatch,
    srcIfModifiedSince,
    srcIfUnmodifiedSince,
    DestinationInfo,
    defaultDestinationInfo,
    dstBucket,
    dstObject,

    -- ** Querying object info
    statObject,

    -- ** Object removal operations
    removeObject,
    removeIncompleteUpload,

    -- ** Select Object Content with SQL
    module Network.Minio.SelectAPI,

    -- * Server-Side Encryption Helpers
    mkSSECKey,
    SSECKey,
    SSE (..),

    -- * Presigned Operations
    presignedPutObjectUrl,
    presignedGetObjectUrl,
    presignedHeadObjectUrl,
    UrlExpiry,

    -- ** POST (browser) upload helpers

    -- | Please see
    -- https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
    -- for detailed information.
    newPostPolicy,
    presignedPostPolicy,
    showPostPolicy,
    PostPolicy,
    PostPolicyError (..),

    -- *** Post Policy condition helpers
    PostPolicyCondition,
    ppCondBucket,
    ppCondContentLengthRange,
    ppCondContentType,
    ppCondKey,
    ppCondKeyStartsWith,
    ppCondSuccessActionStatus,

    -- * Error handling

    -- | Data types representing various errors that may occur while
    -- working with an object storage service.
    MinioErr (..),
    MErrV (..),
    ServiceErr (..),
  )
where

{-
This module exports the high-level MinIO API for object storage.
-}

import qualified Data.Conduit as C
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.Combinators as CC
import Lib.Prelude
import Network.Minio.CopyObject
import Network.Minio.Data
import Network.Minio.Errors
import Network.Minio.ListOps
import Network.Minio.PutObject
import Network.Minio.S3API
import Network.Minio.SelectAPI
import Network.Minio.Utils

-- | Lists buckets.
listBuckets :: Minio [BucketInfo]
listBuckets = getService

-- | Fetch the object and write it to the given file safely. The
-- object is first written to a temporary file in the same directory
-- and then moved to the given path.
fGetObject :: Bucket -> Object -> FilePath -> GetObjectOptions -> Minio ()
fGetObject bucket object fp opts = do
  src <- getObject bucket object opts
  C.connect (gorObjectStream src) $ CB.sinkFileCautious fp

-- | Upload the given file to the given object.
fPutObject ::
  Bucket ->
  Object ->
  FilePath ->
  PutObjectOptions ->
  Minio ()
fPutObject bucket object f opts =
  void $ putObjectInternal bucket object opts $ ODFile f Nothing

-- | Put an object from a conduit source. The size can be provided if
-- known; this helps the library select optimal part sizes to perform
-- a multipart upload. If not specified, it is assumed that the object
-- can be potentially 5TiB and selects multipart sizes appropriately.
putObject ::
  Bucket ->
  Object ->
  C.ConduitM () ByteString Minio () ->
  Maybe Int64 ->
  PutObjectOptions ->
  Minio ()
putObject bucket object src sizeMay opts =
  void $ putObjectInternal bucket object opts $ ODStream src sizeMay

-- | Perform a server-side copy operation to create an object based on
-- the destination specification in DestinationInfo from the source
-- specification in SourceInfo. This function performs a multipart
-- copy operation if the new object is to be greater than 5GiB in
-- size.
copyObject :: DestinationInfo -> SourceInfo -> Minio ()
copyObject dstInfo srcInfo =
  void $
    copyObjectInternal
      (dstBucket dstInfo)
      (dstObject dstInfo)
      srcInfo

-- | Remove an object from the object store.
removeObject :: Bucket -> Object -> Minio ()
removeObject = deleteObject

-- | Get an object from the object store.
getObject ::
  Bucket ->
  Object ->
  GetObjectOptions ->
  Minio GetObjectResponse
getObject bucket object opts =
  getObject' bucket object [] $ gooToHeaders opts

-- | Get an object's metadata from the object store. It accepts the
-- same options as GetObject.
statObject :: Bucket -> Object -> GetObjectOptions -> Minio ObjectInfo
statObject b o opts = headObject b o $ gooToHeaders opts

-- | Creates a new bucket in the object store. The Region can be
-- optionally specified. If not specified, it will use the region
-- configured in ConnectInfo, which is by default, the US Standard
-- Region.
makeBucket :: Bucket -> Maybe Region -> Minio ()
makeBucket bucket regionMay = do
  region <- maybe (asks $ connectRegion . mcConnInfo) return regionMay
  putBucket bucket region
  addToRegionCache bucket region

-- | Removes a bucket from the object store.
removeBucket :: Bucket -> Minio ()
removeBucket bucket = do
  deleteBucket bucket
  deleteFromRegionCache bucket

-- | Query the object store if a given bucket is present.
bucketExists :: Bucket -> Minio Bool
bucketExists = headBucket

-- | Removes an ongoing multipart upload of an object.
removeIncompleteUpload :: Bucket -> Object -> Minio ()
removeIncompleteUpload bucket object = do
  uploads <-
    C.runConduit $
      listIncompleteUploads bucket (Just object) False
        C..| CC.sinkList
  mapM_ (abortMultipartUpload bucket object) (uiUploadId <$> uploads)