{-# 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 [String] -> IO ()
relaunchMaster Maybe [String]
otherArgs = do
String
masterPath <- (Maybe String -> String) -> IO (Maybe String) -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (String -> Maybe String -> String)
-> String -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. HasCallStack => String -> a
error String
"'dyre' data-store doesn't exist (in Config.Dyre.Relaunch.relaunchMaster)") IO (Maybe String)
getMasterBinary
String -> Maybe [String] -> IO ()
forall a. String -> Maybe [String] -> IO a
customExec String
masterPath Maybe [String]
otherArgs
relaunchWithTextState :: Show a => a -> Maybe [String] -> IO ()
relaunchWithTextState :: a -> Maybe [String] -> IO ()
relaunchWithTextState a
state Maybe [String]
otherArgs = do
a -> IO ()
forall a. Show a => a -> IO ()
saveTextState a
state
Maybe [String] -> IO ()
relaunchMaster Maybe [String]
otherArgs
relaunchWithBinaryState :: Binary a => a -> Maybe [String] -> IO ()
relaunchWithBinaryState :: a -> Maybe [String] -> IO ()
relaunchWithBinaryState a
state Maybe [String]
otherArgs = do
a -> IO ()
forall a. Binary a => a -> IO ()
saveBinaryState a
state
Maybe [String] -> IO ()
relaunchMaster Maybe [String]
otherArgs
genStatePath :: IO FilePath
genStatePath :: IO String
genStatePath = do
String
pidString <- IO String
getPIDString
String
tempDir <- IO String
getTemporaryDirectory
let statePath :: String
statePath = String
tempDir String -> String -> String
</> String
pidString String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".state"
String -> String -> String -> IO ()
forall a. Typeable a => String -> String -> a -> IO ()
putValue String
"dyre" String
"persistState" String
statePath
String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
statePath
saveTextState :: Show a => a -> IO ()
saveTextState :: a -> IO ()
saveTextState a
state = do
String
statePath <- IO String
genStatePath
String -> String -> IO ()
writeFile String
statePath (String -> IO ()) -> (a -> String) -> a -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show (a -> IO ()) -> a -> IO ()
forall a b. (a -> b) -> a -> b
$ a
state
saveBinaryState :: Binary a => a -> IO ()
saveBinaryState :: a -> IO ()
saveBinaryState a
state = do
String
statePath <- IO String
genStatePath
String -> Maybe a -> IO ()
forall a. Binary a => String -> a -> IO ()
encodeFile String
statePath (Maybe a -> IO ()) -> (a -> Maybe a) -> a -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe a
forall a. a -> Maybe a
Just (a -> IO ()) -> a -> IO ()
forall a b. (a -> b) -> a -> b
$ a
state
restoreTextState :: Read a => a -> IO a
restoreTextState :: a -> IO a
restoreTextState a
d = do
Maybe String
statePath <- IO (Maybe String)
getStatePersist
case Maybe String
statePath of
Maybe String
Nothing -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Just String
sp -> do
String
stateData <- String -> IO String
readFile String
sp
Either SomeException a
result <- IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO a -> IO (Either SomeException a))
-> IO a -> IO (Either SomeException a)
forall a b. (a -> b) -> a -> b
$ String -> IO a
forall a. Read a => String -> IO a
readIO String
stateData
case Either SomeException a
result of
Left (SomeException
_ :: SomeException) -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Right a
v -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
v
restoreBinaryState :: Binary a => a -> IO a
restoreBinaryState :: a -> IO a
restoreBinaryState a
d = do
Maybe String
statePath <- IO (Maybe String)
getStatePersist
case Maybe String
statePath of
Maybe String
Nothing -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
Just String
sp -> do Maybe a
state <- String -> IO (Maybe a)
forall a. Binary a => String -> IO a
decodeFile String
sp
a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$ a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
d Maybe a
state