pipes-network 0.6.3 → 0.6.4
raw patch · 6 files changed
+277/−138 lines, 6 filesdep ~network-simple
Dependency ranges changed: network-simple
Files
- PEOPLE +4/−2
- changelog +0/−94
- changelog.md +108/−0
- pipes-network.cabal +3/−4
- src/Pipes/Network/TCP.hs +80/−20
- src/Pipes/Network/TCP/Safe.hs +82/−18
PEOPLE view
@@ -1,9 +1,11 @@ The following people have participated in creating this library, either-by directly contributing code or by providing thoughtful input in-discussions about the library design.+by directly contributing code, by providing thoughtful input in+discussions about the library design, or by doing anything else that+helps this library move forwards. Renzo Carbonara Gabriel Gonzalez Paolo Capriotti Marius Ghita Kyle Van Berendonck+Nicolas Trangez
− changelog
@@ -1,94 +0,0 @@-# Version 0.6.3--* Bump `network-simple`, `transformers` and `pipes-safe` upper bounds.--* Remove `Base m ~ IO` constraints from `Pipes.Network.TCP.Safe`, as- not all of them were removed in 0.6.1.---# Version 0.6.2--* Dependency bumps (upper bounds).---# Version 0.6.1--* Remove the `Base m ~ IO` constraint from `Pipes.Network.TCP.Safe`---# Version 0.6.0--* Significantly upgraded the API and renamed functions to play well with- pipes-4.0.0, pipes-safe-2.0.0 and network-simple-0.3.0.--* Throw `IOError` in `IO` in order to report timeout errors. Delete- the `Timeout` data-type.---# Version 0.5.1.0--* Re-export `Network.Socket.withSocketsDo`.--* Use TCP `send` and `recv` as eported by network-simple-0.2.1.0.---# Version 0.5.0.0--* Removed `Control.Proxy.TCP.Sync` and `Control.Proxy.TCP.Safe.Sync`.---# Version 0.4.0.1--* FIX: `acceptFork` now properly closes the connection socket, even in- case of asynchronous exceptions.---# Version 0.4.0.0--* Do not handle “Broken Pipe” errors on the `*Write*D` proxies anymore.- As as a result, those proxies run forever and have a polymorphic- return value, which makes this release binary compatible with 0.2.0.0,- but not with 0.3.0.0.---# Version 0.3.0.0--* Quietly stop writing or reading bytes from a TCP socket if a- “Broken Pipe” error happens, indicating that the remote end- already closed the connection. Previously, a `ResourceVanished`- exception was thrown.--* All the `*Write*D` proxies now return `()` if the remote end- closed the connection.---# Version 0.2.0.0--* Depend on network-simple 0.2--* In both modules `Control.Proxy.TCP` and `Control.Proxy.TCP.Safe`:- `serveFork` was renamed to `serve` and the previous function named- `serve` was removed.---# Version 0.1.1.0--* Split many of the non-pipes-related TCP utilities to the own- `network-simple` package.-* Depend on `network-simple` and re-export its functions.---# Version 0.1.0.1--* Dependency bumps.---# Version 0.1.0--* New backwards incompatible API-* Based on pipes 3.1---# Up to version 0.0.2--* Based on pipes-core.
+ changelog.md view
@@ -0,0 +1,108 @@+# Version 0.6.4++* The various `fromServe` and `toServe*` pipes from+ `Pipes.Network.TCP.Safe` now close the listening socket immediately+ after accepting a first connection.++* Re-export `sendLazy`, `sendMany` and `closeSock`.++* Add `to{Socket,SocketTimeout,Serve,Connect}{Lazy,Many}`.++* Fix issue #29 where `fromSocketTimeout` and `fromSocketTimeoutN`+ would loop forever.+++# Version 0.6.3++* Bump `network-simple`, `transformers` and `pipes-safe` upper bounds.++* Remove `Base m ~ IO` constraints from `Pipes.Network.TCP.Safe`, as+ not all of them were removed in 0.6.1.+++# Version 0.6.2++* Dependency bumps (upper bounds).+++# Version 0.6.1++* Remove the `Base m ~ IO` constraint from `Pipes.Network.TCP.Safe`+++# Version 0.6.0++* Significantly upgraded the API and renamed functions to play well with+ pipes-4.0.0, pipes-safe-2.0.0 and network-simple-0.3.0.++* Throw `IOError` in `IO` in order to report timeout errors. Delete+ the `Timeout` data-type.+++# Version 0.5.1.0++* Re-export `Network.Socket.withSocketsDo`.++* Use TCP `send` and `recv` as eported by network-simple-0.2.1.0.+++# Version 0.5.0.0++* Removed `Control.Proxy.TCP.Sync` and `Control.Proxy.TCP.Safe.Sync`.+++# Version 0.4.0.1++* FIX: `acceptFork` now properly closes the connection socket, even in+ case of asynchronous exceptions.+++# Version 0.4.0.0++* Do not handle “Broken Pipe” errors on the `*Write*D` proxies anymore.+ As as a result, those proxies run forever and have a polymorphic+ return value, which makes this release binary compatible with 0.2.0.0,+ but not with 0.3.0.0.+++# Version 0.3.0.0++* Quietly stop writing or reading bytes from a TCP socket if a+ “Broken Pipe” error happens, indicating that the remote end+ already closed the connection. Previously, a `ResourceVanished`+ exception was thrown.++* All the `*Write*D` proxies now return `()` if the remote end+ closed the connection.+++# Version 0.2.0.0++* Depend on network-simple 0.2++* In both modules `Control.Proxy.TCP` and `Control.Proxy.TCP.Safe`:+ `serveFork` was renamed to `serve` and the previous function named+ `serve` was removed.+++# Version 0.1.1.0++* Split many of the non-pipes-related TCP utilities to the own+ `network-simple` package.+* Depend on `network-simple` and re-export its functions.+++# Version 0.1.0.1++* Dependency bumps.+++# Version 0.1.0++* New backwards incompatible API+* Based on pipes 3.1+++# Up to version 0.0.2++* Based on pipes-core.
pipes-network.cabal view
@@ -1,5 +1,5 @@ name: pipes-network-version: 0.6.3+version: 0.6.4 license: BSD3 license-file: LICENSE copyright: Copyright (c) Renzo Carbonara 2012-2014, Paolo Capriotti 2012-2012.@@ -13,7 +13,7 @@ build-type: Simple synopsis: Use network sockets together with the pipes library. cabal-version: >=1.8-extra-source-files: README.md PEOPLE changelog+extra-source-files: README.md PEOPLE changelog.md description: Use network sockets together with the @pipes@ library. .@@ -41,7 +41,7 @@ base (==4.*), bytestring (>=0.9.2.1), network,- network-simple (>=0.3 && <0.5),+ network-simple (>=0.4.0.1 && <0.5), pipes (>=4.0 && <4.2), pipes-safe (>=2.1 && <2.3), transformers (>=0.2 && <0.5)@@ -49,4 +49,3 @@ Pipes.Network.TCP Pipes.Network.TCP.Safe ghc-options: -Wall -O2-
src/Pipes/Network/TCP.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE RankNTypes #-} -- | This minimal module exports facilities that ease the usage of TCP+ -- 'Socket's in the /Pipes ecosystem/. It is meant to be used together with -- the "Network.Simple.TCP" module from the @network-simple@ package, which is -- completely re-exported from this module.@@ -24,19 +25,25 @@ -- * Sending -- $sending , toSocket+ , toSocketLazy+ , toSocketMany , toSocketTimeout+ , toSocketTimeoutLazy+ , toSocketTimeoutMany -- * Exports -- $exports , module Network.Simple.TCP ) where import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL import Foreign.C.Error (errnoToIOError, eTIMEDOUT) import qualified Network.Socket.ByteString as NSB import Network.Simple.TCP (connect, serve, listen, accept, acceptFork,- bindSock, connectSock, recv, send, withSocketsDo,- HostName, HostPreference(HostAny, HostIPv4, HostIPv6, Host),+ bindSock, connectSock, closeSock, recv, send, sendLazy,+ sendMany, withSocketsDo, HostName,+ HostPreference(HostAny, HostIPv4, HostIPv6, Host), ServiceName, SockAddr, Socket) import Pipes import Pipes.Core@@ -46,13 +53,13 @@ -- $receiving ----- The following pipes allow you to receive bytes from the remote end.+-- The following producers allow you to receive bytes from the remote end. ----- Besides the pipes below, you might want to use "Network.Simple.TCP"'s--- 'Network.Simple.TCP.recv', which happens to be an 'Effect'':+-- Besides the producers below, you might want to use "Network.Simple.TCP"'s+-- 'recv', which happens to be an 'Effect'': -- -- @--- 'Network.Simple.TCP.recv' :: 'MonadIO' m => 'Socket' -> 'Int' -> 'Effect'' m ('Maybe' 'B.ByteString')+-- 'recv' :: 'MonadIO' m => 'Socket' -> 'Int' -> 'Effect'' m ('Maybe' 'B.ByteString') -- @ --------------------------------------------------------------------------------@@ -91,7 +98,9 @@ loop = do mbs <- liftIO (timeout wait (NSB.recv sock nbytes)) case mbs of- Just bs -> yield bs >> loop+ Just bs+ | B.null bs -> return ()+ | otherwise -> yield bs >> loop Nothing -> liftIO $ ioError $ errnoToIOError "Pipes.Network.TCP.fromSocketTimeout" eTIMEDOUT Nothing Nothing {-# INLINABLE fromSocketTimeout #-}@@ -129,7 +138,9 @@ loop = \nbytes -> do mbs <- liftIO (timeout wait (NSB.recv sock nbytes)) case mbs of- Just bs -> respond bs >>= loop+ Just bs+ | B.null bs -> return ()+ | otherwise -> respond bs >>= loop Nothing -> liftIO $ ioError $ errnoToIOError "Pipes.Network.TCP.fromSocketTimeoutN" eTIMEDOUT Nothing Nothing {-# INLINABLE fromSocketTimeoutN #-}@@ -138,13 +149,15 @@ -- $sending ----- The following pipes allow you to send bytes to the remote end.+-- The following consumers allow you to send bytes to the remote end. ----- Besides the pipes below, you might want to use "Network.Simple.TCP"'s--- 'Network.Simple.TCP.send', which happens to be an 'Effect'':+-- Besides the consumers below, you might want to use "Network.Simple.TCP"'s+-- 'send', 'sendLazy' or 'sendMany' which happen to be 'Effect''s: -- -- @--- 'Network.Simple.TCP.send' :: 'MonadIO' m => 'Socket' -> 'B.ByteString' -> 'Effect'' m ()+-- 'send' :: 'MonadIO' m => 'Socket' -> 'B.ByteString' -> 'Effect'' m ()+-- 'sendLazy' :: 'MonadIO' m => 'Socket' -> 'BL.ByteString' -> 'Effect'' m ()+-- 'sendMany' :: 'MonadIO' m => 'Socket' -> ['B.ByteString'] -> 'Effect'' m () -- @ -- | Sends to the remote end each 'B.ByteString' received from upstream.@@ -155,20 +168,64 @@ toSocket sock = for cat (\a -> send sock a) {-# INLINABLE toSocket #-} +-- | Like 'toSocket' but takes a lazy 'BL.ByteSring' and sends it in a more+-- efficient manner (compared to converting it to a strict 'B.ByteString' and+-- sending it).+toSocketLazy+ :: MonadIO m+ => Socket -- ^Connected socket.+ -> Consumer' BL.ByteString m r+toSocketLazy sock = for cat (\a -> sendLazy sock a)+{-# INLINABLE toSocketLazy #-}++-- | Like 'toSocket' but takes a @['BL.ByteSring']@ and sends it in a more+-- efficient manner (compared to converting it to a strict 'B.ByteString' and+-- sending it).+toSocketMany+ :: MonadIO m+ => Socket -- ^Connected socket.+ -> Consumer' [B.ByteString] m r+toSocketMany sock = for cat (\a -> sendMany sock a)+{-# INLINABLE toSocketMany #-}+ -- | Like 'toSocket', except with the first 'Int' argument you can specify -- the maximum time that each interaction with the remote end can take. If such -- time elapses before the interaction finishes, then an 'IOError' exception is -- thrown. The time is specified in microseconds (1 second = 1e6 microseconds).-toSocketTimeout+toSocketTimeout :: MonadIO m => Int -> Socket -> Consumer' B.ByteString m r+toSocketTimeout = _toSocketTimeout send "Pipes.Network.TCP.toSocketTimeout"+{-# INLINABLE toSocketTimeout #-}++-- | Like 'toSocketTimeout' but takes a lazy 'BL.ByteSring' and sends it in a+-- more efficient manner (compared to converting it to a strict 'B.ByteString'+-- and sending it).+toSocketTimeoutLazy :: MonadIO m => Int -> Socket -> Consumer' BL.ByteString m r+toSocketTimeoutLazy =+ _toSocketTimeout sendLazy "Pipes.Network.TCP.toSocketTimeoutLazy"+{-# INLINABLE toSocketTimeoutLazy #-}++-- | Like 'toSocketTimeout' but takes a @['BL.ByteSring']@ and sends it in a+-- more efficient manner (compared to converting it to a strict 'B.ByteString'+-- and sending it).+toSocketTimeoutMany+ :: MonadIO m => Int -> Socket -> Consumer' [B.ByteString] m r+toSocketTimeoutMany =+ _toSocketTimeout sendMany "Pipes.Network.TCP.toSocketTimeoutMany"+{-# INLINABLE toSocketTimeoutMany #-}++_toSocketTimeout :: MonadIO m- => Int -> Socket -> Consumer' B.ByteString m r-toSocketTimeout wait sock = for cat $ \a -> do- mu <- liftIO (timeout wait (NSB.sendAll sock a))+ => (Socket -> a -> IO ())+ -> String+ -> Int+ -> Socket+ -> Consumer' a m r+_toSocketTimeout send' nm = \wait sock -> for cat $ \a -> do+ mu <- liftIO (timeout wait (send' sock a)) case mu of- Just () -> return ()- Nothing -> liftIO $ ioError $ errnoToIOError- "Pipes.Network.TCP.toSocketTimeout" eTIMEDOUT Nothing Nothing-{-# INLINABLE toSocketTimeout #-}+ Just () -> return ()+ Nothing -> liftIO $ ioError $ errnoToIOError nm eTIMEDOUT Nothing Nothing+{-# INLINABLE _toSocketTimeout #-} -------------------------------------------------------------------------------- @@ -180,10 +237,13 @@ -- 'bindSock', -- 'connect', -- 'connectSock',+-- 'closeSock', -- 'HostPreference'('HostAny','HostIPv4','HostIPv6','Host'), -- 'listen', -- 'recv', -- 'send',+-- 'sendLazy',+-- 'sendMany', -- 'serve'. -- -- [From "Network.Socket"]
src/Pipes/Network/TCP/Safe.hs view
@@ -26,10 +26,14 @@ -- $client-streaming , fromConnect , toConnect+ , toConnectLazy+ , toConnectMany -- ** Server side -- $server-streaming , fromServe , toServe+ , toServeLazy+ , toServeMany -- * Exports -- $exports , module Pipes.Network.TCP@@ -39,15 +43,18 @@ import Control.Monad import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL import Network.Simple.TCP- (acceptFork, bindSock, connectSock, recv, send, withSocketsDo,- HostName, HostPreference(HostAny, HostIPv4, HostIPv6, Host),+ (acceptFork, bindSock, connectSock, closeSock, recv, send,+ sendLazy, sendMany, withSocketsDo, HostName,+ HostPreference(HostAny, HostIPv4, HostIPv6, Host), ServiceName, SockAddr, Socket) import qualified Network.Socket as NS import Pipes import Pipes.Network.TCP (fromSocket, fromSocketTimeout, fromSocketN,- fromSocketTimeoutN, toSocket, toSocketTimeout)+ fromSocketTimeoutN, toSocket, toSocketLazy, toSocketMany,+ toSocketTimeout, toSocketTimeoutLazy, toSocketTimeoutMany) import qualified Pipes.Safe as Ps import Pipes.Safe (runSafeT) @@ -128,9 +135,7 @@ -> HostName -- ^Server host name. -> ServiceName -- ^Server service port. -> Producer' B.ByteString m ()-fromConnect nbytes host port = do- connect host port $ \(csock,_) -> do- fromSocket csock nbytes+fromConnect nbytes = _connect (\csock -> fromSocket csock nbytes) -- | Connects to a TCP server, sends to the remote end the bytes received from -- upstream.@@ -147,10 +152,37 @@ => HostName -- ^Server host name. -> ServiceName -- ^Server service port. -> Consumer' B.ByteString m r-toConnect hp port = do- connect hp port $ \(csock,_) -> do- toSocket csock+toConnect = _connect toSocket +-- | Like 'toConnect', but works more efficiently on lazy 'BL.ByteString's+-- (compared to converting them to a strict 'B.ByteString' and sending it)+toConnectLazy+ :: Ps.MonadSafe m+ => HostName -- ^Server host name.+ -> ServiceName -- ^Server service port.+ -> Consumer' BL.ByteString m r+toConnectLazy = _connect toSocketLazy++-- | Like 'toConnect', but works more efficiently on @['B.ByteString']@+-- (compared to converting them to a strict 'B.ByteString' and sending it)+toConnectMany+ :: Ps.MonadSafe m+ => HostName -- ^Server host name.+ -> ServiceName -- ^Server service port.+ -> Consumer' [B.ByteString] m r+toConnectMany = _connect toSocketMany++_connect+ :: Ps.MonadSafe m+ => (Socket -> m r) -- ^Action to perform on the connection socket.+ -> HostName -- ^Server host name.+ -> ServiceName -- ^Server service port.+ -> m r+_connect act hp port = do+ connect hp port $ \(csock,_) -> do+ act csock+{-# INLINABLE _connect #-}+ -------------------------------------------------------------------------------- -- $server-streaming@@ -189,10 +221,7 @@ -> HostPreference -- ^Preferred host to bind. -> ServiceName -- ^Service port to bind. -> Producer' B.ByteString m ()-fromServe nbytes hp port = do- listen hp port $ \(lsock,_) -> do- accept lsock $ \(csock,_) -> do- fromSocket csock nbytes+fromServe nbytes = _serve (\csock -> fromSocket csock nbytes) -- | Binds a listening socket, accepts a single connection, sends to the remote -- end the bytes received from upstream.@@ -210,10 +239,39 @@ => HostPreference -- ^Preferred host to bind. -> ServiceName -- ^Service port to bind. -> Consumer' B.ByteString m r-toServe hp port = do+toServe = _serve toSocket++-- | Like 'toServe', but works more efficiently on lazy 'BL.ByteString's+-- (compared to converting them to a strict 'B.ByteString' and sending it)+toServeLazy+ :: Ps.MonadSafe m+ => HostPreference -- ^Preferred host to bind.+ -> ServiceName -- ^Service port to bind.+ -> Consumer' BL.ByteString m r+toServeLazy = _serve toSocketLazy++-- | Like 'toServe', but works more efficiently on @['B.ByteString']@+-- (compared to converting them to a strict 'B.ByteString' and sending it)+toServeMany+ :: Ps.MonadSafe m+ => HostPreference -- ^Preferred host to bind.+ -> ServiceName -- ^Service port to bind.+ -> Consumer' [B.ByteString] m r+toServeMany = _serve toSocketMany++_serve+ :: Ps.MonadSafe m+ => (Socket -> m r) -- ^Action to perform on the connection socket.+ -> HostPreference -- ^Preferred host to bind.+ -> ServiceName -- ^Service port to bind.+ -> m r+_serve act hp port = do listen hp port $ \(lsock,_) -> do accept lsock $ \(csock,_) -> do- toSocket csock+ closeSock lsock -- We prevent more connection attempts to happen+ -- while we deal with `csock`.+ act csock+{-# INLINABLE _serve #-} -------------------------------------------------------------------------------- @@ -225,15 +283,22 @@ -- 'fromSocketTimeout', -- 'fromSocketTimeoutN', -- 'toSocket',--- 'toSocketTimeout'.+-- 'toSocketLazy',+-- 'toSocketMany',+-- 'toSocketTimeout',+-- 'toSocketTimeoutLazy',+-- 'toSocketTimeoutMany'. -- -- [From "Network.Simple.TCP"] -- 'acceptFork', -- 'bindSock', -- 'connectSock',+-- 'closeSock', -- 'HostPreference'('HostAny','HostIPv4','HostIPv6','Host'), -- 'recv',--- 'send'.+-- 'send',+-- 'sendLazy',+-- 'sendMany'. -- -- [From "Network.Socket"] -- 'HostName',@@ -244,4 +309,3 @@ -- -- [From "Pipes.Safe"] -- 'Ps.runSafeT'.-