content: {-# LANGUAGE CPP #-}
  
  module PostgREST.Unix
    ( installSignalHandlers
    , createAndBindDomainSocket
    ) where
  
  #ifndef mingw32_HOST_OS
  import qualified System.Posix.Signals as Signals
  #endif
  import System.Posix.Types       (FileMode)
  import System.PosixCompat.Files (setFileMode)
  
  import           Data.String      (String)
  import qualified Network.Socket   as NS
  import           Protolude
  import           System.Directory (removeFile)
  import           System.IO.Error  (isDoesNotExistError)
  
  -- | Set signal handlers, only for systems with signals
  installSignalHandlers :: ThreadId -> IO () -> IO () -> IO ()
  #ifndef mingw32_HOST_OS
  installSignalHandlers tid usr1 usr2 = do
    let interrupt = throwTo tid UserInterrupt
    install Signals.sigINT interrupt
    install Signals.sigTERM interrupt
    install Signals.sigUSR1 usr1
    install Signals.sigUSR2 usr2
    where
      install signal handler =
        void $ Signals.installHandler signal (Signals.Catch handler) Nothing
  #else
  installSignalHandlers _ _ _ = pass
  #endif
  
  -- | Create a unix domain socket and bind it to the given path.
  -- | The socket file will be deleted if it already exists.
  createAndBindDomainSocket :: String -> FileMode -> IO NS.Socket
  createAndBindDomainSocket path mode = do
    unless NS.isUnixDomainSocketAvailable $
      panic "Cannot run with unix socket on non-unix platforms. Consider deleting the `server-unix-socket` config entry in order to continue."
    deleteSocketFileIfExist path
    sock <- NS.socket NS.AF_UNIX NS.Stream NS.defaultProtocol
    NS.bind sock $ NS.SockAddrUnix path
    NS.listen sock (max 2048 NS.maxListenQueue)
    setFileMode path mode
    return sock
    where
      deleteSocketFileIfExist path' =
        removeFile path' `catch` handleDoesNotExist
      handleDoesNotExist e
        | isDoesNotExistError e = return ()
        | otherwise = throwIO e
  