ef5eda4015
Use the Data.Time package to implement the isToday predicate.
103 lines
3.4 KiB
Haskell
103 lines
3.4 KiB
Haskell
{-# LANGUAGE NamedFieldPuns #-}
|
|
module Main (main) where
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Dependencies
|
|
--------------------------------------------------------------------------------
|
|
|
|
import qualified Data.Maybe as Maybe
|
|
import qualified Data.Time.Clock as Clock
|
|
import qualified Data.Time.Calendar as Calendar
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Types
|
|
--------------------------------------------------------------------------------
|
|
|
|
newtype URL = URL { getURL :: String } deriving (Show)
|
|
|
|
newtype IPAddress = IPAddress { getIPAddress :: String } deriving (Show)
|
|
|
|
newtype Domain = Domain { getDomain :: String } deriving (Show)
|
|
|
|
newtype Hour = Hour { getHour :: Integer }
|
|
|
|
newtype Minute = Minute { getMinute :: Integer }
|
|
|
|
data EtcHostEntry = EtcHostEntry { ip :: IPAddress
|
|
, domains :: [Domain]
|
|
} deriving (Show)
|
|
|
|
data TimeRange = TimeRange { beg :: (Hour, Minute)
|
|
, end :: (Hour, Minute)
|
|
}
|
|
|
|
data Allowance = Allowance { day :: Calendar.DayOfWeek
|
|
, timeslots :: [TimeRange]
|
|
}
|
|
|
|
data Rule = Rule { urls :: [URL]
|
|
, allowed :: [Allowance]
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Functions
|
|
--------------------------------------------------------------------------------
|
|
|
|
isToday :: Clock.UTCTime -> Calendar.DayOfWeek -> Bool
|
|
isToday date day = Calendar.dayOfWeek (Clock.utctDay date) == day
|
|
|
|
isAllowed :: Clock.UTCTime -> [Allowance] -> Bool
|
|
isAllowed _ [] = False
|
|
isAllowed date xs = do
|
|
let rules = filter (isToday date . day) xs
|
|
case rules of
|
|
[day] -> True
|
|
[] -> False
|
|
-- Error when more than one rule per day
|
|
_ -> False
|
|
|
|
serializeEntry :: EtcHostEntry -> String
|
|
serializeEntry EtcHostEntry{ip, domains} =
|
|
(getIPAddress ip) ++ "\t" ++ (unwords $ fmap getDomain domains)
|
|
|
|
toEtcHostEntry :: Clock.UTCTime -> Rule -> Maybe EtcHostEntry
|
|
toEtcHostEntry date Rule{urls, allowed} =
|
|
if isAllowed date allowed then
|
|
Nothing
|
|
else
|
|
Just $ EtcHostEntry { ip = IPAddress "127.0.0.1"
|
|
, domains = fmap (Domain . getURL) urls
|
|
}
|
|
|
|
-- | Location of the rules.json file.
|
|
rulesFile :: FilePath
|
|
rulesFile =
|
|
"~/.config/website-blocker/rules.json"
|
|
|
|
-- | Reads and parses JSON from `rulesFile` and returns the result.
|
|
getRules :: IO [Rule]
|
|
getRules = pure $
|
|
[ Rule { urls = [ URL "facebook.com"
|
|
, URL "twitter.com"
|
|
, URL "youtube.com"
|
|
, URL "instagram.com"
|
|
]
|
|
, allowed = []
|
|
}
|
|
, Rule { urls = [ URL "chat.googleplex.com" ]
|
|
, allowed = [ Allowance { day = Calendar.Saturday
|
|
, timeslots = [ TimeRange { beg = (Hour 0, Minute 0)
|
|
, end = (Hour 0, Minute 0)
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
main :: IO ()
|
|
main = do
|
|
rules <- getRules
|
|
date <- Clock.getCurrentTime
|
|
let etcHosts = unlines . fmap serializeEntry . Maybe.catMaybes $ fmap (toEtcHostEntry date) rules
|
|
putStrLn etcHosts
|