diff options
| author | Gregor Kleen <aethoago@141.li> | 2017-01-26 22:10:29 +0100 | 
|---|---|---|
| committer | Gregor Kleen <aethoago@141.li> | 2017-01-26 22:10:29 +0100 | 
| commit | 067c9c10e08bc48678687996945b35fa921229f4 (patch) | |
| tree | d3e78984cb65a285b9c6b2c6ea29938709088289 /lib/Postdelay | |
| parent | 0557c61d62bbcb01afc2f2604fa631062e034cc2 (diff) | |
| download | postdelay-067c9c10e08bc48678687996945b35fa921229f4.tar postdelay-067c9c10e08bc48678687996945b35fa921229f4.tar.gz postdelay-067c9c10e08bc48678687996945b35fa921229f4.tar.bz2 postdelay-067c9c10e08bc48678687996945b35fa921229f4.tar.xz postdelay-067c9c10e08bc48678687996945b35fa921229f4.zip | |
Basic concepts
Diffstat (limited to 'lib/Postdelay')
| -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 | ||
