{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- |
-- Module      : Network.DO.Spaces.Actions.GetObject
-- Copyright   : (c) 2021 Rory Tyler Hayford
-- License     : BSD-3-Clause
-- Maintainer  : rory.hayford@protonmail.com
-- Stability   : experimental
-- Portability : GHC
--
module Network.DO.Spaces.Actions.GetObject
    ( GetObject(..)
    , GetObjectResponse(..)
    ) where

import           Conduit                 ( (.|), runConduit )

import           Control.Monad.Reader    ( MonadReader(ask) )

import qualified Data.ByteString.Lazy    as LB
import           Data.Conduit.Binary     ( sinkLbs )

import           GHC.Generics            ( Generic )

import           Network.DO.Spaces.Types
                 ( Action(..)
                 , Bucket
                 , MonadSpaces
                 , Object
                 , ObjectMetadata
                 , RawResponse(..)
                 , SpacesRequestBuilder(..)
                 )
import           Network.DO.Spaces.Utils ( lookupObjectMetadata )

-- | Retrieve an 'Object' along with its associated metadata. The object's data
-- is read into a lazy 'LB.ByteString'
data GetObject = GetObject { GetObject -> Bucket
bucket :: Bucket, GetObject -> Object
object :: Object }
    deriving ( Int -> GetObject -> ShowS
[GetObject] -> ShowS
GetObject -> String
(Int -> GetObject -> ShowS)
-> (GetObject -> String)
-> ([GetObject] -> ShowS)
-> Show GetObject
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GetObject] -> ShowS
$cshowList :: [GetObject] -> ShowS
show :: GetObject -> String
$cshow :: GetObject -> String
showsPrec :: Int -> GetObject -> ShowS
$cshowsPrec :: Int -> GetObject -> ShowS
Show, GetObject -> GetObject -> Bool
(GetObject -> GetObject -> Bool)
-> (GetObject -> GetObject -> Bool) -> Eq GetObject
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GetObject -> GetObject -> Bool
$c/= :: GetObject -> GetObject -> Bool
== :: GetObject -> GetObject -> Bool
$c== :: GetObject -> GetObject -> Bool
Eq, (forall x. GetObject -> Rep GetObject x)
-> (forall x. Rep GetObject x -> GetObject) -> Generic GetObject
forall x. Rep GetObject x -> GetObject
forall x. GetObject -> Rep GetObject x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep GetObject x -> GetObject
$cfrom :: forall x. GetObject -> Rep GetObject x
Generic )

data GetObjectResponse = GetObjectResponse
    { GetObjectResponse -> ObjectMetadata
objectMetadata :: ObjectMetadata, GetObjectResponse -> ByteString
objectData :: LB.ByteString }
    deriving ( Int -> GetObjectResponse -> ShowS
[GetObjectResponse] -> ShowS
GetObjectResponse -> String
(Int -> GetObjectResponse -> ShowS)
-> (GetObjectResponse -> String)
-> ([GetObjectResponse] -> ShowS)
-> Show GetObjectResponse
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GetObjectResponse] -> ShowS
$cshowList :: [GetObjectResponse] -> ShowS
show :: GetObjectResponse -> String
$cshow :: GetObjectResponse -> String
showsPrec :: Int -> GetObjectResponse -> ShowS
$cshowsPrec :: Int -> GetObjectResponse -> ShowS
Show, GetObjectResponse -> GetObjectResponse -> Bool
(GetObjectResponse -> GetObjectResponse -> Bool)
-> (GetObjectResponse -> GetObjectResponse -> Bool)
-> Eq GetObjectResponse
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GetObjectResponse -> GetObjectResponse -> Bool
$c/= :: GetObjectResponse -> GetObjectResponse -> Bool
== :: GetObjectResponse -> GetObjectResponse -> Bool
$c== :: GetObjectResponse -> GetObjectResponse -> Bool
Eq, (forall x. GetObjectResponse -> Rep GetObjectResponse x)
-> (forall x. Rep GetObjectResponse x -> GetObjectResponse)
-> Generic GetObjectResponse
forall x. Rep GetObjectResponse x -> GetObjectResponse
forall x. GetObjectResponse -> Rep GetObjectResponse x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep GetObjectResponse x -> GetObjectResponse
$cfrom :: forall x. GetObjectResponse -> Rep GetObjectResponse x
Generic )

instance MonadSpaces m => Action m GetObject where
    type ConsumedResponse GetObject = GetObjectResponse

    buildRequest :: GetObject -> m SpacesRequestBuilder
buildRequest GetObject { Object
Bucket
object :: Object
bucket :: Bucket
$sel:object:GetObject :: GetObject -> Object
$sel:bucket:GetObject :: GetObject -> Bucket
.. } = do
        Spaces
spaces <- m Spaces
forall r (m :: * -> *). MonadReader r m => m r
ask
        SpacesRequestBuilder -> m SpacesRequestBuilder
forall (m :: * -> *) a. Monad m => a -> m a
return SpacesRequestBuilder :: Spaces
-> Maybe RequestBody
-> Maybe Method
-> [Header]
-> Maybe Bucket
-> Maybe Object
-> Maybe Query
-> Maybe Query
-> Maybe Region
-> SpacesRequestBuilder
SpacesRequestBuilder
               { $sel:bucket:SpacesRequestBuilder :: Maybe Bucket
bucket         = Bucket -> Maybe Bucket
forall a. a -> Maybe a
Just Bucket
bucket
               , $sel:object:SpacesRequestBuilder :: Maybe Object
object         = Object -> Maybe Object
forall a. a -> Maybe a
Just Object
object
               , $sel:method:SpacesRequestBuilder :: Maybe Method
method         = Maybe Method
forall a. Maybe a
Nothing
               , $sel:body:SpacesRequestBuilder :: Maybe RequestBody
body           = Maybe RequestBody
forall a. Maybe a
Nothing
               , $sel:queryString:SpacesRequestBuilder :: Maybe Query
queryString    = Maybe Query
forall a. Maybe a
Nothing
               , $sel:subresources:SpacesRequestBuilder :: Maybe Query
subresources   = Maybe Query
forall a. Maybe a
Nothing
               , $sel:overrideRegion:SpacesRequestBuilder :: Maybe Region
overrideRegion = Maybe Region
forall a. Maybe a
Nothing
               , $sel:headers:SpacesRequestBuilder :: [Header]
headers        = [Header]
forall a. Monoid a => a
mempty
               , Spaces
$sel:spaces:SpacesRequestBuilder :: Spaces
spaces :: Spaces
..
               }

    consumeResponse :: RawResponse m -> m (ConsumedResponse GetObject)
consumeResponse raw :: RawResponse m
raw@RawResponse { [Header]
BodyBS m
$sel:body:RawResponse :: forall (m :: * -> *). RawResponse m -> BodyBS m
$sel:headers:RawResponse :: forall (m :: * -> *). RawResponse m -> [Header]
body :: BodyBS m
headers :: [Header]
.. } = ObjectMetadata -> ByteString -> GetObjectResponse
GetObjectResponse
        (ObjectMetadata -> ByteString -> GetObjectResponse)
-> m ObjectMetadata -> m (ByteString -> GetObjectResponse)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawResponse m -> m ObjectMetadata
forall (m :: * -> *).
MonadThrow m =>
RawResponse m -> m ObjectMetadata
lookupObjectMetadata RawResponse m
raw
        m (ByteString -> GetObjectResponse)
-> m ByteString -> m GetObjectResponse
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ConduitT () Void m ByteString -> m ByteString
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit (BodyBS m
body BodyBS m
-> ConduitM ByteString Void m ByteString
-> ConduitT () Void m ByteString
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
.| ConduitM ByteString Void m ByteString
forall (m :: * -> *) o.
Monad m =>
ConduitT ByteString o m ByteString
sinkLbs)