http-pony-0.1.0.6: src/Network/HTTP/Pony/Serve.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.HTTP.Pony.Serve where
import Control.Exception (IOException)
import Control.Monad.Catch (MonadCatch)
import Control.Monad.Catch (MonadMask)
import Control.Monad.IO.Class (MonadIO(..))
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Monoid ((<>))
import qualified Network.Socket as NS
import qualified Network.Socket.ByteString as NSB
import Pipes (Effect, Producer, Consumer, runEffect, (>->), await)
import Pipes.Network.TCP.Safe (HostPreference())
import Pipes.Network.TCP.Safe (fromSocket, toSocket, connect, connectSock
, closeSock)
import qualified Pipes.Network.TCP.Safe as PipesNetwork
import Pipes.Safe (MonadSafe(), runSafeT, SafeT, tryP, throwM)
import Network.HTTP.Pony.Helper ((-), shutdownSend, shutdownReceive)
import Network.HTTP.Pony.ServeSafe (serveWithPipe)
import Prelude hiding ((-), log)
serveWithSocket :: (MonadSafe m, MonadCatch m) => (NS.Socket, NS.SockAddr)
-> (Producer ByteString m () -> m (Producer ByteString m ()))
-> m ()
serveWithSocket (s,_) =
let
pull = fromSocket s 4096
push = do
x <- await
-- liftIO (putStrLn ( "pony chunk: " ++ show (B.length x) ++ " - " ++ B.unpack x ))
if B.null x
then do
-- liftIO - do
-- connected <- NS.isConnected s
-- putStrLn - "socket connected? " <> show connected
-- if connected
-- then do
-- shutdownSend s
-- else
-- pure ()
let cont = () <$ await
r <- tryP (shutdownSend s)
case r of
Right _ -> cont
Left e -> do
-- liftIO - putStrLn - "Caught: " <> show e
cont
throwM (e :: IOException)
else do
liftIO (NSB.send s x)
push
in
serveWithPipe pull push
serveT :: (MonadSafe m, MonadMask n, MonadIO n)
=> (n () -> IO ())
-> HostPreference
-> NS.ServiceName
-> (Producer ByteString (SafeT n) ()
-> (SafeT n) (Producer ByteString (SafeT n) ()))
-> m ()
serveT exit host service app =
PipesNetwork.serve host service - \socket -> do
-- no-delay is specifically encouraged in HTTP/2
-- https://http2.github.io/faq/#will-i-need-tcpnodelay-for-my-http2-connections
liftIO - NS.setSocketOption (fst socket) NS.NoDelay 1
exit - runSafeT (serveWithSocket socket app)
serve, run :: (MonadSafe m) => HostPreference
-> NS.ServiceName
-> (Producer ByteString (SafeT IO) ()
-> (SafeT IO) (Producer ByteString (SafeT IO) ()))
-> m ()
serve = serveT id
run = serve