@@ -0,0 +1,133 @@
2+{-# LANGUAGE BangPatterns #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE MagicHash #-}
5+{-# LANGUAGE RecordWildCards #-}
6+{-# LANGUAGE UnboxedTuples #-}
11+-- Module : Streamly.Network.Client
12+-- Copyright : (c) 2019 Composewell Technologies
15+-- Maintainer : harendra.kumar@gmail.com
16+-- Stability : experimental
19+-- Combinators to build network clients.
21+-- > import qualified Streamly.Network.Socket as Client
24+module Streamly.Network.Client
27+ -- | Socket based reads and writes.
48+ -- , writeUtf8ByLines
58+import Control.Monad.Catch (MonadCatch)
59+import Control.Monad.IO.Class (MonadIO(..))
60+import Data.Word (Word8)
62+ (Socket, PortNumber, Family(..), SockAddr(..), SocketType(..),
63+ socket, connect, defaultProtocol)
64+import Prelude hiding (read)
66+import qualified Network.Socket as Net
68+import Streamly (MonadAsync)
69+import Streamly.Mem.Array.Types (Array(..))
70+import Streamly.Streams.Serial (SerialT)
71+import Streamly.Streams.StreamK.Type (IsStream)
73+import qualified Streamly.Prelude as S
74+import qualified Streamly.Network.Socket as SK
76+-------------------------------------------------------------------------------
78+-------------------------------------------------------------------------------
80+openConnection :: (Word8, Word8, Word8, Word8) -> PortNumber -> IO Socket
81+openConnection addr port = do
82+ sock <- socket AF_INET Stream defaultProtocol
83+ connect sock $ SockAddrInet port (Net.tupleToHostAddress addr)
86+-- | @'withConnection' addr port act@ opens a connection to the specified IPv4
87+-- host address and port and passes the resulting socket handle to the
88+-- computation @act@. The handle will be closed on exit from 'withConnection',
89+-- whether by normal termination or by raising an exception. If closing the
90+-- handle raises an exception, then this exception will be raised by
91+-- 'withConnection' rather than any exception raised by 'act'.
94+withConnection :: (IsStream t, MonadCatch m, MonadIO m)
95+ => (Word8, Word8, Word8, Word8) -> PortNumber -> (Socket -> t m a) -> t m a
96+withConnection addr port =
97+ S.bracket (liftIO $ openConnection addr port) (liftIO . Net.close)
99+-------------------------------------------------------------------------------
100+-- Read Addr to Stream
101+-------------------------------------------------------------------------------
103+-- | Read a stream from the supplied IPv4 host address and port number.
106+read :: (IsStream t, MonadCatch m, MonadIO m)
107+ => (Word8, Word8, Word8, Word8) -> PortNumber -> t m Word8
108+read addr port = withConnection addr port SK.read
110+-------------------------------------------------------------------------------
112+-------------------------------------------------------------------------------
114+-- | Write a stream to the supplied IPv4 host address and port number.
117+write :: (MonadCatch m, MonadIO m)
118+ => (Word8, Word8, Word8, Word8) -> PortNumber -> SerialT m Word8 -> m ()
120+ S.drain $ withConnection addr port (\sk -> S.yieldM $ SK.write sk xs)
122+-- | Write a stream of arrays to the supplied IPv4 host address and port
127+ :: (MonadCatch m, MonadAsync m)
128+ => (Word8, Word8, Word8, Word8)
130+ -> SerialT m (Array Word8)
132+writeArrays addr port xs =
133+ S.drain $ withConnection addr port (\sk -> S.yieldM $ SK.writeArrays sk xs)