-- | servant-client utilities
module Unison.Cli.ServantClientUtils
  ( ConnectionError (..),
    classifyConnectionError,
  )
where

import Control.Exception (fromException)
import Network.HTTP.Client qualified as HttpClient
import System.IO.Error (isDoesNotExistError)
import Unison.Prelude

data ConnectionError
  = ConnectionError'Offline
  | ConnectionError'SomethingElse HttpClient.HttpExceptionContent
  | ConnectionError'SomethingEntirelyUnexpected SomeException

-- | Given a 'SomeException' from a @servant-client@ 'ClientError', attempt to classify what happened.
classifyConnectionError :: SomeException -> ConnectionError
classifyConnectionError :: SomeException -> ConnectionError
classifyConnectionError SomeException
exception0 =
  case SomeException -> Maybe HttpException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
exception0 of
    Just (HttpClient.HttpExceptionRequest Request
_request HttpExceptionContent
content) ->
      ConnectionError -> Maybe ConnectionError -> ConnectionError
forall a. a -> Maybe a -> a
fromMaybe (HttpExceptionContent -> ConnectionError
ConnectionError'SomethingElse HttpExceptionContent
content) do
        case HttpExceptionContent
content of
          HttpClient.ConnectionFailure SomeException
exception1 -> do
            IOException
ioException <- forall e. Exception e => SomeException -> Maybe e
fromException @IOException SomeException
exception1
            if
              | -- This may not be 100% accurate... but if the initial `getAddrInfo` request fails it will indeed throw
                -- a "does not exist" error. It seems in order to *know* that `getAddrInfo` was the cause of this
                -- exception, we'd have to parse the `show` output, which is preposterous.
                IOException -> Bool
isDoesNotExistError IOException
ioException ->
                  ConnectionError -> Maybe ConnectionError
forall a. a -> Maybe a
Just ConnectionError
ConnectionError'Offline
              | Bool
otherwise -> Maybe ConnectionError
forall a. Maybe a
Nothing
          HttpExceptionContent
_ -> Maybe ConnectionError
forall a. Maybe a
Nothing
    Maybe HttpException
_ -> SomeException -> ConnectionError
ConnectionError'SomethingEntirelyUnexpected SomeException
exception0