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 import Data
.Version
(showVersion
)
30 import Paths_advlib
(version
)
32 runAdvent
:: MonadIO m
=> ReaderT Manager m b
-> m b
34 liftIO
$ hSetBuffering stdout NoBuffering
35 man
<- liftIO
$ newManager tlsManagerSettings
38 download
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => String -> m
(Response ByteString
)
41 urlreq
<- parseRequest url
44 ("User-Agent", "advlib " <> pack
(show version
) <> " <jlagarespo@protonmail.com>") : requestHeaders urlreq
}
45 session
<- liftIO
$ getEnv "AOC_SESSION"
46 let sessionCookie
= Cookie
47 { cookie_name
= "session"
48 , cookie_value
= pack session
49 , cookie_expiry_time
= future
50 , cookie_domain
= "adventofcode.com"
52 , cookie_creation_time
= past
53 , cookie_last_access_time
= past
54 , cookie_persistent
= False
55 , cookie_host_only
= False
56 , cookie_secure_only
= False
57 , cookie_http_only
= False
59 httpLbs req
{cookieJar
= Just
$ createCookieJar
[sessionCookie
]} man
62 past
= UTCTime
(ModifiedJulianDay
56200) (secondsToDiffTime
0)
63 future
= UTCTime
(ModifiedJulianDay
562000) (secondsToDiffTime
0)
65 getDay
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => Int -> Int -> m
String
67 cached
<- liftIO
$ doesFileExist dayCache
69 then liftIO
$ readFile dayCache
71 liftIO
$ putStrLn $ "Caching " <> show year
<> "/" <> show day
72 liftIO
$ createDirectoryIfMissing
True cacheDir
74 liftIO
$ writeFile dayCache day
79 dayCache
= cacheDir
<> show year
<> "." <> show day
82 day
<- download
$ "https://adventofcode.com/" <> show year
<> "/day/" <> show day
<> "/input"
83 if statusCode
(responseStatus day
) == 200
85 let body
= L
.unpack
. L
.decodeUtf8
. responseBody
88 currentTime
<- liftIO getCurrentTime
89 let estTime
= utcToZonedTime
(hoursToTimeZone
(-5)) currentTime
90 dayTime
= zonedTimeToUTC
$ estTime
{ zonedTimeToLocalTime
= (zonedTimeToLocalTime estTime
) { localTimeOfDay
= midnight
} }
91 dayTime
' | currentTime
> dayTime
= addUTCTime nominalDay dayTime
97 current
<- liftIO getCurrentTime
98 when (current
<= dest
) $ do
99 let remaining
= dest `diffUTCTime` current
100 liftIO
$ putStr $ formatTime
defaultTimeLocale "%H:%M:%S\r" remaining
101 liftIO
$ threadDelay
1000000
104 cacheAllDays
:: (MonadReader Manager m
, MonadIO m
, MonadThrow m
) => m
()
105 cacheAllDays
= sequence_ [getDay year day | year
<- [2015..2021], day
<- [1..25]]