1 {-# LANGUAGE FlexibleContexts #-}
2 module Advent
(runAdvent
, getDay
, cacheAllDays
) where
4 import Control
.Concurrent
(threadDelay
)
6 import Data
.ByteString
.Char8
(pack
)
7 import Data
.ByteString
.Lazy
(ByteString
)
8 import qualified Data
.Text
.Lazy
as L
9 import qualified Data
.Text
.Lazy
.IO as L
10 import qualified Data
.Text
.Lazy
.Encoding
as L
12 import Data
.Time
.Clock
13 import Data
.Time
.Calendar
14 import Data
.Time
.LocalTime
15 import Data
.Time
.Format
17 import Control
.Monad
.Catch
18 import Control
.Monad
.Reader
20 import System
.Directory
21 import System
.Environment
23 import Network
.HTTP
.Conduit
24 import Network
.HTTP
.Types
25 import Data
.Time
(ZonedTime
(ZonedTime
))
27 import System
.IO (BufferMode(NoBuffering
), hSetBuffering, stdout)
29 runAdvent
:: MonadIO m
=> ReaderT Manager m b
-> m b
31 liftIO
$ hSetBuffering stdout NoBuffering
32 man
<- liftIO
$ newManager tlsManagerSettings
35 download
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => String -> m
(Response ByteString
)
38 req
<- parseRequest url
39 session
<- liftIO
$ getEnv "AOC_SESSION"
40 let sessionCookie
= Cookie
41 { cookie_name
= "session"
42 , cookie_value
= pack session
43 , cookie_expiry_time
= future
44 , cookie_domain
= "adventofcode.com"
46 , cookie_creation_time
= past
47 , cookie_last_access_time
= past
48 , cookie_persistent
= False
49 , cookie_host_only
= False
50 , cookie_secure_only
= False
51 , cookie_http_only
= False
53 httpLbs req
{cookieJar
= Just
$ createCookieJar
[sessionCookie
]} man
56 past
= UTCTime
(ModifiedJulianDay
56200) (secondsToDiffTime
0)
57 future
= UTCTime
(ModifiedJulianDay
562000) (secondsToDiffTime
0)
59 getDay
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => Int -> Int -> m
String
61 cached
<- liftIO
$ (&&) <$> doesFileExist dayCache
<*> doesFileExist inputCache
63 then liftIO
$ readFile dayCache
65 liftIO
$ putStrLn $ "Caching " <> show year
<> "/" <> show day
66 liftIO
$ createDirectoryIfMissing
True cacheDir
68 liftIO
$ writeFile dayCache day
73 dayCache
= cacheDir
<> show year
<> "." <> show day
74 inputCache
= dayCache
<> ".input"
77 day
<- download
$ "https://adventofcode.com/" <> show year
<> "/day/" <> show day
<> "/input"
78 if statusCode
(responseStatus day
) == 200
80 let body
= L
.unpack
. L
.decodeUtf8
. responseBody
83 -- TODO: Check calendar to know how long to wait for!!!
84 currentTime
<- liftIO getCurrentTime
85 let estTime
= utcToZonedTime
(hoursToTimeZone
(-5)) currentTime
86 dayTime
= zonedTimeToUTC
$ estTime
{ zonedTimeToLocalTime
= (zonedTimeToLocalTime estTime
) { localTimeOfDay
= midnight
} }
87 dayTime
' | currentTime
> dayTime
= addUTCTime nominalDay dayTime
93 current
<- liftIO getCurrentTime
94 when (current
<= dest
) $ do
95 let remaining
= dest `diffUTCTime` current
96 liftIO
$ putStr $ formatTime
defaultTimeLocale "%H:%M:%S\r" remaining
97 liftIO
$ threadDelay
1000000
100 cacheAllDays
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => m
()
101 cacheAllDays
= sequence_ [getDay year day | year
<- [2015..2021], day
<- [1..25]]