{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-} -- | -- Module : Pinboard.Error -- Copyright : (c) Jon Schoning, 2015 -- Maintainer : jonschoning@gmail.com -- Stability : experimental -- Portability : POSIX module Pinboard.Error ( MonadErrorPinboard , defaultPinboardError , pinboardExceptionToEither , pinboardExceptionToMonadError , exceptionToMonadErrorPinboard , tryMonadError , eitherToMonadError , eitherToMonadThrow , PinboardErrorHTTPCode (..) , PinboardErrorType (..) , PinboardErrorCode (..) , PinboardError (..) ) where import Data.Text (Text, pack) import Data.Monoid import Prelude import Control.Exception.Safe import Control.Monad.Error.Class (MonadError, throwError) ------------------------------------------------------------------------------ data PinboardErrorHTTPCode = BadRequest -- ^ 400 | UnAuthorized -- ^ 401 | RequestFailed -- ^ 402 | Forbidden -- ^ 403 | NotFound -- ^ 404 | TooManyRequests -- ^ 429 | PinboardServerError -- ^ (>=500) | UnknownHTTPCode -- ^ All other codes deriving Show ------------------------------------------------------------------------------ data PinboardErrorType = ConnectionFailure | HttpStatusFailure | ParseFailure | UnknownErrorType deriving (Eq, Show) ------------------------------------------------------------------------------ data PinboardErrorCode = UnknownError deriving Show ------------------------------------------------------------------------------ data PinboardError = PinboardError { errorType :: PinboardErrorType , errorMsg :: !Text , errorCode :: Maybe PinboardErrorCode , errorParam :: Maybe Text , errorHTTP :: Maybe PinboardErrorHTTPCode } deriving Show instance Exception PinboardError type MonadErrorPinboard m = MonadError PinboardError m defaultPinboardError :: PinboardError defaultPinboardError = PinboardError UnknownErrorType mempty Nothing Nothing Nothing pinboardExceptionToEither :: MonadCatch m => m (Either PinboardError a) -> m (Either PinboardError a) pinboardExceptionToEither = handle (\(e::PinboardError) -> return (Left e)) tryMonadError :: (Exception e, MonadCatch m, MonadError e r) => m a -> m (r a) tryMonadError a = eitherToMonadError <$> try a pinboardExceptionToMonadError :: (MonadCatch m, MonadErrorPinboard e) => m (e a) -> m (e a) pinboardExceptionToMonadError = handle (\(e::PinboardError) -> return (throwError e)) exceptionToMonadErrorPinboard :: (MonadCatch m, MonadErrorPinboard e) => m (e a) -> m (e a) exceptionToMonadErrorPinboard = handle (\(e::SomeException) -> return $ throwError $ defaultPinboardError { errorMsg = (pack.show) e }) eitherToMonadError :: MonadError e m => Either e a -> m a eitherToMonadError = either throwError return eitherToMonadThrow :: (Exception e, MonadThrow m) => Either e a -> m a eitherToMonadThrow = either throw return