{-# LANGUAGE FlexibleContexts #-} module Network.Salvia.Handler.Error ( hError , hCustomError , hIOError , hSafeIO , catchIO ) where import Control.Monad.Trans import Data.Record.Label import Network.Protocol.Http import Network.Salvia.Interface import System.IO.Error -- | The 'hError' handler enables the creation of a default style of error -- responses for the specified HTTP `Status` code. hError :: (HttpM Response m, SendM m) => Status -> m () hError e = hCustomError e (concat ["[", show (codeFromStatus e), "] ", show e, "\n"]) -- | Like `hError` but with a custom error message. hCustomError :: (HttpM Response m, SendM m) => Status -> String -> m () hCustomError e m = do response $ do status =: e contentLength =: Just (length m) contentType =: Just ("text/plain", Nothing) send m {- | Map an `IOError` to a default style error response. The mapping from an IO error to an error response is rather straightforward: > | isDoesNotExistError e = hError NotFound > | isAlreadyInUseError e = hError ServiceUnavailable > | isPermissionError e = hError Forbidden > | True = hError InternalServerError -} hIOError :: (HttpM Response m, SendM m) => IOError -> m () hIOError e | isDoesNotExistError e = hError NotFound | isAlreadyInUseError e = hError ServiceUnavailable | isPermissionError e = hError Forbidden | otherwise = hError InternalServerError -- | Execute an handler with the result of an IO action. When the IO actions -- fails a default error handler will be executed. hSafeIO :: (MonadIO m, HttpM Response m, SendM m) => IO a -> (a -> m ()) -> m () hSafeIO io h = liftIO (try io) >>= either hIOError h -- | Utility function to easily catch IO errors. catchIO :: MonadIO m => IO a -> a -> m a catchIO a b = liftIO (a `catch` (const (return b)))