{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Brok.IO.Http
( check
, mkManager
) where
import ClassyPrelude
import Control.Concurrent (threadDelay)
import Network.Connection (TLSSettings (TLSSettingsSimple))
import Network.HTTP.Client (HttpExceptionContent (InternalException), Manager, httpNoBody,
newManager)
import Network.HTTP.Client.TLS (mkManagerSettings)
import Network.HTTP.Simple (HttpException, HttpException (..), Request, addRequestHeader,
getResponseStatusCode, parseRequest, setRequestMethod)
import Brok.IO.CLI (replace)
import Brok.Types.Brok (Brok, appConfig, appTLSManager)
import Brok.Types.Config (interval)
import Brok.Types.Link
import Brok.Types.URL (URL)
type StatusCode = Either HttpException Int
mkManager :: Bool -> IO Manager
mkManager checkCerts = do
let tls = TLSSettingsSimple (not checkCerts) False False
let settings = mkManagerSettings tls Nothing
newManager settings
setHeaders :: Request -> Request
setHeaders = addRequestHeader "User-Agent" "smallhadroncollider/brok"
makeRequest :: ByteString -> URL -> Brok StatusCode
makeRequest method url = do
manager <- asks appTLSManager
delay <- interval <$> asks appConfig
lift . try $ do
request <- setHeaders . setRequestMethod method <$> parseRequest (unpack url)
threadDelay (fromIntegral delay * 1000)
getResponseStatusCode <$> httpNoBody request manager
tryWithGet :: URL -> StatusCode -> Brok StatusCode
tryWithGet url (Right code)
| code >= 400 = makeRequest "GET" url
| otherwise = pure (Right code)
tryWithGet url (Left (HttpExceptionRequest _ (InternalException _))) = makeRequest "GET" url
tryWithGet url (Left _) = makeRequest "GET" url
fetch :: URL -> Brok StatusCode
fetch url = replace ("Fetching: " <> url) >> makeRequest "HEAD" url >>= tryWithGet url
codeToResponse :: Link -> StatusCode -> Link
codeToResponse lnk (Right code)
| code >= 200 && code < 300 = working lnk code
| otherwise = broken lnk code
codeToResponse lnk (Left (HttpExceptionRequest _ _)) = failure lnk
codeToResponse lnk (Left (InvalidUrlException _ _)) = invalid lnk
check :: Link -> Brok Link
check lnk = codeToResponse lnk <$> fetch (getURL lnk)