{-# LANGUAGE ScopedTypeVariables #-}
module Config.Dyre.Relaunch
( relaunchMaster
, relaunchWithTextState
, relaunchWithBinaryState
, saveTextState
, saveBinaryState
, restoreTextState
, restoreBinaryState
) where
import Data.Maybe ( fromMaybe )
import System.IO ( writeFile, readFile )
import Data.Binary ( Binary, encodeFile, decodeFile )
import Control.Exception ( try, SomeException )
import System.FilePath ( (</>) )
import System.Directory ( getTemporaryDirectory )
import System.IO.Storage ( putValue )
import Config.Dyre.Options ( getMasterBinary, getStatePersist )
import Config.Dyre.Compat ( customExec, getPIDString )
relaunchMaster :: Maybe [String] -> IO ()
relaunchMaster :: Maybe [FilePath] -> IO ()
relaunchMaster Maybe [FilePath]
otherArgs = do
masterPath <- (Maybe FilePath -> FilePath) -> IO (Maybe FilePath) -> IO FilePath
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath -> Maybe FilePath -> FilePath
forall a. a -> Maybe a -> a
fromMaybe (FilePath -> Maybe FilePath -> FilePath)
-> FilePath -> Maybe FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
forall a. HasCallStack => FilePath -> a
error FilePath
"'dyre' data-store doesn't exist (in Config.Dyre.Relaunch.relaunchMaster)") IO (Maybe FilePath)
getMasterBinary
customExec masterPath otherArgs
relaunchWithTextState :: Show a => a -> Maybe [String] -> IO ()
relaunchWithTextState :: forall a. Show a => a -> Maybe [FilePath] -> IO ()
relaunchWithTextState a
state Maybe [FilePath]
otherArgs = do
a -> IO ()
forall a. Show a => a -> IO ()
saveTextState a
state
Maybe [FilePath] -> IO ()
relaunchMaster Maybe [FilePath]
otherArgs
relaunchWithBinaryState :: Binary a => a -> Maybe [String] -> IO ()
relaunchWithBinaryState :: forall a. Binary a => a -> Maybe [FilePath] -> IO ()
relaunchWithBinaryState a
state Maybe [FilePath]
otherArgs = do
a -> IO ()
forall a. Binary a => a -> IO ()
saveBinaryState a
state
Maybe [FilePath] -> IO ()
relaunchMaster Maybe [FilePath]
otherArgs
genStatePath :: IO FilePath
genStatePath :: IO FilePath
genStatePath = do
pidString <- IO FilePath
getPIDString
tempDir <- getTemporaryDirectory
let statePath = FilePath
tempDir FilePath -> FilePath -> FilePath
</> FilePath
pidString FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
".state"
putValue "dyre" "persistState" statePath
return statePath
saveTextState :: Show a => a -> IO ()
saveTextState :: forall a. Show a => a -> IO ()
saveTextState a
state = do
statePath <- IO FilePath
genStatePath
writeFile statePath . show $ state
saveBinaryState :: Binary a => a -> IO ()
saveBinaryState :: forall a. Binary a => a -> IO ()
saveBinaryState a
state = do
statePath <- IO FilePath
genStatePath
encodeFile statePath . Just $ state
restoreTextState :: Read a => a -> IO a
restoreTextState :: forall a. Read a => a -> IO a
restoreTextState a
d = do
statePath <- IO (Maybe FilePath)
getStatePersist
case statePath of
Maybe FilePath
Nothing -> a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Just FilePath
sp -> do
stateData <- FilePath -> IO FilePath
readFile FilePath
sp
result <- try $ readIO stateData
case result of
Left (SomeException
_ :: SomeException) -> a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Right a
v -> a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
v
restoreBinaryState :: Binary a => a -> IO a
restoreBinaryState :: forall a. Binary a => a -> IO a
restoreBinaryState a
d = do
statePath <- IO (Maybe FilePath)
getStatePersist
case statePath of
Maybe FilePath
Nothing -> a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Just FilePath
sp -> do state <- FilePath -> IO (Maybe a)
forall a. Binary a => FilePath -> IO a
decodeFile FilePath
sp
return $ fromMaybe d state