packages feed

imm-0.5.0.0: Imm/Database.hs

module Imm.Database where

-- {{{ Imports
import Imm.Error
import Imm.Options
import Imm.Util

import Control.Monad.Base
import Control.Monad.Error

import Data.Time hiding(parseTime)
import Data.Time.Clock.POSIX

import Network.URI

import System.Directory
import System.FilePath
import System.Locale
import System.IO
-- }}}

-- | A state file stores the last check time for a single feed, identified with its 'URI'.
getStateFile :: URI -> FilePath
getStateFile feedUri@URI{ uriAuthority = Just auth } = toFileName =<< ((++ uriQuery feedUri) . (++ uriPath feedUri) . uriRegName $ auth)
getStateFile feedUri = show feedUri >>= toFileName

-- | Remove forbidden characters in a filename.
toFileName :: Char -> String
toFileName '/' = "."
toFileName '?' = "."
toFileName x = [x]

-- | Read the last check time in the state file.
getLastCheck :: (OptionsReader m, MonadBase IO m) => URI -> m UTCTime
getLastCheck feedUri = do
    directory <- getStateDirectory
    result    <- runErrorT $ do
        content <- try $ readFile (directory </> fileName)
        parseTime content

    either (const $ return timeZero) return result
  where
    fileName = getStateFile feedUri
    timeZero = posixSecondsToUTCTime 0


-- | Write the last check time in the state file.
storeLastCheck :: (OptionsReader m, MonadBase IO m, MonadError ImmError m) => URI -> UTCTime -> m ()
storeLastCheck feedUri date = do
    directory <- getStateDirectory

    (file, stream) <- try $ openTempFile directory fileName
    io $ hPutStrLn stream (formatTime defaultTimeLocale "%c" date)
    io $ hClose stream
    try $ renameFile file (directory </> fileName)
  where
    fileName = getStateFile feedUri


forget :: (OptionsReader m, MonadBase IO m, MonadError ImmError m) => URI -> m ()
forget uri = do
    directory <- getStateDirectory
    try $ removeFile (directory </> getStateFile uri)