packages feed

lucienne-0.0.1: Lucienne/Fetch/Main.hs

import           Prelude hiding (log)
import           Control.Monad (forM_)
import           Control.Monad.Trans (liftIO)
import           Data.Time.LocalTime (getZonedTime)
import           Data.Bson (ObjectId)
import           Database.MongoDB (runIOE,readHostPort,connect,close)
import qualified Lucienne.Database as DB
import           Lucienne.ConnectionReader (ConnectionReader,runConnectionReader)
import           Lucienne.Fetch (fetchFeed)
import           Lucienne.Fetch.Util (partitionM)
import           Lucienne.Model.User (User)
import qualified Lucienne.Model.User as User
import           Lucienne.Model.Feed (Feed)
import qualified Lucienne.Model.Feed as F
import           Lucienne.Model.FeedItem (FeedItem)
import qualified Lucienne.Model.FeedItem as FI
import           Lucienne.Args (getArgs,dbConnectionString)

main :: IO ()
main = do
  args <- getArgs
  putStrLn $ "Connecting to database " ++ (dbConnectionString args) ++ " ..."
  connection <- runIOE $ connect $ readHostPort $ dbConnectionString args
  runConnectionReader connection fetch
  close connection
  
fetch :: ConnectionReader ()  
fetch = do 
  users <- DB.users
  forM_ users fetchFeedsAndUpdate
  
fetchFeedsAndUpdate :: User -> ConnectionReader ()
fetchFeedsAndUpdate user = do
  feeds <- DB.feedsByUser user
  forM_ feeds $ \f -> do
    log $ concat ["Fetching feed '",F.title f, "' for user '",User.name user,"'"]
    fetchFeedItemsAndUpdate user f
  
fetchFeedItemsAndUpdate :: User -> Feed -> ConnectionReader ()
fetchFeedItemsAndUpdate user feed = 
  let fId  = F.id  feed
      fUrl = F.url feed
  in do
   result <- liftIO $ fetchFeed feed
   case result of
     Left message      -> log $ "Could not fetch feed '" ++ fUrl ++ "' because of: " ++ message
     Right (_,items')  -> 
       let items = map (FI.setOwner user . FI.setFeedId fId) items'
       in do
         (rest,toAdd) <- partitionExistentFeedItems fId items
         log $ concat ["Fetched ", show $ length items," items (",show $ length toAdd," new)"]
                                
         forM_ toAdd DB.upsertFeedItem 
         deleteFeedItems fId rest

partitionExistentFeedItems :: ObjectId -> [FeedItem] -> ConnectionReader ([FeedItem],[FeedItem])
partitionExistentFeedItems feedId =
  partitionM $ \i -> DB.feedItemExists feedId (FI.title i) (FI.url i)

deleteFeedItems :: ObjectId -> [FeedItem] -> ConnectionReader ()
deleteFeedItems feedId feedItems =
  let titlesToRemain = map FI.title feedItems
      urlsToRemain   = map FI.url   feedItems
  in
   DB.deleteMarkedFeedItems feedId titlesToRemain urlsToRemain
   
log :: String -> ConnectionReader ()
log s = do
  time <- liftIO $ getZonedTime
  liftIO $ putStrLn $ concat ["[",show time,"]\t",s]