{-# LANGUAGE TemplateHaskell, OverloadedStrings, BangPatterns #-}
module NgxExport.Tools.Aggregate (
AggregateServerConf
,ngxExportAggregateService
,reportAggregate
,Foreign.C.Types.CInt (..)
,Foreign.C.Types.CUInt (..)
) where
import NgxExport.Tools
import Language.Haskell.TH
import Network.HTTP.Client
import Foreign.C.Types
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as L
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.IORef
import Data.Int
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Time.Clock.POSIX
import Data.Aeson
import Data.Maybe
import Control.Monad
import Control.Monad.IO.Class
import Control.Arrow
import Control.Exception
import Control.Exception.Enclosed (handleAny)
import System.IO.Unsafe
import Snap.Http.Server
import Snap.Core
type Aggregate a = IORef (CTime, Map Int32 (CTime, Maybe a))
data AggregateServerConf =
AggregateServerConf { AggregateServerConf -> Int
asPort :: Int
, AggregateServerConf -> TimeInterval
asPurgeInterval :: TimeInterval
} deriving ReadPrec [AggregateServerConf]
ReadPrec AggregateServerConf
Int -> ReadS AggregateServerConf
ReadS [AggregateServerConf]
(Int -> ReadS AggregateServerConf)
-> ReadS [AggregateServerConf]
-> ReadPrec AggregateServerConf
-> ReadPrec [AggregateServerConf]
-> Read AggregateServerConf
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [AggregateServerConf]
$creadListPrec :: ReadPrec [AggregateServerConf]
readPrec :: ReadPrec AggregateServerConf
$creadPrec :: ReadPrec AggregateServerConf
readList :: ReadS [AggregateServerConf]
$creadList :: ReadS [AggregateServerConf]
readsPrec :: Int -> ReadS AggregateServerConf
$creadsPrec :: Int -> ReadS AggregateServerConf
Read
aggregateServer :: (FromJSON a, ToJSON a) =>
Aggregate a -> ByteString -> AggregateServerConf -> Bool -> IO L.ByteString
aggregateServer :: Aggregate a
-> ByteString -> AggregateServerConf -> Bool -> IO ByteString
aggregateServer a :: Aggregate a
a u :: ByteString
u = (AggregateServerConf -> IO ByteString)
-> AggregateServerConf -> Bool -> IO ByteString
forall a. (a -> IO ByteString) -> a -> Bool -> IO ByteString
ignitionService ((AggregateServerConf -> IO ByteString)
-> AggregateServerConf -> Bool -> IO ByteString)
-> (AggregateServerConf -> IO ByteString)
-> AggregateServerConf
-> Bool
-> IO ByteString
forall a b. (a -> b) -> a -> b
$ \conf :: AggregateServerConf
conf ->
Config Snap Any -> Snap () -> IO ()
forall (m :: * -> *) a.
MonadSnap m =>
Config m a -> Snap () -> IO ()
simpleHttpServe (Int -> Config Snap Any
forall a. Int -> Config Snap a
asConfig (Int -> Config Snap Any) -> Int -> Config Snap Any
forall a b. (a -> b) -> a -> b
$ AggregateServerConf -> Int
asPort AggregateServerConf
conf) (Aggregate a -> ByteString -> AggregateServerConf -> Snap ()
forall a.
(FromJSON a, ToJSON a) =>
Aggregate a -> ByteString -> AggregateServerConf -> Snap ()
asHandler Aggregate a
a ByteString
u AggregateServerConf
conf) IO () -> IO ByteString -> IO ByteString
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> IO ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ""
asConfig :: Int -> Config Snap a
asConfig :: Int -> Config Snap a
asConfig p :: Int
p = Int -> Config Snap a -> Config Snap a
forall (m :: * -> *) a. Int -> Config m a -> Config m a
setPort Int
p
(Config Snap a -> Config Snap a) -> Config Snap a -> Config Snap a
forall a b. (a -> b) -> a -> b
$ ByteString -> Config Snap a -> Config Snap a
forall (m :: * -> *) a. ByteString -> Config m a -> Config m a
setBind "127.0.0.1"
(Config Snap a -> Config Snap a) -> Config Snap a -> Config Snap a
forall a b. (a -> b) -> a -> b
$ ConfigLog -> Config Snap a -> Config Snap a
forall (m :: * -> *) a. ConfigLog -> Config m a -> Config m a
setAccessLog ConfigLog
ConfigNoLog
(Config Snap a -> Config Snap a) -> Config Snap a -> Config Snap a
forall a b. (a -> b) -> a -> b
$ ConfigLog -> Config Snap a -> Config Snap a
forall (m :: * -> *) a. ConfigLog -> Config m a -> Config m a
setErrorLog ConfigLog
ConfigNoLog
(Config Snap a -> Config Snap a) -> Config Snap a -> Config Snap a
forall a b. (a -> b) -> a -> b
$ Bool -> Config Snap a -> Config Snap a
forall (m :: * -> *) a. Bool -> Config m a -> Config m a
setVerbose Bool
False Config Snap a
forall a. Monoid a => a
mempty
asHandler :: (FromJSON a, ToJSON a) =>
Aggregate a -> ByteString -> AggregateServerConf -> Snap ()
asHandler :: Aggregate a -> ByteString -> AggregateServerConf -> Snap ()
asHandler a :: Aggregate a
a u :: ByteString
u conf :: AggregateServerConf
conf =
[(ByteString, Snap ())] -> Snap ()
forall (m :: * -> *) a. MonadSnap m => [(ByteString, m a)] -> m a
route [(ByteString -> ByteString -> ByteString
B.append "put/" ByteString
u, Method -> Snap () -> Snap ()
forall (m :: * -> *) a. MonadSnap m => Method -> m a -> m a
Snap.Core.method Method
POST (Snap () -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ Aggregate a -> AggregateServerConf -> Snap ()
forall a.
FromJSON a =>
Aggregate a -> AggregateServerConf -> Snap ()
receiveAggregate Aggregate a
a AggregateServerConf
conf)
,(ByteString -> ByteString -> ByteString
B.append "get/" ByteString
u, Method -> Snap () -> Snap ()
forall (m :: * -> *) a. MonadSnap m => Method -> m a -> m a
Snap.Core.method Method
GET (Snap () -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ Aggregate a -> Snap ()
forall a. ToJSON a => Aggregate a -> Snap ()
sendAggregate Aggregate a
a)
]
receiveAggregate :: FromJSON a =>
Aggregate a -> AggregateServerConf -> Snap ()
receiveAggregate :: Aggregate a -> AggregateServerConf -> Snap ()
receiveAggregate a :: Aggregate a
a conf :: AggregateServerConf
conf =
String -> Snap () -> Snap ()
handleAggregateExceptions "Exception while receiving aggregate" (Snap () -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ do
!Maybe (Int32, Maybe a)
s <- ByteString -> Maybe (Int32, Maybe a)
forall a. FromJSON a => ByteString -> Maybe a
decode' (ByteString -> Maybe (Int32, Maybe a))
-> Snap ByteString -> Snap (Maybe (Int32, Maybe a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word64 -> Snap ByteString
forall (m :: * -> *). MonadSnap m => Word64 -> m ByteString
readRequestBody 65536
Bool -> Snap () -> Snap ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe (Int32, Maybe a) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (Int32, Maybe a)
s) (Snap () -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ IO () -> Snap ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Snap ()) -> IO () -> Snap ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
forall a. String -> IO a
throwUserError "Unreadable aggregate!"
IO () -> Snap ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Snap ()) -> IO () -> Snap ()
forall a b. (a -> b) -> a -> b
$ do
let (pid :: Int32
pid, v :: Maybe a
v) = Maybe (Int32, Maybe a) -> (Int32, Maybe a)
forall a. HasCallStack => Maybe a -> a
fromJust Maybe (Int32, Maybe a)
s
int :: CTime
int = Int -> CTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CTime)
-> (AggregateServerConf -> Int) -> AggregateServerConf -> CTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeInterval -> Int
toSec (TimeInterval -> Int)
-> (AggregateServerConf -> TimeInterval)
-> AggregateServerConf
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AggregateServerConf -> TimeInterval
asPurgeInterval (AggregateServerConf -> CTime) -> AggregateServerConf -> CTime
forall a b. (a -> b) -> a -> b
$ AggregateServerConf
conf
!CTime
t <- IO CTime
ngxNow
Aggregate a
-> ((CTime, Map Int32 (CTime, Maybe a))
-> ((CTime, Map Int32 (CTime, Maybe a)), ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' Aggregate a
a (((CTime, Map Int32 (CTime, Maybe a))
-> ((CTime, Map Int32 (CTime, Maybe a)), ()))
-> IO ())
-> ((CTime, Map Int32 (CTime, Maybe a))
-> ((CTime, Map Int32 (CTime, Maybe a)), ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$
\(t' :: CTime
t', v' :: Map Int32 (CTime, Maybe a)
v') ->
(let (!CTime
tn, f :: Map k (CTime, b) -> Map k (CTime, b)
f) =
if CTime
t CTime -> CTime -> CTime
forall a. Num a => a -> a -> a
- CTime
t' CTime -> CTime -> Bool
forall a. Ord a => a -> a -> Bool
>= CTime
int
then (CTime
t, ((CTime, b) -> Bool) -> Map k (CTime, b) -> Map k (CTime, b)
forall a k. (a -> Bool) -> Map k a -> Map k a
M.filter (((CTime, b) -> Bool) -> Map k (CTime, b) -> Map k (CTime, b))
-> ((CTime, b) -> Bool) -> Map k (CTime, b) -> Map k (CTime, b)
forall a b. (a -> b) -> a -> b
$ \(t'' :: CTime
t'', _) -> CTime
t CTime -> CTime -> CTime
forall a. Num a => a -> a -> a
- CTime
t'' CTime -> CTime -> Bool
forall a. Ord a => a -> a -> Bool
< CTime
int)
else (CTime
t', Map k (CTime, b) -> Map k (CTime, b)
forall a. a -> a
id)
!vn :: Map Int32 (CTime, Maybe a)
vn = Map Int32 (CTime, Maybe a) -> Map Int32 (CTime, Maybe a)
forall k b. Map k (CTime, b) -> Map k (CTime, b)
f (Map Int32 (CTime, Maybe a) -> Map Int32 (CTime, Maybe a))
-> Map Int32 (CTime, Maybe a) -> Map Int32 (CTime, Maybe a)
forall a b. (a -> b) -> a -> b
$ (Maybe (CTime, Maybe a) -> Maybe (CTime, Maybe a))
-> Int32
-> Map Int32 (CTime, Maybe a)
-> Map Int32 (CTime, Maybe a)
forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
M.alter
(\old :: Maybe (CTime, Maybe a)
old ->
let !new' :: Maybe a
new' =
if Maybe (CTime, Maybe a) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (CTime, Maybe a)
old Bool -> Bool -> Bool
|| Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
v
then Maybe a
v
else (CTime, Maybe a) -> Maybe a
forall a b. (a, b) -> b
snd ((CTime, Maybe a) -> Maybe a) -> (CTime, Maybe a) -> Maybe a
forall a b. (a -> b) -> a -> b
$ Maybe (CTime, Maybe a) -> (CTime, Maybe a)
forall a. HasCallStack => Maybe a -> a
fromJust Maybe (CTime, Maybe a)
old
in (CTime, Maybe a) -> Maybe (CTime, Maybe a)
forall a. a -> Maybe a
Just (CTime
t, Maybe a
new')
) Int32
pid Map Int32 (CTime, Maybe a)
v'
in (CTime
tn, Map Int32 (CTime, Maybe a)
vn)
,()
)
Response -> Snap ()
forall (m :: * -> *) a. MonadSnap m => Response -> m a
finishWith Response
emptyResponse
sendAggregate :: ToJSON a => Aggregate a -> Snap ()
sendAggregate :: Aggregate a -> Snap ()
sendAggregate a :: Aggregate a
a =
String -> Snap () -> Snap ()
handleAggregateExceptions "Exception while sending aggregate" (Snap () -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ do
(CTime, Map Int32 (CTime, Maybe a))
s <- IO (CTime, Map Int32 (CTime, Maybe a))
-> Snap (CTime, Map Int32 (CTime, Maybe a))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (CTime, Map Int32 (CTime, Maybe a))
-> Snap (CTime, Map Int32 (CTime, Maybe a)))
-> IO (CTime, Map Int32 (CTime, Maybe a))
-> Snap (CTime, Map Int32 (CTime, Maybe a))
forall a b. (a -> b) -> a -> b
$ Aggregate a -> IO (CTime, Map Int32 (CTime, Maybe a))
forall a. IORef a -> IO a
readIORef Aggregate a
a
(Response -> Response) -> Snap ()
forall (m :: * -> *). MonadSnap m => (Response -> Response) -> m ()
modifyResponse ((Response -> Response) -> Snap ())
-> (Response -> Response) -> Snap ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Response -> Response
setContentType "application/json"
ByteString -> Snap ()
forall (m :: * -> *). MonadSnap m => ByteString -> m ()
writeLBS (ByteString -> Snap ()) -> ByteString -> Snap ()
forall a b. (a -> b) -> a -> b
$ (UTCTime, Map Int32 (UTCTime, Maybe a)) -> ByteString
forall a. ToJSON a => a -> ByteString
encode ((UTCTime, Map Int32 (UTCTime, Maybe a)) -> ByteString)
-> (UTCTime, Map Int32 (UTCTime, Maybe a)) -> ByteString
forall a b. (a -> b) -> a -> b
$ (CTime -> UTCTime
toUTCTime (CTime -> UTCTime)
-> (Map Int32 (CTime, Maybe a) -> Map Int32 (UTCTime, Maybe a))
-> (CTime, Map Int32 (CTime, Maybe a))
-> (UTCTime, Map Int32 (UTCTime, Maybe a))
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** ((CTime, Maybe a) -> (UTCTime, Maybe a))
-> Map Int32 (CTime, Maybe a) -> Map Int32 (UTCTime, Maybe a)
forall a b k. (a -> b) -> Map k a -> Map k b
M.map ((CTime -> UTCTime) -> (CTime, Maybe a) -> (UTCTime, Maybe a)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first CTime -> UTCTime
toUTCTime)) (CTime, Map Int32 (CTime, Maybe a))
s
where toUTCTime :: CTime -> UTCTime
toUTCTime (CTime t :: Int64
t) = POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime) -> POSIXTime -> UTCTime
forall a b. (a -> b) -> a -> b
$ Int64 -> POSIXTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
t
handleAggregateExceptions :: String -> Snap () -> Snap ()
handleAggregateExceptions :: String -> Snap () -> Snap ()
handleAggregateExceptions cmsg :: String
cmsg = (SomeException -> Snap ()) -> Snap () -> Snap ()
forall (m :: * -> *) a.
MonadBaseControl IO m =>
(SomeException -> m a) -> m a -> m a
handleAny ((SomeException -> Snap ()) -> Snap () -> Snap ())
-> (SomeException -> Snap ()) -> Snap () -> Snap ()
forall a b. (a -> b) -> a -> b
$ \e :: SomeException
e ->
Int -> String -> Snap ()
forall (m :: * -> *). MonadSnap m => Int -> String -> m ()
writeErrorResponse 500 (String -> Snap ()) -> String -> Snap ()
forall a b. (a -> b) -> a -> b
$ SomeException -> String
forall a. Show a => a -> String
show (SomeException
e :: SomeException)
where writeErrorResponse :: Int -> String -> m ()
writeErrorResponse c :: Int
c msg :: String
msg = do
(Response -> Response) -> m ()
forall (m :: * -> *). MonadSnap m => (Response -> Response) -> m ()
modifyResponse ((Response -> Response) -> m ()) -> (Response -> Response) -> m ()
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> Response -> Response
setResponseStatus Int
c (ByteString -> Response -> Response)
-> ByteString -> Response -> Response
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
cmsg
ByteString -> m ()
forall (m :: * -> *). MonadSnap m => ByteString -> m ()
writeBS (ByteString -> m ()) -> ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
msg
throwUserError :: String -> IO a
throwUserError :: String -> IO a
throwUserError = IOError -> IO a
forall a. IOError -> IO a
ioError (IOError -> IO a) -> (String -> IOError) -> String -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IOError
userError
ngxExportAggregateService :: String
-> Name
-> Q [Dec]
ngxExportAggregateService :: String -> Name -> Q [Dec]
ngxExportAggregateService f :: String
f a :: Name
a = do
let nameF :: Name
nameF = 'aggregateServer
fName :: Name
fName = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ "aggregate_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f
sName :: Name
sName = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ "aggregate_storage_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f
uName :: Name
uName = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ "aggregate_url_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f
[[Dec]] -> [Dec]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Dec]] -> [Dec]) -> Q [[Dec]] -> Q [Dec]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Q [Dec]] -> Q [[Dec]]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence
[[Q Dec] -> Q [Dec]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence
[Name -> TypeQ -> Q Dec
sigD Name
uName [t|ByteString|]
,Name -> [ClauseQ] -> Q Dec
funD Name
uName [[PatQ] -> BodyQ -> [Q Dec] -> ClauseQ
clause [] (ExpQ -> BodyQ
normalB [|C8.pack f|]) []]
,Name -> TypeQ -> Q Dec
sigD Name
sName [t|Aggregate $(conT a)|]
,Name -> [ClauseQ] -> Q Dec
funD Name
sName
[[PatQ] -> BodyQ -> [Q Dec] -> ClauseQ
clause []
(ExpQ -> BodyQ
normalB [|unsafePerformIO $ newIORef (0, M.empty)|])
[]
]
,Name -> Inline -> RuleMatch -> Phases -> Q Dec
pragInlD Name
sName Inline
NoInline RuleMatch
FunLike Phases
AllPhases
,Name -> TypeQ -> Q Dec
sigD Name
fName [t|AggregateServerConf -> Bool -> IO L.ByteString|]
,Name -> [ClauseQ] -> Q Dec
funD Name
fName
[[PatQ] -> BodyQ -> [Q Dec] -> ClauseQ
clause []
(ExpQ -> BodyQ
normalB [|$(varE nameF) $(varE sName) $(varE uName)|])
[]
]
]
,Name -> Name -> ServiceMode -> Q [Dec]
ngxExportSimpleServiceTyped
Name
fName ''AggregateServerConf ServiceMode
SingleShotService
]
reportAggregate :: ToJSON a => Int
-> Maybe a
-> ByteString
-> IO ()
reportAggregate :: Int -> Maybe a -> ByteString -> IO ()
reportAggregate p :: Int
p v :: Maybe a
v u :: ByteString
u =
(SomeException -> IO ()) -> IO () -> IO ()
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (IO () -> SomeException -> IO ()
forall a b. a -> b -> a
const (IO () -> SomeException -> IO ())
-> IO () -> SomeException -> IO ()
forall a b. (a -> b) -> a -> b
$ () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () :: SomeException -> IO ()) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Request
req <- String -> IO Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseRequest "POST http://127.0.0.1"
Int32
pid <- CPid -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CPid -> Int32) -> IO CPid -> IO Int32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO CPid
ngxPid :: IO Int32
let !req' :: Request
req' = Request
req { requestBody :: RequestBody
requestBody = ByteString -> RequestBody
RequestBodyLBS (ByteString -> RequestBody) -> ByteString -> RequestBody
forall a b. (a -> b) -> a -> b
$ (Int32, Maybe a) -> ByteString
forall a. ToJSON a => a -> ByteString
encode (Int32
pid, Maybe a
v)
, port :: Int
port = Int
p
, path :: ByteString
Network.HTTP.Client.path = ByteString -> ByteString -> ByteString
B.append "put/" ByteString
u
}
IO (Response ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Response ()) -> IO ()) -> IO (Response ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Request -> Manager -> IO (Response ())
httpNoBody Request
req' Manager
httpManager
httpManager :: Manager
httpManager :: Manager
httpManager = IO Manager -> Manager
forall a. IO a -> a
unsafePerformIO (IO Manager -> Manager) -> IO Manager -> Manager
forall a b. (a -> b) -> a -> b
$ ManagerSettings -> IO Manager
newManager ManagerSettings
defaultManagerSettings
{-# NOINLINE httpManager #-}