diff options
author | Gregor Kleen <aethoago@141.li> | 2017-01-29 01:21:09 +0100 |
---|---|---|
committer | Gregor Kleen <aethoago@141.li> | 2017-01-29 01:21:09 +0100 |
commit | 636bf21caf774a6eef4e678b79bad524c9ef3b01 (patch) | |
tree | 6aad0810c7ba1e935cb0f263080a4123dc726725 /lib/Postdelay/Scan.hs | |
parent | 067c9c10e08bc48678687996945b35fa921229f4 (diff) | |
download | postdelay-636bf21caf774a6eef4e678b79bad524c9ef3b01.tar postdelay-636bf21caf774a6eef4e678b79bad524c9ef3b01.tar.gz postdelay-636bf21caf774a6eef4e678b79bad524c9ef3b01.tar.bz2 postdelay-636bf21caf774a6eef4e678b79bad524c9ef3b01.tar.xz postdelay-636bf21caf774a6eef4e678b79bad524c9ef3b01.zip |
Feature complete time specification
Diffstat (limited to 'lib/Postdelay/Scan.hs')
-rw-r--r-- | lib/Postdelay/Scan.hs | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/lib/Postdelay/Scan.hs b/lib/Postdelay/Scan.hs index e6de0cf..fba9f35 100644 --- a/lib/Postdelay/Scan.hs +++ b/lib/Postdelay/Scan.hs | |||
@@ -1,4 +1,4 @@ | |||
1 | {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts #-} | 1 | {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts, RecordWildCards, ViewPatterns #-} |
2 | 2 | ||
3 | module Postdelay.Scan | 3 | module Postdelay.Scan |
4 | ( scan | 4 | ( scan |
@@ -12,13 +12,17 @@ import Postdelay.TimeSpec | |||
12 | 12 | ||
13 | import Control.Monad | 13 | import Control.Monad |
14 | import Control.Monad.IO.Class | 14 | import Control.Monad.IO.Class |
15 | import Control.Monad.Error.Class | 15 | import Control.Monad.Except |
16 | import Control.Monad.Reader | ||
17 | import Control.Monad.List | ||
18 | import Control.Exception.Base | ||
16 | 19 | ||
17 | import Text.Parsec.Char | 20 | import Text.Parsec.Char |
18 | import Text.Parsec.Prim | 21 | import Text.Parsec.Prim |
19 | import Text.Parsec.Combinator | 22 | import Text.Parsec.Combinator |
20 | import Text.Parsec.Error (ParseError(..)) | 23 | import Text.Parsec.Error (ParseError(..)) |
21 | import Text.ParserCombinators.Parsec.Rfc2822 | 24 | import Text.ParserCombinators.Parsec.Rfc2822 |
25 | import Codec.MIME.Decode (decodeWords) | ||
22 | 26 | ||
23 | import Data.CaseInsensitive (CI) | 27 | import Data.CaseInsensitive (CI) |
24 | import qualified Data.CaseInsensitive as CI | 28 | import qualified Data.CaseInsensitive as CI |
@@ -26,18 +30,39 @@ import qualified Data.CaseInsensitive as CI | |||
26 | import Data.Either | 30 | import Data.Either |
27 | import Data.Foldable | 31 | import Data.Foldable |
28 | import Data.Semigroup | 32 | import Data.Semigroup |
33 | import Data.Time | ||
34 | import Data.List | ||
35 | import Data.Ord | ||
36 | import Data.Ratio | ||
37 | |||
38 | import Data.Time.Zones | ||
39 | import System.Time (CalendarTime(..)) | ||
40 | |||
41 | import Debug.Trace | ||
29 | 42 | ||
30 | 43 | ||
31 | scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay) | 44 | scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay) |
32 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" | 45 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" |
33 | 46 | ||
34 | 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) |
35 | extractDelay (Message headers _) = foldMap pure <$> mapM parseDelay delayHeaders | 48 | extractDelay (Message headers _) |
49 | = let latestCtx = maximumBy (comparing baseTime) dateHeaders | ||
50 | in foldMap pure <$> mapM (flip runReaderT latestCtx . parseDelay) delayHeaders | ||
36 | where | 51 | where |
37 | delayHeaders :: [Field] | 52 | delayHeaders :: [Field] |
38 | delayHeaders = do | 53 | delayHeaders = do |
39 | h@(OptionalField field content) <- headers | 54 | (OptionalField field content) <- headers |
40 | guard $ CI.mk field == "X-Delay" | 55 | guard $ CI.mk field == "X-Delay" |
41 | return h | 56 | return . OptionalField field $ decodeWords content |
42 | parseDelay :: Field -> m Delay | 57 | dateHeaders :: [TimeCtx] |
58 | dateHeaders = do | ||
59 | (Date CalendarTime{..}) <- headers | ||
60 | let tz = minutesToTimeZone . round $ ctTZ % 60 | ||
61 | return $ TimeCtx | ||
62 | { baseTime = localTimeToUTC tz $ LocalTime | ||
63 | (fromGregorian (fromIntegral ctYear) (fromEnum ctMonth + 1) ctDay) | ||
64 | (TimeOfDay ctHour ctMin $ fromIntegral ctSec + fromIntegral ctPicosec * 1e-12) | ||
65 | , tz = Left tz | ||
66 | } | ||
67 | parseDelay :: Field -> ReaderT TimeCtx m Delay | ||
43 | parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content | 68 | parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content |