diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Postdelay/Scan.hs | 27 | ||||
| -rw-r--r-- | lib/Postdelay/TimeSpec.hs | 7 |
2 files changed, 21 insertions, 13 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 |
diff --git a/lib/Postdelay/TimeSpec.hs b/lib/Postdelay/TimeSpec.hs index af8d801..676dabf 100644 --- a/lib/Postdelay/TimeSpec.hs +++ b/lib/Postdelay/TimeSpec.hs | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | module Postdelay.TimeSpec | 3 | module Postdelay.TimeSpec |
| 4 | ( pTimeSpec | 4 | ( pTimeSpec |
| 5 | , pTimeZone | ||
| 5 | , TimeCtx(..) | 6 | , TimeCtx(..) |
| 6 | ) where | 7 | ) where |
| 7 | 8 | ||
| @@ -308,7 +309,7 @@ pTimeBase = choice' [ do | |||
| 308 | pMinute = ensure (< 60) =<< natural | 309 | pMinute = ensure (< 60) =<< natural |
| 309 | pSecond = decimal | 310 | pSecond = decimal |
| 310 | 311 | ||
| 311 | pTimeZone :: MonadTP m => ParsecT String () m (Either TimeZone TZ) | 312 | pTimeZone :: MonadIO m => ParsecT String () m (Either TimeZone TZ) |
| 312 | pTimeZone = choice' [ do | 313 | pTimeZone = choice' [ do |
| 313 | sgn <- choice [ id <$ char '+' | 314 | sgn <- choice [ id <$ char '+' |
| 314 | , negate <$ char '-' | 315 | , negate <$ char '-' |
| @@ -317,7 +318,9 @@ pTimeZone = choice' [ do | |||
| 317 | ms <- option 0 $ (\d u -> 10 * d + u) <$> digit <*> digit | 318 | ms <- option 0 $ (\d u -> 10 * d + u) <$> digit <*> digit |
| 318 | return . Left . minutesToTimeZone $ hs * 60 + ms | 319 | return . Left . minutesToTimeZone $ hs * 60 + ms |
| 319 | , do | 320 | , do |
| 320 | n <- many1 $ letter <|> char '/' | 321 | let |
| 322 | ident = (++) <$> many1 alphaNum <*> option "" ((:) <$> oneOf "_-/.+" <*> ident) | ||
| 323 | n <- ident | ||
| 321 | tz <- liftIO $ do | 324 | tz <- liftIO $ do |
| 322 | let | 325 | let |
| 323 | fbHandler :: IO a -> (IOException -> IO a) | 326 | fbHandler :: IO a -> (IOException -> IO a) |
