@@ -0,0 +1,82 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+{-|
4+ A Snap adapter to the HTML5 Server-Sent Events API. Push-mode and
5+ pull-mode interfaces are both available.
6+-}
7+module EventStream (
8+ ServerEvent(..),
9+ eventToBuilder
10+ ) where
11+
12+import Blaze.ByteString.Builder
13+import Blaze.ByteString.Builder.Char8
14+import Control.Monad.Trans
15+import Control.Concurrent
16+import Data.Monoid
17+import Data.Enumerator hiding (map)
18+import Data.Enumerator.List (generateM)
19+
20+{-|
21+ Type representing a communication over an event stream. This can be an
22+ actual event, a comment, a modification to the retry timer, or a special
23+ "close" event indicating the server should close the connection.
24+-}
25+data ServerEvent
26+ = ServerEvent {
27+ eventName :: Maybe Builder,
28+ eventId :: Maybe Builder,
29+ eventData :: [Builder]
30+ }
31+ | CommentEvent {
32+ eventComment :: Builder
33+ }
34+ | RetryEvent {
35+ eventRetry :: Int
36+ }
37+ | CloseEvent
38+
39+
40+{-|
41+ Newline as a Builder.
42+-}
43+nl = fromChar '\n'
44+
45+
46+{-|
47+ Field names as Builder
48+-}
49+nameField = fromString "event:"
50+idField = fromString "id:"
51+dataField = fromString "data:"
52+retryField = fromString "retry:"
53+commentField = fromChar ':'
54+
55+
56+{-|
57+ Wraps the text as a labeled field of an event stream.
58+-}
59+field l b = l `mappend` b `mappend` nl
60+
61+
62+{-|
63+ Appends a buffer flush to the end of a Builder.
64+-}
65+flushAfter b = b `mappend` flush
66+
67+
68+{-|
69+ Converts a 'ServerEvent' to its wire representation as specified by the
70+ @text/event-stream@ content type.
71+-}
72+eventToBuilder :: ServerEvent -> Maybe Builder
73+eventToBuilder (CommentEvent txt) = Just $ flushAfter $ field commentField txt
74+eventToBuilder (RetryEvent n) = Just $ flushAfter $ field retryField (fromShow n)
75+eventToBuilder (CloseEvent) = Nothing
76+eventToBuilder (ServerEvent n i d)= Just $ flushAfter $
77+ (name n $ evid i $ mconcat (map (field dataField) d)) `mappend` nl
78+ where
79+ name Nothing = id
80+ name (Just n) = mappend (field nameField n)
81+ evid Nothing = id
82+ evid (Just i) = mappend (field idField i)