packages feed

cached-json-file (empty) → 0.1.0

raw patch · 5 files changed

+185/−0 lines, 5 filesdep +aesondep +basedep +bytestring

Dependencies added: aeson, base, bytestring, directory, filepath, http-query, time, xdg-basedir

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Version history for cached-json-file++## 0.1.0 (2021-07-29)+- initial release with getCachedJSON and getCachedJSONQuery+- exports lookupKey from http-query
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2021, Jens Petersen++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Jens Petersen nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,35 @@+# cached-json-file++A Haskell library providing a cached json file.++Useful for frequently used programs that use some remote json data+which changes rather slowly (like in hours, days, weeks or months),+where it is not critical to have always the latest data immediately.++## Usage++`getCachedJSON dir file url minutes` caches the json obtained from `url` in+`~/.cache/dir/file` for `minutes`.++eg:++```haskell+import System.Cached.JSON++getSnapshots :: IO Object+getSnapshots =+  getCachedJSON "stackage-snapshots" "snapshots.json" "http://haddock.stackage.org/snapshots.json" 180++main = getSnapshots >>= print+```++Each time you run this program within 3 hours the data will be read+from the local cache file `~/.cache/stackage-snapshots/snapshots.json`+rather than re-downloading it each time,+which helps to speed up the program and avoid unnecessary web queries.++There is also `getCachedJSONQuery prog jsonfile webquery minutes`+which uses `webquery :: (FromJSON a, ToJSON a) => IO a` to download+the json data.++Currently the smallest possible cache time is 1 minute.
+ cached-json-file.cabal view
@@ -0,0 +1,54 @@+name:                cached-json-file+version:             0.1.0+synopsis:            Locally cache a json file obtained by http+description:+        A small library for caching a slow-changing remote json file in+        a specified directory (under "~\/.cache\/").  When the json is requested+        and the cache file is still fresh enough it is read directly from+        the local cache, otherwise the cached file is refreshed first.+license:             BSD3+license-file:        LICENSE+author:              Jens Petersen <juhpetersen@gmail.com>+maintainer:          Jens Petersen <juhpetersen@gmail.com>+copyright:           2021  Jens Petersen <juhpetersen@gmail.com>+category:            Network+homepage:            https://github.com/juhp/cached-json-file+bug-reports:         https://github.com/juhp/cached-json-file/issues+build-type:          Simple+extra-doc-files:     README.md+                     ChangeLog.md+cabal-version:       2.0+tested-with:         GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4,+                     GHC == 8.10.4, GHC == 9.0.1++source-repository head+  type:                git+  location:            https://github.com/juhp/cached-json-file.git++library+  build-depends:       base < 5,+                       aeson,+                       bytestring,+                       directory,+                       filepath,+                       http-query,+                       time,+                       xdg-basedir+  default-language:    Haskell2010+  exposed-modules:     System.Cached.JSON+  hs-source-dirs:      src++  ghc-options:         -Wall+  if impl(ghc >= 8.0)+    ghc-options:       -Wcompat+                       -Widentities+                       -Wincomplete-uni-patterns+                       -Wincomplete-record-updates+                       -Wredundant-constraints+  if impl(ghc >= 8.2)+    ghc-options:       -fhide-source-paths+  if impl(ghc >= 8.4)+    ghc-options:       -Wmissing-export-lists+                       -Wpartial-fields+  if impl(ghc >= 8.10)+    ghc-options:       -Wunused-packages
+ src/System/Cached/JSON.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}++module System.Cached.JSON (+  getCachedJSON,+  getCachedJSONQuery,+  lookupKey+  )+where++import Control.Monad+import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as B+import Data.Time.Clock (diffUTCTime, getCurrentTime, NominalDiffTime)+import Network.HTTP.Query+import System.Directory+import System.Environment.XDG.BaseDir+import System.FilePath++-- FIXME handle network failure++-- | If the local cached json file is new enough then use it,+-- otherwise refresh from the remote url.+getCachedJSON :: (FromJSON a, ToJSON a)+              => String -- ^ subdirectory/program name+              -> FilePath -- ^ filename+              -> String -- ^ json url+              -> NominalDiffTime -- ^ cache duration (minutes)+              -> IO a+getCachedJSON prog jsonfile url =+  getCachedJSONQuery prog jsonfile (webAPIQuery url [])++-- | Similar to getCachedJSON but takes an IO procedure that fetches+-- the remote json data.+getCachedJSONQuery :: (FromJSON a, ToJSON a)+                   => String -- ^ program name+                   -> FilePath -- ^ filename+                   -> IO a -- ^ http query+                   -> NominalDiffTime -- ^ cache duration (minutes)+                   -> IO a+getCachedJSONQuery prog jsonfile webquery minutes = do+  file <- getUserCacheFile prog jsonfile+  exists <- doesFileExist file+  unless exists $ do+    putStrLn $ "Creating " ++ file ++ " ..."+    createDirectoryIfMissing True (takeDirectory file)+  recent <- do+    if exists then do+      ts <- getModificationTime file+      t <- getCurrentTime+      return $ diffUTCTime t ts < (minutes * 60)+      else return False+  if recent+    then do+    eObj <- eitherDecode <$> B.readFile file+    case eObj of+      Left err -> error err+      Right obj -> return obj+    else do+    obj <- webquery+    B.writeFile file $ encode obj+    return obj