diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Postdelay/Scan.hs | 43 | ||||
-rw-r--r-- | lib/Postdelay/TimeSpec.hs | 14 | ||||
-rw-r--r-- | lib/Postdelay/Types.hs | 13 | ||||
-rw-r--r-- | lib/Postdelay/Utils.hs | 21 |
4 files changed, 91 insertions, 0 deletions
diff --git a/lib/Postdelay/Scan.hs b/lib/Postdelay/Scan.hs new file mode 100644 index 0000000..e6de0cf --- /dev/null +++ b/lib/Postdelay/Scan.hs | |||
@@ -0,0 +1,43 @@ | |||
1 | {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, FlexibleContexts #-} | ||
2 | |||
3 | module Postdelay.Scan | ||
4 | ( scan | ||
5 | , Delay(..) | ||
6 | , ParseError(..) | ||
7 | ) where | ||
8 | |||
9 | import Postdelay.Types | ||
10 | import Postdelay.Utils | ||
11 | import Postdelay.TimeSpec | ||
12 | |||
13 | import Control.Monad | ||
14 | import Control.Monad.IO.Class | ||
15 | import Control.Monad.Error.Class | ||
16 | |||
17 | import Text.Parsec.Char | ||
18 | import Text.Parsec.Prim | ||
19 | import Text.Parsec.Combinator | ||
20 | import Text.Parsec.Error (ParseError(..)) | ||
21 | import Text.ParserCombinators.Parsec.Rfc2822 | ||
22 | |||
23 | import Data.CaseInsensitive (CI) | ||
24 | import qualified Data.CaseInsensitive as CI | ||
25 | |||
26 | import Data.Either | ||
27 | import Data.Foldable | ||
28 | import Data.Semigroup | ||
29 | |||
30 | |||
31 | scan :: (MonadIO m, MonadError ParseError m) => String -> m (Maybe Delay) | ||
32 | scan = fmap getOption . extractDelay <=< either throwError return . parse message "" | ||
33 | |||
34 | extractDelay :: forall m. (MonadIO m, MonadError ParseError m) => Message -> m (Option Delay) | ||
35 | extractDelay (Message headers _) = foldMap pure <$> mapM parseDelay delayHeaders | ||
36 | where | ||
37 | delayHeaders :: [Field] | ||
38 | delayHeaders = do | ||
39 | h@(OptionalField field content) <- headers | ||
40 | guard $ CI.mk field == "X-Delay" | ||
41 | return h | ||
42 | parseDelay :: Field -> m Delay | ||
43 | parseDelay (OptionalField field content) = either throwError return =<< runParserT (Until <$> pTimeSpec) () field content | ||
diff --git a/lib/Postdelay/TimeSpec.hs b/lib/Postdelay/TimeSpec.hs new file mode 100644 index 0000000..b080dcc --- /dev/null +++ b/lib/Postdelay/TimeSpec.hs | |||
@@ -0,0 +1,14 @@ | |||
1 | module Postdelay.TimeSpec | ||
2 | ( pTimeSpec | ||
3 | ) where | ||
4 | |||
5 | import Control.Monad.IO.Class | ||
6 | import Data.Time | ||
7 | |||
8 | import Text.Parsec.Char | ||
9 | import Text.Parsec.Prim | ||
10 | import Text.Parsec.Combinator | ||
11 | import Text.Parsec.Error (ParseError(..)) | ||
12 | |||
13 | pTimeSpec :: MonadIO m => ParsecT String () m UTCTime | ||
14 | pTimeSpec = undefined | ||
diff --git a/lib/Postdelay/Types.hs b/lib/Postdelay/Types.hs new file mode 100644 index 0000000..3f66fb8 --- /dev/null +++ b/lib/Postdelay/Types.hs | |||
@@ -0,0 +1,13 @@ | |||
1 | module Postdelay.Types | ||
2 | ( Delay(..) | ||
3 | ) where | ||
4 | |||
5 | import Data.Semigroup | ||
6 | |||
7 | import Data.Time.Clock (UTCTime) | ||
8 | |||
9 | newtype Delay = Until { releaseTime :: UTCTime } | ||
10 | deriving (Eq, Ord) | ||
11 | |||
12 | instance Semigroup Delay where | ||
13 | (Until a) <> (Until b) = Until $ max a b | ||
diff --git a/lib/Postdelay/Utils.hs b/lib/Postdelay/Utils.hs new file mode 100644 index 0000000..d716b4d --- /dev/null +++ b/lib/Postdelay/Utils.hs | |||
@@ -0,0 +1,21 @@ | |||
1 | {-# LANGUAGE FlexibleContexts #-} | ||
2 | |||
3 | module Postdelay.Utils | ||
4 | ( hoistParsecT | ||
5 | ) where | ||
6 | |||
7 | import Control.Monad.Error.Class | ||
8 | |||
9 | import Data.Functor | ||
10 | import Data.Either | ||
11 | |||
12 | import Data.Functor.Identity | ||
13 | import Text.Parsec.Prim | ||
14 | import Text.Parsec.Error | ||
15 | |||
16 | hoistParsecT :: (Monad m, Stream s Identity t, Stream s m t) => ParsecT s u Identity a -> ParsecT s u m a | ||
17 | hoistParsecT p = do | ||
18 | st <- getParserState | ||
19 | let res = runParser p' undefined "" undefined | ||
20 | p' = setParserState st >> ((,) <$> getState <*> p) | ||
21 | either (fail . show) (\(st', res) -> putState st' $> res) $ res | ||