module Database.Bolt.Transport.Socket
( ConnInfo
, hostserv
, uri
, Connection
, connect
, close
, send
, sendMany
, recv
, put
, get
) where
import Control.Exception
import Control.Monad
import Data.Monoid
import qualified Data.Text as T
import qualified Network.Socket as Net
import qualified Network.Socket.ByteString as NetBS
import Network.URI
import Database.Bolt.Exception
import Database.Bolt.Transport
newtype Connection = Connection { connSocket :: Net.Socket }
instance Transport Connection where
send = NetBS.sendAll . connSocket
sendMany = NetBS.sendMany . connSocket
recv = NetBS.recv . connSocket
close = Net.close . connSocket
data ConnInfo = ConnInfo
{ connHost :: Net.HostName
, connService :: Net.ServiceName
} deriving (Show, Read, Eq, Ord)
hostserv :: String -> String -> ConnInfo
hostserv = ConnInfo
uri :: String -> Maybe ConnInfo
uri uristr = do
uri' <- parseAbsoluteURI uristr
guard $ uriScheme uri' == "bolt"
auth <- uriAuthority uri'
guard $ uriUserInfo auth == ""
guard $ uriPath uri' == ""
guard $ uriQuery uri' == ""
guard $ uriFragment uri' == ""
return ConnInfo { connHost = uriRegName auth
, connService = uriPort auth }
connect :: ConnInfo -> IO Connection
connect ConnInfo{..} = do
let hints = Net.defaultHints { Net.addrSocketType = Net.Stream }
addrs <- Net.getAddrInfo (Just hints) (Just connHost) (Just connService)
connectAny addrs
where
connectAny [] = transportErr $ "Unable to connect to " <> T.pack connHost <> ":" <> T.pack connService
connectAny (addr:addrs) = doConnect addr `catch` (\ (_ :: IOException) -> connectAny addrs)
doConnect addr = do
sock <- Net.socket (Net.addrFamily addr) (Net.addrSocketType addr) (Net.addrProtocol addr)
Net.connect sock (Net.addrAddress addr) `onException` Net.close sock
return $ Connection sock