module Network.Hadoop.Socket
( S.Socket
, bracketSocket
, connectSocket
, closeSocket
) where
import Control.Monad.Catch (MonadMask, bracket, bracketOnError)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Hadoop.Types
import qualified Data.Text as T
import Network (PortID(PortNumber))
import qualified Network.Socket as S
import Network.Socks5 (defaultSocksConf, socksConnectWith)
bracketSocket :: (MonadMask m, MonadIO m) => Maybe SocksProxy -> Endpoint -> (S.Socket -> m a) -> m a
bracketSocket proxy endpoint = bracket (connectSocket proxy endpoint) closeSocket
connectSocket :: (MonadMask m, MonadIO m) => Maybe SocksProxy -> Endpoint -> m S.Socket
connectSocket Nothing = connectDirect
connectSocket (Just proxy) = connectSocks proxy
closeSocket :: MonadIO m => S.Socket -> m ()
closeSocket = liftIO . S.sClose
connectDirect :: (MonadMask m, MonadIO m) => Endpoint -> m S.Socket
connectDirect endpoint = do
(addr:_) <- liftIO $ S.getAddrInfo (Just hints) (Just host) (Just port)
bracketOnError (newSocket addr) closeSocket $ \sock -> do
liftIO $ S.connect sock (S.addrAddress addr)
return sock
where
host = T.unpack (epHost endpoint)
port = show (epPort endpoint)
hints = S.defaultHints { S.addrFlags = [S.AI_ADDRCONFIG]
, S.addrSocketType = S.Stream }
newSocket :: MonadIO m => S.AddrInfo -> m S.Socket
newSocket addr = liftIO $ S.socket (S.addrFamily addr)
(S.addrSocketType addr)
(S.addrProtocol addr)
connectSocks :: (MonadMask m, MonadIO m) => SocksProxy -> Endpoint -> m S.Socket
connectSocks proxy endpoint = liftIO (socksConnectWith proxyConf host port)
where
proxyConf = defaultSocksConf (T.unpack $ epHost proxy)
(fromIntegral $ epPort proxy)
host = T.unpack $ epHost endpoint
port = PortNumber $ fromIntegral $ epPort endpoint