{-# LANGUAGE RecordWildCards #-}

module HOCD
  ( runOCD
  , runOCDConfig
  , module HOCD.Error
  , module HOCD.Monad
  , module HOCD.Types
  ) where

import Control.Monad.Catch (MonadMask)
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.Default.Class (Default(def))

import qualified Control.Monad.Catch
import qualified Network.Socket

import HOCD.Error
import HOCD.Monad
import HOCD.Types

-- | Run OpenOCD client
-- with defaults ("127.0.0.1:6666")
runOCD
  :: ( MonadIO m
     , MonadMask m
     )
  => OCDT m a
  -> m (Either OCDError a)
runOCD :: forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
OCDT m a -> m (Either OCDError a)
runOCD = OCDConfig -> OCDT m a -> m (Either OCDError a)
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
OCDConfig -> OCDT m a -> m (Either OCDError a)
runOCDConfig OCDConfig
forall a. Default a => a
def

-- | Run OpenOCD client with @OCDConfig@
-- allowing to set custom host and port
runOCDConfig
  :: ( MonadIO m
     , MonadMask m
     )
  => OCDConfig
  -> OCDT m a
  -> m (Either OCDError a)
runOCDConfig :: forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
OCDConfig -> OCDT m a -> m (Either OCDError a)
runOCDConfig OCDConfig{Int
String
ocdHost :: String
ocdPort :: Int
ocdHost :: OCDConfig -> String
ocdPort :: OCDConfig -> Int
..} OCDT m a
act = do
  [AddrInfo]
addrInfo <- IO [AddrInfo] -> m [AddrInfo]
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [AddrInfo] -> m [AddrInfo]) -> IO [AddrInfo] -> m [AddrInfo]
forall a b. (a -> b) -> a -> b
$ Maybe AddrInfo -> Maybe String -> Maybe String -> IO [AddrInfo]
Network.Socket.getAddrInfo
    (AddrInfo -> Maybe AddrInfo
forall a. a -> Maybe a
Just AddrInfo
Network.Socket.defaultHints)
    (String -> Maybe String
forall a. a -> Maybe a
Just String
ocdHost)
    (String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show Int
ocdPort)

  case [AddrInfo]
addrInfo of
    (AddrInfo
sockAddr:[AddrInfo]
_) ->
      m Socket
-> (Socket -> m ())
-> (Socket -> m (Either OCDError a))
-> m (Either OCDError a)
forall (m :: * -> *) a c b.
(HasCallStack, MonadMask m) =>
m a -> (a -> m c) -> (a -> m b) -> m b
Control.Monad.Catch.bracket
        (IO Socket -> m Socket
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
          (IO Socket -> m Socket) -> IO Socket -> m Socket
forall a b. (a -> b) -> a -> b
$ Family -> SockAddr -> IO Socket
open
              (AddrInfo -> Family
Network.Socket.addrFamily AddrInfo
sockAddr)
              (AddrInfo -> SockAddr
Network.Socket.addrAddress AddrInfo
sockAddr)
        )
        (IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Socket -> IO ()) -> Socket -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Socket -> IO ()
Network.Socket.close)
        (\Socket
sock -> Socket -> OCDT m a -> m (Either OCDError a)
forall (m :: * -> *) a.
Monad m =>
Socket -> OCDT m a -> m (Either OCDError a)
runOCDT Socket
sock OCDT m a
act)
    [AddrInfo]
_ -> Either OCDError a -> m (Either OCDError a)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OCDError -> Either OCDError a
forall a b. a -> Either a b
Left OCDError
OCDError_GetAddrInfoFailed)
  where
    open :: Family -> SockAddr -> IO Socket
open Family
sockFamily SockAddr
sockAddr = do
      Socket
soc <-
        Family -> SocketType -> ProtocolNumber -> IO Socket
Network.Socket.socket
          Family
sockFamily
          SocketType
Network.Socket.Stream
          ProtocolNumber
Network.Socket.defaultProtocol
      Socket -> SockAddr -> IO ()
Network.Socket.connect Socket
soc SockAddr
sockAddr
      Socket -> IO Socket
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Socket
soc