diff options
Diffstat (limited to 'lib/Postdelay/Scan.hs')
-rw-r--r-- | lib/Postdelay/Scan.hs | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/lib/Postdelay/Scan.hs b/lib/Postdelay/Scan.hs index fba9f35..2f0a78a 100644 --- a/lib/Postdelay/Scan.hs +++ b/lib/Postdelay/Scan.hs | |||
@@ -1,4 +1,4 @@ | |||
1 | {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts, RecordWildCards, ViewPatterns #-} | 1 | {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts, RecordWildCards, ViewPatterns, TupleSections #-} |
2 | 2 | ||
3 | module Postdelay.Scan | 3 | module Postdelay.Scan |
4 | ( scan | 4 | ( scan |
@@ -45,24 +45,29 @@ scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay) | |||
45 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" | 45 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" |
46 | 46 | ||
47 | extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) | 47 | extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) |
48 | extractDelay (Message headers _) | 48 | extractDelay (Message headers _) = do |
49 | = let latestCtx = maximumBy (comparing baseTime) dateHeaders | 49 | zones <- zoneHeaders |
50 | in foldMap pure <$> mapM (flip runReaderT latestCtx . parseDelay) delayHeaders | 50 | let (baseTime, dateTz) = maximumBy (comparing fst) dateHeaders |
51 | tz = foldr' (flip (<>)) (Left dateTz) zones | ||
52 | foldMap pure <$> mapM (flip runReaderT TimeCtx{..} . parseDelay) delayHeaders | ||
51 | where | 53 | where |
52 | delayHeaders :: [Field] | 54 | delayHeaders :: [Field] |
53 | delayHeaders = do | 55 | delayHeaders = do |
54 | (OptionalField field content) <- headers | 56 | (OptionalField field content) <- headers |
55 | guard $ CI.mk field == "X-Delay" | 57 | guard $ CI.mk field == "X-Delay" |
56 | return . OptionalField field $ decodeWords content | 58 | return . OptionalField field $ decodeWords content |
57 | dateHeaders :: [TimeCtx] | 59 | dateHeaders :: [(UTCTime, TimeZone)] |
58 | dateHeaders = do | 60 | dateHeaders = do |
59 | (Date CalendarTime{..}) <- headers | 61 | (Date CalendarTime{..}) <- headers |
60 | let tz = minutesToTimeZone . round $ ctTZ % 60 | 62 | let tz = minutesToTimeZone . round $ ctTZ % 60 |
61 | return $ TimeCtx | 63 | return . (, tz) . localTimeToUTC tz $ LocalTime |
62 | { baseTime = localTimeToUTC tz $ LocalTime | 64 | (fromGregorian (fromIntegral ctYear) (fromEnum ctMonth + 1) ctDay) |
63 | (fromGregorian (fromIntegral ctYear) (fromEnum ctMonth + 1) ctDay) | 65 | (TimeOfDay ctHour ctMin $ fromIntegral ctSec + fromIntegral ctPicosec * 1e-12) |
64 | (TimeOfDay ctHour ctMin $ fromIntegral ctSec + fromIntegral ctPicosec * 1e-12) | 66 | zoneHeaders :: m [Either TimeZone TZ] |
65 | , tz = Left tz | 67 | zoneHeaders = runListT $ do |
66 | } | 68 | (OptionalField field content) <- ListT $ return headers |
69 | guard $ CI.mk field == "X-Timezone" | ||
70 | Right r <- runParserT (spaces *> pTimeZone <* spaces <* eof) () field content | ||
71 | return r | ||
67 | parseDelay :: Field -> ReaderT TimeCtx m Delay | 72 | parseDelay :: Field -> ReaderT TimeCtx m Delay |
68 | parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content | 73 | parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content |