{-# LANGUAGE TypeApplications #-}
module DMQ.Handlers.TopLevel (toplevelExceptionHandler) where
import Control.Exception
import Control.Monad.Class.MonadAsync (ExceptionInLinkedThread (..))
import System.Environment
import System.Exit
import System.IO
import Ouroboros.Network.Diffusion qualified as Network
toplevelExceptionHandler :: IO a -> IO a
toplevelExceptionHandler :: forall a. IO a -> IO a
toplevelExceptionHandler IO a
prog = do
Handle -> BufferMode -> IO ()
hSetBuffering Handle
stderr BufferMode
LineBuffering
IO a -> [Handler a] -> IO a
forall a. IO a -> [Handler a] -> IO a
catches IO a
prog [
(SomeAsyncException -> IO a) -> Handler a
forall a e. Exception e => (e -> IO a) -> Handler a
Handler SomeAsyncException -> IO a
forall a. SomeAsyncException -> IO a
rethrowAsyncExceptions
, (ExitCode -> IO a) -> Handler a
forall a e. Exception e => (e -> IO a) -> Handler a
Handler ExitCode -> IO a
forall a. ExitCode -> IO a
rethrowExitCode
, (Failure -> IO a) -> Handler a
forall a e. Exception e => (e -> IO a) -> Handler a
Handler Failure -> IO a
forall a. Failure -> IO a
handleDiffusionError
, (SomeException -> IO a) -> Handler a
forall a e. Exception e => (e -> IO a) -> Handler a
Handler SomeException -> IO a
forall a. SomeException -> IO a
handleSomeException
]
where
rethrowAsyncExceptions :: SomeAsyncException -> IO a
rethrowAsyncExceptions :: forall a. SomeAsyncException -> IO a
rethrowAsyncExceptions full :: SomeAsyncException
full@(SomeAsyncException e
e) =
case SomeException -> Maybe ExceptionInLinkedThread
forall e. Exception e => SomeException -> Maybe e
fromException (e -> SomeException
forall e. Exception e => e -> SomeException
toException e
e) of
Just (ExceptionInLinkedThread String
_ SomeException
eInner)
| Just ExitCode
ExitSuccess <- SomeException -> Maybe ExitCode
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
eInner
-> ExitCode -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ExitCode
ExitSuccess
Maybe ExceptionInLinkedThread
_ -> SomeAsyncException -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeAsyncException
full
rethrowExitCode :: ExitCode -> IO a
rethrowExitCode :: forall a. ExitCode -> IO a
rethrowExitCode = ExitCode -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO
handleDiffusionError :: Network.Failure -> IO a
handleDiffusionError :: forall a. Failure -> IO a
handleDiffusionError Failure
full =
case Failure
full of
Network.DiffusionError SomeException
e
| Just SomeAsyncException
e' <- forall e. Exception e => SomeException -> Maybe e
fromException @SomeAsyncException SomeException
e
-> SomeAsyncException -> IO a
forall a. SomeAsyncException -> IO a
rethrowAsyncExceptions SomeAsyncException
e'
| Just ExitCode
e' <- forall e. Exception e => SomeException -> Maybe e
fromException @ExitCode SomeException
e
-> ExitCode -> IO a
forall a. ExitCode -> IO a
rethrowExitCode ExitCode
e'
Failure
_ -> Failure -> IO a
forall e a. Exception e => e -> IO a
handleException Failure
full
handleSomeException :: SomeException -> IO a
handleSomeException :: forall a. SomeException -> IO a
handleSomeException = SomeException -> IO a
forall e a. Exception e => e -> IO a
handleException
handleException :: Exception e => e -> IO a
handleException :: forall e a. Exception e => e -> IO a
handleException e
e = do
Handle -> IO ()
hFlush Handle
stdout
progname <- IO String
getProgName
hPutStr stderr (renderException progname e)
throwIO (ExitFailure 1)
renderException :: Exception e => String -> e -> String
renderException :: forall e. Exception e => String -> e -> String
renderException String
progname e
e
| String
showOutput String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
displayOutput
= String
showOutput String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
progname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
displayOutput
| Bool
otherwise
= String
"\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
progname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
showOutput
where
showOutput :: String
showOutput = e -> String
forall a. Show a => a -> String
show e
e
displayOutput :: String
displayOutput = e -> String
forall e. Exception e => e -> String
displayException e
e