module Program.Mighty.Network (
    daemonize,
) where

import Control.Monad
import System.Exit
import System.Posix

-- | Run a program detaching its terminal.
daemonize :: IO () -> IO ()
daemonize :: IO () -> IO ()
daemonize IO ()
program = IO () -> IO ()
forall {b}. IO () -> IO b
ensureDetachTerminalCanWork (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    IO ()
detachTerminal
    IO () -> IO ()
forall {b}. IO () -> IO b
ensureNeverAttachTerminal (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        FilePath -> IO ()
changeWorkingDirectory FilePath
"/"
        IO FileMode -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO FileMode -> IO ()) -> IO FileMode -> IO ()
forall a b. (a -> b) -> a -> b
$ FileMode -> IO FileMode
setFileCreationMask FileMode
0
        (Fd -> IO ()) -> [Fd] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Fd -> IO ()
closeFd [Fd
stdInput, Fd
stdOutput, Fd
stdError]
        IO ()
program
  where
    ensureDetachTerminalCanWork :: IO () -> IO b
ensureDetachTerminalCanWork IO ()
p = do
        IO ProcessID -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ProcessID -> IO ()) -> IO ProcessID -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ProcessID
forkProcess IO ()
p
        IO b
forall a. IO a
exitSuccess
    ensureNeverAttachTerminal :: IO () -> IO b
ensureNeverAttachTerminal IO ()
p = do
        IO ProcessID -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ProcessID -> IO ()) -> IO ProcessID -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ProcessID
forkProcess IO ()
p
        IO b
forall a. IO a
exitSuccess
    detachTerminal :: IO ()
detachTerminal = IO ProcessID -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void IO ProcessID
createSession