udp-streaming 0.1.0.1 → 0.2.0.0
raw patch · 3 files changed
+88/−32 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Streaming.UDP: SockAddrInet :: PortNumber -> HostAddress -> SockAddr
+ Streaming.UDP: data SockAddr :: *
+ Streaming.UDP: inet_addr :: String -> IO HostAddress
- Streaming.UDP: toIOSocket :: (MonadResource m) => IO Socket -> Stream (Of ByteString) m r -> m r
+ Streaming.UDP: toIOSocket :: (MonadResource m) => IO Socket -> Stream (Of (ByteString, SockAddr)) m r -> m r
- Streaming.UDP: toSocket :: (MonadIO m) => Socket -> Stream (Of ByteString) m r -> m r
+ Streaming.UDP: toSocket :: (MonadIO m) => Socket -> Stream (Of (ByteString, SockAddr)) m r -> m r
- Streaming.UDP: toUDP :: (MonadResource m) => String -> PortNumber -> Stream (Of ByteString) m r -> m r
+ Streaming.UDP: toUDP :: (MonadResource m) => String -> PortNumber -> Stream (Of (ByteString, SockAddr)) m r -> m r
Files
- README.md +48/−0
- src/Streaming/UDP.hs +31/−27
- udp-streaming.cabal +9/−5
+ README.md view
@@ -0,0 +1,48 @@+udp-streaming+==============++Simple fire and forget style streaming source and consumer in the spirit+of the [udp-conduit](https://github.com/kqr/udp-conduit) package.++Here's an example run in ghci that sends e messages to UDP port 8888 on localhost,+from the port 3000 on the localhost:++ >>> import qualified Streaming.Prelude as S+ >>> import Control.Monad.Trans.Resource+ >>> import Streaming.UDP+ >>>+ >>> :set -XOverloadedStrings+ >>>+ >>> addr1 <- SockAddrInet 8888 <$> (inet_addr "127.0.0.1")+ >>>+ >>> runResourceT $ toUDP "127.0.0.1" 3000 $ S.zip (S.each ["hello", "world", "!"]) (S.repeat addr1)+ +Here's an example in ghci where we continuously receive messages with a +maximum length of 500 bytes on port 8888 on localhost:++ >>> import qualified Streaming.Prelude as S+ >>> import Streaming.UDP+ >>> import Control.Monad.Trans.Resource+ >>> import qualified Data.ByteString as B + >>>+ >>>+ >>> runResourceT $ S.stdoutLn $ S.map (map (toEnum.fromEnum) . B.unpack) $ S.map fst $ fromUDP "127.0.0.1" 8888 500+++Now, here's an example where we receive messages on port 8001, encode them as hex+digits (using base16-bytestring package), and then send them on to port 8002.++ >>> import qualified Streaming.Prelude as S+ >>> import Streaming.UDP+ >>> import Data.ByteString.Base16 (encode)+ >>> import Control.Monad.Trans.Resource+ >>>+ >>> addr2 <- SockAddrInet 8002 <$> (inet_addr "127.0.0.1")+ >>>+ >>> runResourceT $ toUDP "127.0.0.1" 8002 $ S.zip (S.map encode $ S.map fst $ fromUDP "127.0.0.1" 8001 500) (S.repeat addr2)++Or you could, in the previous example, to also log the messages receved, before processing and+send them further:++ >>> runResourceT $ toUDP "127.0.0.1" 3000 $ S.zip (S.map encode $ S.map fst $ S.print $ S.copy $ fromUDP "127.0.0.1" 8001 500) (S.repeat addr2)+
src/Streaming/UDP.hs view
@@ -15,6 +15,10 @@ toUDP, toSocket, toIOSocket,++ -- * Reexports+ inet_addr,+ SockAddr(SockAddrInet) ) where import Streaming (Of, Stream, lift)@@ -22,30 +26,44 @@ import Network.Socket (Socket, SockAddr(SockAddrInet), PortNumber,- setSocketOption)+ setSocketOption,+ inet_addr) import qualified Network.Socket as Socket-import Network.Socket.ByteString (recvFrom, send)+import Network.Socket.ByteString (recvFrom,+ sendTo) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Trans.Resource (MonadResource, allocate) import Data.ByteString (ByteString) --- | gets an ip adress, a port and stream of strict `ByteString`s and--- sends all the `ByteString`s to UDP socket-toUDP :: (MonadResource m) => String -> PortNumber -> Stream (Of ByteString) m r -> m r-toUDP host port = toIOSocket (udpSocket host port SinkSocket)+-- | gets an ip adress, a port and stream of strict pairs ('ByteString', 'SockAddr') and+-- sends all the `ByteString`s to the 'SockAddr' from a socet bounded to the give ip and port.+--+-- /Note/: before 0.2.0.0 this function had a different specification.+--+-- @since 0.2.0.0+toUDP :: (MonadResource m) => String -> PortNumber -> Stream (Of (ByteString, SockAddr)) m r -> m r+toUDP host port = toIOSocket (udpSocket host port) -- | Stream all incoming data to the given connected 'Socket'. Note that this function will -- not automatically close the 'Socket' when processing completes.-toSocket :: (MonadIO m) => Socket -> Stream (Of ByteString) m r -> m r-toSocket s = S.mapM_ $ liftIO . send s+--+-- /Note/: before 0.2.0.0 this function had a different specification.+--+-- @since 0.2.0.0+toSocket :: (MonadIO m) => Socket -> Stream (Of (ByteString, SockAddr)) m r -> m r+toSocket s = S.mapM_ $ liftIO . (\ (m, a) -> sendTo s m a) -- since we are sending a datagram, can't use sendAll; ignore the value returned by send -- | An alternative to 'toSocket'. Instead of taking a pre-opened 'Socket', it -- takes an action that returns a connected 'Socket' , so that it can open it -- only when needed and close it as soon as possible.-toIOSocket :: (MonadResource m) => IO Socket -> Stream (Of ByteString) m r -> m r+--+-- /Note/: before 0.2.0.0 this function had a different specification.+--+-- @since 0.2.0.0+toIOSocket :: (MonadResource m) => IO Socket -> Stream (Of (ByteString, SockAddr)) m r -> m r toIOSocket connectAction str = do (_, s) <- allocate connectAction Socket.close toSocket s str@@ -62,7 +80,7 @@ -> Int -- ^ maximum size of a datagram -> Stream (Of (ByteString, SockAddr)) m r fromUDP host port sz =- fromIOSocket (udpSocket host port SourceSocket) sz+ fromIOSocket (udpSocket host port) sz -- | Stream the contents of a bound 'Socket' as binary data. Note that this function will -- not automatically close the 'Socket' when processing completes, since it did not acquire@@ -93,24 +111,10 @@ udpSocket :: String -- ^ IP address to host -> PortNumber- -> SocketType -> IO Socket-udpSocket host port socketType = do+udpSocket host port = do socket <- Socket.socket Socket.AF_INET Socket.Datagram Socket.defaultProtocol setSocketOption socket Socket.ReusePort 1- address <- Socket.inet_addr host- socketMode socketType socket (SockAddrInet port address)+ address <- inet_addr host+ Socket.bind socket (SockAddrInet port address) return socket---- | A type to distinguish when we want to read and write from sockets,--- simplifying the implementation-data SocketType- = SourceSocket -- ^ source socket, should 'Network.Socket.bind'- | SinkSocket -- ^ sink socket, should 'Network.Socket.connect'---- | Use either 'Network.Socket.bind' or 'Network.Socket.connect' depending on the 'SocketType'-socketMode :: SocketType -> Socket -> SockAddr -> IO ()-socketMode socketType =- case socketType of- SourceSocket -> Socket.bind- SinkSocket -> Socket.connect
udp-streaming.cabal view
@@ -1,12 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.27.0. -- -- see: https://github.com/sol/hpack ----- hash: fe0af0b6e00f4017f468ad1df7906de71eb634f5215bb20cd40c0a7364247174+-- hash: 85a95f5ca918709a3c111fac4ca4f1a8fd0f982d84b8c410b97435a2c6b343e9 name: udp-streaming-version: 0.1.0.1-synopsis: Simple fire-and-forget udp Streaming components modelled after udp-conduit+version: 0.2.0.0+synopsis: Streaming to and from UDP socket+description: Simple fire-and-forget udp Streaming components modelled after udp-conduit category: Network, Streaming stability: experimental homepage: https://hub.darcs.net/mihaigiurgeanu/udp-streaming@@ -16,7 +17,10 @@ license: MIT license-file: LICENSE build-type: Simple-cabal-version: >= 1.10+cabal-version: >= 1.18++extra-doc-files:+ README.md library hs-source-dirs: