@@ -1,13 +1,18 @@
11{-# LANGUAGE OverloadedStrings #-}
22module Network.Wai.EventSource (
33 ServerEvent(..),
4− eventSourceApp
4+ eventSourceApp,
5+ eventSourceAppChan,
6+ eventSourceAppSource,
7+ eventSourceAppIO
58 ) where
69
710import Blaze.ByteString.Builder (Builder)
811import Control.Concurrent.Chan (Chan, dupChan, readChan)
912import Control.Monad.IO.Class (liftIO)
13+import Data.Conduit (($=))
1014import qualified Data.Conduit as C
15+import qualified Data.Conduit.List as CL
1116import Network.HTTP.Types (statusOK)
1217import Network.Wai (Application, Response(..))
1318
@@ -16,15 +21,31 @@ import Network.Wai.EventSource.EventStream
1621-- | Make a new WAI EventSource application reading events from
1722-- the given channel.
1823eventSourceApp :: Chan ServerEvent -> Application
19−eventSourceApp chan _ = do
24+eventSourceApp = eventSourceAppChan
25+{-# DEPRECATED eventSourceApp "Use evnetSourceAppChan instead." #-}
26+
27+-- | Make a new WAI EventSource application reading events from
28+-- the given channel.
29+eventSourceAppChan :: Chan ServerEvent -> Application
30+eventSourceAppChan chan _ = do
2031 chan' <- liftIO $ dupChan chan
21− return $ res chan'
32+ return $ response chanToSource chan'
2233
23−res :: Chan ServerEvent -> Response
24−res chan = ResponseSource statusOK [("Content-Type", "text/event-stream")] $ resE chan
34+-- | Make a new WAI EventSource application reading events from
35+-- the given source.
36+eventSourceAppSource :: C.Source IO ServerEvent -> Application
37+eventSourceAppSource src _ = return $ response sourceToSource src
2538
26−resE :: Chan ServerEvent -> C.Source IO (C.Flush Builder)
27−resE chan =
39+-- | Make a new WAI EventSource application reading events from
40+-- the given IO action.
41+eventSourceAppIO :: IO ServerEvent -> Application
42+eventSourceAppIO act _ = return $ response ioToSource act
43+
44+response :: (a -> C.Source IO (C.Flush Builder)) -> a -> Response
45+response f a = ResponseSource statusOK [("Content-Type", "text/event-stream")] $ f a
46+
47+chanToSource :: Chan ServerEvent -> C.Source IO (C.Flush Builder)
48+chanToSource chan =
2849 C.sourceState Nothing pull
2950 where
3051 pull Nothing = do
@@ -33,3 +54,22 @@ resE chan =
3354 Nothing -> C.StateClosed
3455 Just y -> C.StateOpen (Just C.Flush) (C.Chunk y)
3556 pull (Just x) = return $ C.StateOpen Nothing x
57+
58+ioToSource :: IO ServerEvent -> C.Source IO (C.Flush Builder)
59+ioToSource act =
60+ C.sourceState Nothing pull
61+ where
62+ pull Nothing = do
63+ x <- liftIO act
64+ return $ case eventToBuilder x of
65+ Nothing -> C.StateClosed
66+ Just y -> C.StateOpen (Just C.Flush) (C.Chunk y)
67+ pull (Just x) = return $ C.StateOpen Nothing x
68+
69+sourceToSource :: C.Source IO ServerEvent -> C.Source IO (C.Flush Builder)
70+sourceToSource src = src $= CL.concatMap eventToFlushBuilder
71+ where
72+ eventToFlushBuilder event =
73+ case eventToBuilder event of
74+ Nothing -> []
75+ Just x -> [C.Chunk x, C.Flush]