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 |
