packages feed

advent-of-code-api-0.2.12.0: src/Advent/Cache.hs

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RecordWildCards #-}

-- |
-- Module      : Advent.Throttle
-- Copyright   : (c) Justin Le 2018
-- License     : BSD3
--
-- Maintainer  : justin@jle.im
-- Stability   : experimental
-- Portability : non-portable
--
-- (Internal) Implement cacheing of API requests.
module Advent.Cache (
  cacheing,
  SaverLoader (..),
  noCache,
) where

import Control.DeepSeq
import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Data.Text (Text)
import qualified Data.Text.IO as T
import System.Directory
import System.FilePath
import System.IO.Error

data SaverLoader a
  = SL
  { _slSave :: a -> Maybe Text
  , _slLoad :: Text -> Maybe a
  }

noCache :: SaverLoader a
noCache = SL (const Nothing) (const Nothing)

cacheing ::
  MonadIO m =>
  FilePath ->
  SaverLoader a ->
  m a ->
  m a
cacheing fp SL{..} act = do
  old <- liftIO $ do
    createDirectoryIfMissing True (takeDirectory fp)
    (_slLoad =<<) <$> readFileMaybe fp
  case old of
    Nothing -> do
      r <- act
      liftIO . mapM_ (T.writeFile fp) $ _slSave r
      pure r
    Just o -> pure o

readFileMaybe :: FilePath -> IO (Maybe Text)
readFileMaybe =
  (traverse (evaluate . force) . either (const Nothing) Just)
    <=< (tryJust (guard . isDoesNotExistError) . T.readFile)