gogol-0.0.1: src/Network/Google.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
-- |
-- Module : Network.Google
-- Copyright : (c) 2015 Brendan Hay
-- License : Mozilla Public License, v. 2.0.
-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
-- Stability : provisional
-- Portability : non-portable (GHC extensions)
--
-- This module provides a simple 'AWS' monad and a set of operations which
-- can be performed against remote Google Service APIs, for use with the types
-- supplied by the various @gogol-*@ libraries.
--
-- A 'MonadGoogle' typeclass is used as a function constraint to provide automatic
-- lifting of functions when embedding 'Google' as a layer inside your own
-- application stack.
module Network.Google
(
-- * Running Google Actions
Google
, MonadGoogle (..)
, runGoogle
, runResourceT
-- * Authentication and Environment
, newEnv
, Env
, HasEnv (..)
-- ** Credential Discovery
, Credentials (..)
-- * Sending Requests
, send
-- ** Media Downloads
, download
-- ** Media Uploads
, upload
, ToBody (..)
, RequestBody
, requestBodySource
, requestBodySourceChunked
-- ** Service Configuration
-- ** Overriding Defaults
, configure
, override
-- *** Scoped Actions
, reconfigure
, timeout
-- * Running Asynchronous Actions
-- $async
-- * Handling Errors
, AsError (..)
, AsAuthError (..)
, trying
, catching
-- * Logging
-- $logging
, Logger
, LogLevel (..)
-- ** Constructing a Logger
, newLogger
-- * Re-exported Types
, Proxy (..)
, OctetStream
, PlainText
, JSON
, module Network.Google.Types
) where
import Control.Applicative
import Control.Exception.Lens
import Control.Monad
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Reader
import qualified Control.Monad.RWS.Lazy as LRW
import qualified Control.Monad.RWS.Strict as RW
import qualified Control.Monad.State.Lazy as LS
import qualified Control.Monad.State.Strict as S
import Control.Monad.Trans.Control
import Control.Monad.Trans.Except (ExceptT)
import Control.Monad.Trans.Identity (IdentityT)
import Control.Monad.Trans.List (ListT)
import Control.Monad.Trans.Maybe (MaybeT)
import Control.Monad.Trans.Resource
import qualified Control.Monad.Writer.Lazy as LW
import qualified Control.Monad.Writer.Strict as W
import Network.Google.Auth
import Network.Google.Env
import Network.Google.Internal.HTTP
import Network.Google.Internal.Logger
import Network.Google.Prelude
import Network.Google.Types
import Network.HTTP.Conduit (requestBodySource,
requestBodySourceChunked)
newtype Google a = Google { unGoogle :: ReaderT Env (ResourceT IO) a }
deriving
( Functor
, Applicative
, Alternative
, Monad
, MonadPlus
, MonadIO
, MonadThrow
, MonadCatch
, MonadMask
, MonadBase IO
, MonadReader Env
, MonadResource
)
instance MonadBaseControl IO Google where
type StM Google a = StM (ReaderT Env (ResourceT IO)) a
liftBaseWith f = Google . liftBaseWith $ \g -> f (g . unGoogle)
restoreM = Google . restoreM
-- | Monads in which 'Google' actions may be embedded.
class ( Functor m
, Applicative m
, Monad m
, MonadIO m
, MonadCatch m
) => MonadGoogle m where
-- | Lift a computation to the 'Google' monad.
liftGoogle :: Google a -> m a
instance MonadGoogle Google where
liftGoogle = id
instance MonadGoogle m => MonadGoogle (IdentityT m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (ListT m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (MaybeT m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (ExceptT e m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (ReaderT r m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (S.StateT s m) where liftGoogle = lift . liftGoogle
instance MonadGoogle m => MonadGoogle (LS.StateT s m) where liftGoogle = lift . liftGoogle
instance (Monoid w, MonadGoogle m) => MonadGoogle (W.WriterT w m) where
liftGoogle = lift . liftGoogle
instance (Monoid w, MonadGoogle m) => MonadGoogle (LW.WriterT w m) where
liftGoogle = lift . liftGoogle
instance (Monoid w, MonadGoogle m) => MonadGoogle (RW.RWST r w s m) where
liftGoogle = lift . liftGoogle
instance (Monoid w, MonadGoogle m) => MonadGoogle (LRW.RWST r w s m) where
liftGoogle = lift . liftGoogle
-- | Run a 'Google' aciton using the specified environment.
runGoogle :: (MonadResource m, HasEnv r) => r -> Google a -> m a
runGoogle e m = liftResourceT $ runReaderT (unGoogle m) (e ^. environment)
-- | Send a request, returning the associated response if successful.
--
-- Throws 'Error'.
send :: (MonadGoogle m, GoogleRequest a) => a -> m (Rs a)
send x = liftGoogle $ do
e <- ask
r <- perform e x
hoistError r
-- | Send a request returning the associated streaming media response if successful.
--
-- Some request data types have two possible responses, the JSON metadata and
-- a streaming media response. Use 'send' to retrieve the metadata and 'download'
-- to retrieve the streaming media.
--
-- Throws 'Error'.
download :: (MonadGoogle m, GoogleRequest (MediaDownload a))
=> a
-> m (Rs (MediaDownload a))
download = send . MediaDownload
-- | Send a request with an attached multipart/related media upload.
--
-- Throws 'Error'.
upload :: (MonadGoogle m, GoogleRequest (MediaUpload a))
=> a
-> RequestBody
-> m (Rs (MediaUpload a))
upload x = send . MediaUpload x
hoistError :: MonadThrow m => Either Error a -> m a
hoistError = either (throwingM _Error) return
{- $async
Requests can be sent asynchronously, but due to guarantees about resource closure
require the use of <http://hackage.haskell.org/package/lifted-async lifted-async>.
-}
{- $logging
The exposed logging interface is a primitive 'Logger' function which gets
threaded through service calls and serialisation routines. This allows the
library to output useful information and diagnostics.
The 'newLogger' function can be used to construct a simple logger which writes
output to a 'Handle', but in most production code you should probably consider
using a more robust logging library such as
<http://hackage.haskell.org/package/tiny-log tiny-log> or
<http://hackage.haskell.org/package/fast-logger fast-logger>.
-}