module Data.Conduit.Network.UDP
(
Message (..)
, sourceSocket
, sinkSocket
, sinkAllSocket
, sinkToSocket
, sinkAllToSocket
, HostPreference (..)
, bindPort
, getSocket
) where
import Data.Conduit
import Network.Socket (AddrInfo, SockAddr, Socket)
import qualified Network.Socket as NS
import Network.Socket.ByteString (recvFrom, send, sendAll, sendTo, sendAllTo)
import Data.ByteString (ByteString)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad (void)
import Control.Monad.Trans.Class (lift)
import Data.Conduit.Network.Utils (HostPreference)
import qualified Data.Conduit.Network.Utils as Utils
data Message = Message { msgData :: !ByteString
, msgSender :: !SockAddr
}
sourceSocket :: MonadIO m => Socket -> Int -> GSource m Message
sourceSocket socket len = loop
where
loop = do
(bs, addr) <- lift $ liftIO $ recvFrom socket len
yield (Message bs addr) >> loop
sinkSocket :: MonadIO m => Socket -> GInfSink ByteString m
sinkSocket = sinkSocketHelper (\sock bs -> void $ send sock bs)
sinkAllSocket :: MonadIO m => Socket -> GInfSink ByteString m
sinkAllSocket = sinkSocketHelper sendAll
sinkToSocket :: MonadIO m => Socket -> GInfSink Message m
sinkToSocket = sinkSocketHelper (\sock (Message bs addr) -> void $ sendTo sock bs addr)
sinkAllToSocket :: MonadIO m => Socket -> GInfSink Message m
sinkAllToSocket = sinkSocketHelper (\sock (Message bs addr) -> sendAllTo sock bs addr)
getSocket :: String -> Int -> IO (Socket, AddrInfo)
getSocket host' port' = Utils.getSocket host' port' NS.Datagram
bindPort :: Int -> HostPreference -> IO Socket
bindPort p s = Utils.bindPort p s NS.Datagram
sinkSocketHelper :: MonadIO m => (Socket -> a -> IO ())
-> Socket
-> GInfSink a m
sinkSocketHelper act socket = loop
where
loop = awaitE >>= either
return
(\a -> lift (liftIO $ act socket a) >> loop)