@@ -8,7 +8,7 @@
8#include "inline.hs"
8#include "inline.hs"
11−-- Module : Streamly.Internal.Network.Client
11+-- Module : Streamly.Internal.Network.Inet.TCP
12-- Copyright : (c) 2019 Composewell Technologies
12-- Copyright : (c) 2019 Composewell Technologies
14-- License : BSD3
14-- License : BSD3
@@ -16,18 +16,28 @@
16-- Stability : experimental
16-- Stability : experimental
17-- Portability : GHC
17-- Portability : GHC
19−-- Combinators to build network clients.
19+-- Combinators to build Inet/TCP clients and servers.
21−-- > import qualified Streamly.Network.Socket as Client
24−module Streamly.Internal.Network.Client
21+module Streamly.Internal.Network.Inet.TCP
26− -- * Interact
23+ -- * TCP Servers
24+ -- ** Connected sockets
33+ , connectionsOnAllAddrs
34+ , connectionsOnLocalHost
27 -- | Socket based reads and writes.
37 -- | Socket based reads and writes.
28− withConnection
38+ , withConnection
30− -- * Source
40+ -- ** Source
32 -- , readUtf8
42 -- , readUtf8
33 -- , readLines
43 -- , readLines
@@ -42,7 +52,7 @@ module Streamly.Internal.Network.Client
42 -- , readArraysOf
52 -- , readArraysOf
43 -- , readArrays
53 -- , readArrays
45− -- * Sink
55+ -- ** Sink
47 -- , writeUtf8
57 -- , writeUtf8
48 -- , writeUtf8ByLines
58 -- , writeUtf8ByLines
@@ -52,6 +62,27 @@ module Streamly.Internal.Network.Client
52 -- -- * Array Write
62 -- -- * Array Write
53 -- , writeArray
63 -- , writeArray
54 , writeArrays
64 , writeArrays
68+ -- These abstractions can be applied to any setting where we need to do a
69+ -- sink processing of multiple streams e.g. output from multiple processes
70+ -- or data coming from multiple files.
72+ -- handle connections concurrently using a specified fold
73+ -- , handleConnections
75+ -- handle frames concurrently using a specified fold
78+ -- merge frames from all connection into a single stream. Frames can be
79+ -- created by a specified fold.
@@ -59,24 +90,124 @@ import Control.Monad.Catch (MonadCatch)
59import Control.Monad.IO.Class (MonadIO(..))
90import Control.Monad.IO.Class (MonadIO(..))
60import Data.Word (Word8)
91import Data.Word (Word8)
61import Network.Socket
92import Network.Socket
62− (Socket, PortNumber, Family(..), SockAddr(..), SocketType(..),
93+ (Socket, PortNumber, SocketOption(..), Family(..), SockAddr(..),
94+ SocketType(..), defaultProtocol, maxListenQueue, tupleToHostAddress,
63− socket, connect, defaultProtocol)
95+ socket, connect)
64import Prelude hiding (read)
96import Prelude hiding (read)
66−import qualified Network.Socket as Net
68import Streamly (MonadAsync)
98import Streamly (MonadAsync)
69import Streamly.Internal.Data.Fold.Types (Fold(..))
99import Streamly.Internal.Data.Fold.Types (Fold(..))
100+import Streamly.Internal.Data.Unfold.Types (Unfold(..))
101+import Streamly.Internal.Network.Socket (SockSpec(..), listen, connections)
102+import Streamly.Streams.Serial (SerialT)
70import Streamly.Internal.Memory.Array.Types (Array(..), defaultChunkSize, writeNUnsafe)
103import Streamly.Internal.Memory.Array.Types (Array(..), defaultChunkSize, writeNUnsafe)
71−-- import Streamly.Streams.Serial (SerialT)
72import Streamly.Streams.StreamK.Type (IsStream)
104import Streamly.Streams.StreamK.Type (IsStream)
106+import qualified Network.Socket as Net
107+import qualified Streamly.Internal.Data.Unfold as UF
74import qualified Streamly.Internal.Memory.ArrayStream as AS
108import qualified Streamly.Internal.Memory.ArrayStream as AS
75import qualified Streamly.Internal.Data.Fold.Types as FL
109import qualified Streamly.Internal.Data.Fold.Types as FL
76import qualified Streamly.Prelude as S
110import qualified Streamly.Prelude as S
77import qualified Streamly.Network.Socket as SK
111import qualified Streamly.Network.Socket as SK
78import qualified Streamly.Internal.Network.Socket as ISK
112import qualified Streamly.Internal.Network.Socket as ISK
114+-------------------------------------------------------------------------------
116+-------------------------------------------------------------------------------
118+-- | Unfold a tuple @(ipAddr, port)@ into a stream of connected TCP sockets.
119+-- @ipAddr@ is the local IP address and @port@ is the local port on which
120+-- connections are accepted.
123+{-# INLINE listenOnAddr #-}
126+ => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Socket
127+listenOnAddr = UF.lmap f listen
132+ { sockFamily = AF_INET
134+ , sockProto = defaultProtocol -- TCP
135+ , sockOpts = [(NoDelay,1), (ReuseAddr,1)]
137+ , SockAddrInet port (tupleToHostAddress addr)
140+-- | Like 'listenOnAddr' but binds on the IPv4 address @0.0.0.0@ i.e. on all
141+-- IPv4 addresses/interfaces of the machine and listens for TCP connections on
142+-- the specified port.
144+-- > listenOnPort = UF.supplyFirst listenOnAddr (0,0,0,0)
147+{-# INLINE listenOnPort #-}
148+listenOnPort :: MonadIO m => Unfold m PortNumber Socket
149+listenOnPort = UF.supplyFirst listenOnAddr (0,0,0,0)
151+-- | Like 'listenOnAddr' but binds on the localhost IPv4 address @127.0.0.1@.
152+-- The server can only be accessed from the local host, it cannot be accessed
153+-- from other hosts on the network.
155+-- > listenOnPortLocal = UF.supplyFirst listenOnAddr (127,0,0,1)
158+{-# INLINE listenOnPortLocal #-}
159+listenOnPortLocal :: MonadIO m => Unfold m PortNumber Socket
160+listenOnPortLocal = UF.supplyFirst listenOnAddr (127,0,0,1)
162+-------------------------------------------------------------------------------
164+-------------------------------------------------------------------------------
166+-- | Like 'connections' but binds on the specified IPv4 address of the machine
167+-- and listens for TCP connections on the specified port.
170+{-# INLINE connectionsOnAddr #-}
173+ => (Word8, Word8, Word8, Word8)
176+connectionsOnAddr addr port =
177+ connections maxListenQueue SockSpec
178+ { sockFamily = AF_INET
180+ , sockProto = defaultProtocol
181+ , sockOpts = [(NoDelay,1), (ReuseAddr,1)]
183+ (SockAddrInet port (tupleToHostAddress addr))
185+-- | Like 'connections' but binds on the IPv4 address @0.0.0.0@ i.e. on all
186+-- IPv4 addresses/interfaces of the machine and listens for TCP connections on
187+-- the specified port.
189+-- > connectionsOnAllAddrs = connectionsOnAddr (0,0,0,0)
192+{-# INLINE connectionsOnAllAddrs #-}
193+connectionsOnAllAddrs :: MonadAsync m => PortNumber -> SerialT m Socket
194+connectionsOnAllAddrs = connectionsOnAddr (0,0,0,0)
196+-- | Like 'connections' but binds on the localhost IPv4 address @127.0.0.1@.
197+-- The server can only be accessed from the local host, it cannot be accessed
198+-- from other hosts on the network.
200+-- > connectionsOnLocalHost = connectionsOnAddr (127,0,0,1)
203+{-# INLINE connectionsOnLocalHost #-}
204+connectionsOnLocalHost :: MonadAsync m => PortNumber -> SerialT m Socket
205+connectionsOnLocalHost = connectionsOnAddr (127,0,0,1)
207+-------------------------------------------------------------------------------
209+-------------------------------------------------------------------------------
80-------------------------------------------------------------------------------
211-------------------------------------------------------------------------------
81-- Connect
212-- Connect
82-------------------------------------------------------------------------------
213-------------------------------------------------------------------------------