-- 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