-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Keep program state in JSON files.
--
@package json-state
@version 0.1.0.0
-- | This module provides a function for loading a state value from a JSON
-- file, and a function which generates a safe scalable saver function.
-- The JSON files are written using the aeson-pretty package, so
-- that they are easy to read and modify manually if needed.
--
-- The save function generator, mkSaveState, returns a function
-- which saves settings when called, but only at most once in t,
-- the time interval passed to the generator. For example, if you pass an
-- interval of 3 seconds, you can safely call the generated save function
-- even 100 times a second, and the JSON file will still get updated just
-- once in 3 seconds, avoiding an overload of file I/O.
--
-- The actual saving happens in a dedicated worker thread, so even when a
-- save does occur, it won't block the caller thread. The generator can
-- be called once at program start, and the returned save function saved
-- in application state.
--
-- mkSaveStateVC works similarly, but additionally provides a
-- saver function which commits the change into a git repo.
--
-- Note that while this simple periodic save-to-file method can serve a
-- simple standalone application well, it won't work if you wish your
-- data to be shared by multiple applications and allow them to read and
-- write it at the same time. If that's the case, check out the
-- acid-state package, and other persistence related packages.
module Data.JsonState
-- | Try to load state from a file.
--
-- If an error occurs, Left a pair is returned. The boolean
-- indicates whether reading the file failed (False) or parsing
-- the content failed (True). The string is an error description.
--
-- If the operation succeeds, Right the loaded state data is
-- returned.
loadState :: FromJSON s => FilePath -> IO (Either (Bool, String) s)
-- | Prepare a save action which writes state into a JSON file. This action
-- defers the work to a separate dedicated thread, and ensures the file
-- isn't saved more than once within the given time interval.
--
-- The action is non-blocking but there is a chance a save is missed if
-- saves are triggered simultaneously from different threads.
--
-- You can call the returned action from your UI thread as a reaction to
-- a state change, without worrying about delay or IO load.
mkSaveState :: (TimeUnit t, ToJSON s) => t -> FilePath -> IO (s -> IO ())
-- | Like mkSaveState, but also takes a repository path. Creates a
-- Git repository there if there isn't yet. Two save actions are
-- returned. The first one simply saves state to a file, just like in
-- mkSaveState. The second one saves to file and then commits it
-- into the Git repository.
--
-- Note that the file path is relative to the repo path. For example, if
-- you have the repo in "homejoerepo" and the file is
-- "homejoerepo/file", pass just "file" as the file path.
mkSaveStateVC :: (TimeUnit t, ToJSON s) => t -> FilePath -> FilePath -> String -> IO (s -> IO (), s -> IO ())
-- | This is a variant which returns a single save action, which either
-- uses or doesn't use a Git repo. If the repo path (3rd argument) is
-- Nothing, then Git isn't used at all and the file path is
-- treated like mkSaveState would. Otherwise, i.e. if a repo path
-- is specified, the returned action will commit changes to the Git repo,
-- and the repo and file path arguments are treated like
-- mkSaveStateVC would, i.e. the file path is relative to the
-- repo.
--
-- If you use this function, also use stateFilePath to determine
-- the correct path to pass to loadState.
mkSaveStateChoose :: (TimeUnit t, ToJSON s) => t -> FilePath -> Maybe FilePath -> String -> IO (s -> IO ())
-- | If you use mkSaveStateChoose to save the state, that function
-- combines the repo path and the file path when needed, to determine the
-- full path of the state file. But then, how do you determine which path
-- to pass to loadState? This is exactly what this function does.
-- Pass it the optional repo path and the file path you passed to
-- mkSaveStateChoose, and you'll get a full path you can pass to
-- loadState.
stateFilePath :: FilePath -> Maybe FilePath -> FilePath